2

Ok, so I'm spitting command line arguments by spaces, like Command Prompt, but the problem is, if the user tries to type in DoStuff "argument that has spaces but is quoted" it will not split it correctly. I am using a console application. I've tried to do it like this: baseCommand is the string that the user types in unparsed, and secondCommand is supposed to be the second argument.

int firstQuoteIndex = baseCommand.IndexOf('"');

if (firstQuoteIndex != -1)
{
    int secondQuoteIndex = baseCommand.LastIndexOf('"');
    secondCommand = baseCommand.Substring(firstQuoteIndex, 
        secondQuoteIndex - firstQuoteIndex + 1).Replace("\"", "");
}

This works well, but first, it's messy, and second, I'm not sure how to do this if the user types in something like this:

DoSomething "second arg that has spaces" "third arg that has spaces"

Keep in mind that the user doesn't have to type in quotes if the arg(s) don't have quotes. Does anybody have any suggestions, Thanks.

2
  • Last is not the same as next... stackoverflow.com/questions/22669044/… Commented Jan 8, 2020 at 2:07
  • You're only capturing the fist and last quote. Instead, you should continue to use IndexOf, starting at the position after the previous quote. Commented Jan 8, 2020 at 2:08

2 Answers 2

9

You could use following Regex for the purpose.

[\""].+?[\""]|[^ ]+

For example,

var commandList = Regex.Matches(baseCommand, @"[\""].+?[\""]|[^ ]+")
                .Cast<Match>()
                .Select(x => x.Value.Trim('"'))
                .ToList();

Sample 1 Input

DoSomething "second arg that has spaces" thirdArgumentWithoutSpaces

Output

Command List
------------
DoSomething 
second arg that has spaces
thirdArgumentWithoutSpaces

Sample 2 Input

DoSomething "second arg that has spaces" "third Argument With Spaces"

Output

Command List
------------
DoSomething 
second arg that has spaces
third Argument With Spaces
Sign up to request clarification or add additional context in comments.

5 Comments

This works really well, however, the first argument is not in the array.
Oops, I did not notice the skip. Sorry for the mis-understanding, this works really well also!
@VisualUser Do you need the first arguement in list ? I thought you want to skip it.
@VisualUser updated to include the first arguement as well
How about this commandline: cmd.exe /C ""c:\some path\ffmpeg.exe" -i "c:\some path\vid.mp4" "c:\some path\vid_small.mp4"" :)
3

I'm sure there's a more elegant way to do this, but one way is to simply walk through your command line one character at a time, keeping track if you're "inside a quoted string", and simply build the arguments as you go, adding them to a list when you encounter an end-quote or a space that's not inside a quoted string.

For example:

public static List<string> ParseCommandLine(string cmdLine)
{
    var args = new List<string>();
    if (string.IsNullOrWhiteSpace(cmdLine)) return args;

    var currentArg = new StringBuilder();
    bool inQuotedArg = false;

    for (int i = 0; i < cmdLine.Length; i++)
    {
        if (cmdLine[i] == '"')
        {
            if (inQuotedArg)
            {
                args.Add(currentArg.ToString());
                currentArg = new StringBuilder();
                inQuotedArg = false;
            }
            else
            {
                inQuotedArg = true;
            }
        }
        else if (cmdLine[i] == ' ')
        {
            if (inQuotedArg)
            {
                currentArg.Append(cmdLine[i]);
            }
            else if (currentArg.Length > 0)
            {
                args.Add(currentArg.ToString());
                currentArg = new StringBuilder();
            }
        }
        else
        {
            currentArg.Append(cmdLine[i]);
        }
    }

    if (currentArg.Length > 0) args.Add(currentArg.ToString());

    return args;
}

Usage might look like:

public static void Main()
{
    var args = "one two \"three four\" five \"six seven\" eight \"nine ten";

    Console.WriteLine($"Command line: \"{args}\"\n");
    Console.WriteLine("Individual Arguments");
    Console.WriteLine("--------------------");
    Console.WriteLine(string.Join(Environment.NewLine, ParseCommandLine(args)));

    GetKeyFromUser("\nDone! Press any key to exit...");
}

Output

enter image description here

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.