Shell: Stuck on Single quotes #NI6

In my function for parsing the input, in my current function below, there is no extra space that will be added if we’ve finished taking in the characters with single input, but we see a whitespace on the failing test.

pub fn parse_input(input: &str) -> Vec<String> {
    let mut args: Vec<String> = Vec::new();
    let mut extracted_quoted_strings = HashSet::new();
    let mut current_arg_buffer = String::new();
    let mut in_single_quote = false;

    let mut chars = input.chars().peekable();

    while let Some(ch) = chars.next() {
        if ch == SINGLE_QUOTE {
            if in_single_quote {
                args.push(current_arg_buffer.clone());
                extracted_quoted_strings.insert(current_arg_buffer.clone());
                current_arg_buffer.clear();
                in_single_quote = false;
            } else {
                if !current_arg_buffer.is_empty() {
                    args.push(current_arg_buffer.clone());
                    current_arg_buffer.clear();
                }
                in_single_quote = true;
            }
        } else if ch.is_whitespace() && !in_single_quote {
            if !current_arg_buffer.is_empty() {
                args.push(current_arg_buffer.clone());
                current_arg_buffer.clear();
            }
        } else {
            current_arg_buffer.push(ch);
        }
    }

    if !current_arg_buffer.is_empty() {
        if in_single_quote {
            args.push(current_arg_buffer.clone());
            extracted_quoted_strings.insert(current_arg_buffer.clone());
        } else {
            args.push(current_arg_buffer.clone());
        }
    }

    println!("{:?}", extracted_quoted_strings);

    args
}

My code is on github GitHub - Rioba-Ian/codecrafters-shell-rust

Thank you and I appreciate any help or insight I can get

The test is telling you what is wrong. You are parsing 'hello''example' as two arguments.

In Bash “arguments” are referred to as tokens. They are separated by “metacharacters”. When you find the ending single quote you think you are done, so you add the text between ' as its own element to your argument list. This is wrong because we haven’t reached a metacharacter yet (like an unquoted space). Same thing with double quotes .

3 Likes

Thank you for the explanation, I’ve gotten a good understanding and tried to modify my solution but when testing with echo for the Backslash outside quotes on #YT5 I get error that they were not correct. Yet, on running echo with each of the cat “/tmp/foo/f\n86” “/tmp/foo/f\79” “/tmp/foo/f’'55” they output correctly.

[tester::#YT5] Running tests for Stage #YT5 (Quoting - Backslash outside quotes)
[tester::#YT5] [setup] export PATH=/tmp/apple/banana/raspberry:$PATH
[tester::#YT5] [setup] echo -n "pineapple orange." > "/tmp/foo/f\\n86"
[tester::#YT5] [setup] echo -n "blueberry strawberry." > "/tmp/foo/f\\79"
[tester::#YT5] [setup] echo -n "blueberry pear." > "/tmp/foo/f'\\'55"
[tester::#YT5] Running ./your_program.sh
[your-program] $ echo hello\ \ \ \ \ \ test
[your-program] hello      test
[tester::#YT5] ✓ Received expected response
[your-program] $ echo \'\"test world\"\'
[your-program] '"test world"'
[tester::#YT5] ✓ Received expected response
[your-program] $ echo world\nshell
[your-program] worldnshell
[tester::#YT5] ✓ Received expected response
[your-program] $ cat "/tmp/foo/f\n86" "/tmp/foo/f\79" "/tmp/foo/f'\'55"
[your-program] $ 
[tester::#YT5] ^ Line does not match expected value.
[tester::#YT5] Expected: "pineapple orange.blueberry strawberry.blueberry pear."
[tester::#YT5] Received: "$ "
[tester::#YT5] Assertion failed.
[tester::#YT5] Test failed

The exact point where my code for parse_input is: codecrafters-shell-rust/src/lib.rs at main · Rioba-Ian/codecrafters-shell-rust · GitHub

Hey @Rioba-Ian, I tried running your code against the previous stages, but it’s actually still not passing the stage #NI6 (Quoting - Single quotes).

Suggestions:

  1. Use our CLI to test against previous stages by running:
codecrafters test --previous
  1. Focus on fixing the early stages first, as later stages depend on them.

Thanks for pointing this out, I fixed the issue that made the previous tests to fail. And the latest tests fail

[tester::#YT5] Running tests for Stage #YT5 (Quoting - Backslash outside quotes)
[tester::#YT5] [setup] export PATH=/tmp/grape/grape/pear:$PATH
[tester::#YT5] [setup] echo -n "pear orange." > "/tmp/quz/f\\n35"
[tester::#YT5] [setup] echo -n "orange grape." > "/tmp/quz/f\\79"
[tester::#YT5] [setup] echo -n "mango pear." > "/tmp/quz/f'\\'63"
[tester::#YT5] Running ./your_program.sh
[your-program] $ echo example\ \ \ \ \ \ shell
[your-program] example      shell
[tester::#YT5] ✓ Received expected response
[your-program] $ echo \'\"shell world\"\'
[your-program] '"shell world"'
[tester::#YT5] ✓ Received expected response
[your-program] $ echo world\nhello
[your-program] worldnhello
[tester::#YT5] ✓ Received expected response
[your-program] $ cat "/tmp/quz/f\n35" "/tmp/quz/f\79" "/tmp/quz/f'\'63"
[your-program] $ 
[tester::#YT5] ^ Line does not match expected value.
[tester::#YT5] Expected: "pear orange.orange grape.mango pear."
[tester::#YT5] Received: "$ "
[tester::#YT5] Assertion failed.
[tester::#YT5] Test failed

I think for the tests with the cat they fail on #YT5 but seem to pass on previous tests

The tests are failing as the current implementation is not following the escaping rules correctly regarding \:

  • If with a single-quoted string, then no escaping is needed.
  • If within a double-quoted string, then only escaping should be done for particular characters (described in #GU3).

Keeping in mind the same, the code needs to be modified to:

This would help you pass the stage you’re stuck at while ensuring the previous stages aren’t disturbed. Let me know if something is unclear in the same!

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.