I needed to parse some command line switches from a string and I tried to do it the easy way so I just wrote this:
static class CommandLineParser
{
public static IEnumerable<string> ParseCommandLine(this string text)
{
if (Regex.Matches(text, "\"").Count % 2 != 0)
{
throw new ArgumentException("Invalid number of qotes.");
}
return text.Aggregate(new
{
lastChar = '\0',
isEscaped = false,
result = new List<StringBuilder> { new StringBuilder() }
}, (state, next) =>
{
var isQuote = next == '"';
var isEscapedQuote = state.lastChar == '\\' && isQuote;
if (next == ' ' && !state.isEscaped)
{
// Ignore multiple spaces between switches.
if (state.lastChar != ' ')
{
state.result.Add(new StringBuilder());
}
}
else
{
state.result.Last().Append(next);
}
return new
{
lastChar = next,
isEscaped = isQuote && !isEscapedQuote ? !state.isEscaped : state.isEscaped,
result = state.result
};
}).result.Select(x => x.ToString());
}
}
Example:
var text = "foo -bar -baz=\"abc \\\"def\\\" ghi\" -qux";
text.ParseCommandLine().Dump();
and the result:
foo -bar -baz="abc \"def\" ghi" -qux
What do you think? Is this enough? Can this be even shorter?
te\xt
,tex"t
ortex\"t
? \$\endgroup\$te\xt
andtex\"t
, ortext
andtex"t
? (Or some other combination)? \$\endgroup\$