Skip to content

Instantly share code, notes, and snippets.

@yetanotherchris
Last active February 24, 2019 03:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yetanotherchris/4747009 to your computer and use it in GitHub Desktop.
Save yetanotherchris/4747009 to your computer and use it in GitHub Desktop.
Command line argument parser
static void Main(string[] args)
{
string[] example = { @"--arg1=""test"" --arg2= this is wrong --arg3=x --arg4=""value 4""" };
// Default usage
CommandLineTokenizer tokenizer = new CommandLineTokenizer(example);
Console.WriteLine(tokenizer["arg1"]);
Console.WriteLine(tokenizer["arg2"]); // bad tokens are blank strings
Console.WriteLine(tokenizer["arg5"]); // unknown tokens will also be blank string
// Alternative usage
tokenizer = new CommandLineTokenizer();
List<KeyValuePair<string, string>> list = tokenizer.Tokenize(example);
}
public class CommandLineTokenizer
{
private enum State
{
None,
FirstDash,
SecondDash,
StartArg,
StartArgDoubleQuotes,
EndArgDoubleQuotes,
StartArgSingleQuotes,
EndArgSingleQuotes,
Parse
}
private List<KeyValuePair<string, string>> _tokens;
public string this[string key]
{
get
{
for (int i = 0; i < _tokens.Count; i++)
{
if (_tokens[i].Key == key)
return _tokens[i].Value;
}
return "";
}
}
public CommandLineTokenizer()
{
string line = Environment.CommandLine;
line = line.Replace("\"" + Process.GetCurrentProcess().MainModule.FileName + "\"", "");
_tokens = Tokenize(line);
}
public CommandLineTokenizer(string[] args)
: this()
{
string input = string.Join(" ", args);
_tokens = Tokenize(input);
}
public List<KeyValuePair<string, string>> Tokenize(string input)
{
return Pass2(Pass1(input));
}
private List<string> Pass1(string input)
{
State state = State.None;
int start = 0;
int end = 0;
List<string> list = new List<string>();
for (int i = 0; i < input.Length; i++)
{
char current = input[i];
//Console.WriteLine("{0} {1}", current, state);
if (input[i] == '-')
{
if (state == State.None)
{
state = State.FirstDash;
}
else if (state == State.FirstDash)
{
state = State.SecondDash;
}
else if (state == State.SecondDash)
{
state = State.None;
start = 0;
}
}
else if (state == State.SecondDash)
{
start = i;
state = State.StartArg;
}
else if (current == '"')
{
if (state == State.StartArg)
{
state = State.StartArgDoubleQuotes;
}
else if (state == State.StartArgDoubleQuotes)
{
state = State.EndArgDoubleQuotes;
if (i == input.Length - 1)
{
state = State.Parse;
end = input.Length;
}
}
}
else if (current == '\'')
{
if (state == State.StartArg)
{
state = State.StartArgSingleQuotes;
}
else if (state == State.StartArgSingleQuotes)
{
state = State.EndArgSingleQuotes;
if (i == input.Length - 1)
{
state = State.Parse;
end = input.Length;
}
}
}
else if ((state == State.EndArgSingleQuotes || state == State.EndArgDoubleQuotes) && (current == ' ' || i == input.Length - 1))
{
end = i + 1;
state = State.Parse;
}
else if (state == State.StartArg && (current == ' ' || i == input.Length - 1))
{
end = i + 1; // get past this current char
state = State.Parse;
}
if (state == State.Parse)
{
state = State.None;
list.Add(input.Substring(start, end - start));
}
}
return list;
}
private List<KeyValuePair<string, string>> Pass2(List<string> list)
{
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
foreach (string item in list)
{
int equals = item.IndexOf("=");
if (equals > -1 && item.Length >= 3)
{
string key = item.Substring(0, equals);
string value = item.Substring(equals + 1);
KeyValuePair<string, string> pair = new KeyValuePair<string, string>(key, value);
result.Add(pair);
}
}
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment