Is it possible to detect combinations and permutations of captured groups in a single line?

Viewed 40

I'm trying to detect a program from the process table and I need to parse its argument in captured groups. I want to do this with a single regex, however, I don't know if it is possible if some arguments are jumbled and/or omitted.

For example, I have:

program.exe -a arg_a -b arg_b -c arg_c -d arg_d -e arg_e

But it can also be:

program.exe -c arg_c -a arg_a -b arg_b -e arg_e
program.exe -b arg_b 
program.exe -a arg_a -c arg_c -d arg_d

Now, I need to get each argument. I know I can simply have 5 sets of regex a shown below,

"program.exe(?:.*-a (?<arga>\w+)|)"
"program.exe(?:.*-b (?<argb>\w+)|)"
"program.exe(?:.*-c (?<argc>\w+)|)"
"program.exe(?:.*-d (?<argd>\w+)|)"
"program.exe(?:.*-e (?<arge>\w+)|)"

but that would take 5 iterations and I would really like to get it in a single run.

Is it possible? Would highly appreciate any insights on this.

2 Answers

You can use a regex like this that matches the whole string:

^program.exe(?:\s+-(?<name>[a-e]) (?<arg>\w+))+$

then make use of the Captures property:

string regex = @"^program.exe(?:\s+-(?<name>[a-e]) (?<arg>\w+))+$";
string text = "program.exe -a arg_a -d arg_d -e arg_e -b arg_b -c arg_c";
Match match = Regex.Match(text, regex);
var names = match.Groups["name"];
var args = match.Groups["arg"];
foreach (var (name, arg) in names.Captures.Zip(args.Captures)) {
    Console.WriteLine($"{name.Value}: {arg.Value}");
    // or add these pairs to a dictionary for further processing and validation
}

/*
a: arg_a
d: arg_d
e: arg_e
b: arg_b
c: arg_c
*/

Sure, make your regex like

-(?<arg>[a-e]) (?<val>\w+)

Run it and you'll get n matches where n is the number of arguments, then you can loop them

If you assign them to a dictionary and have props that read the dictionary it doesn't matter what order they were supplied

foreach(var m in r.Matches(...))
  args[m.Groups["arg"].Value] = m.Groups["val"].Value;

(Could also use LINQ for that bit..)

And then some props like:

public string ArgumentE { get => args.TryGetValue("e", out string s) ? s ; "default"; }

So your code can just

if(ArgumentE == "White")
  ...
Related