patterncsharpMinor
LINQish command line parser
Viewed 0 times
parsercommandlinelinqish
Problem
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:
Example:
and the result:
What do you think? Is this enough? Can this be even shorter?
static class CommandLineParser
{
public static IEnumerable 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 { 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"
-quxWhat do you think? Is this enough? Can this be even shorter?
Solution
Validate your
It would be better to check the argument before passing it on:
Why is this better? The stack trace is more meaningful because the error is thrown closer to where the problem call is and you can supply your own context specific error message. Either that, or you can return an empty array for
Properties should be PascalCase - including anonymous types.
Use
Name your constants! E.g. the double quote and the space. A single space is the most difficult thing to read in source code (in my experience).
I think this is good code (all the above is pretty minor). I'd never thought of using
text argument. This causes an ArgumentNullException in Regex.Matches:((string)null).ParseCommandLine();It would be better to check the argument before passing it on:
if (text == null)
{
throw new ArgumentNullException(nameof(text), "Command line arguments cannot be null");
}Why is this better? The stack trace is more meaningful because the error is thrown closer to where the problem call is and you can supply your own context specific error message. Either that, or you can return an empty array for
null.Properties should be PascalCase - including anonymous types.
lastChar should be LastChar and the same for the rest.result should be plural as it is a collection: Results.Use
default() to get the default value, it signals intent better than a literal ('\0' == default(char)).Name your constants! E.g. the double quote and the space. A single space is the most difficult thing to read in source code (in my experience).
I think this is good code (all the above is pretty minor). I'd never thought of using
Aggregate over a string for simple parsing before :)Code Snippets
((string)null).ParseCommandLine();if (text == null)
{
throw new ArgumentNullException(nameof(text), "Command line arguments cannot be null");
}Context
StackExchange Code Review Q#140552, answer score: 4
Revisions (0)
No revisions yet.