3

With the following regular expression:

InitValue\((\w*)\)

and the test string:

InitValue(Input1)

I get the following result:

Full match: InitValue(Input1)
Group1: Input1

With the following regular expression:

InitValue\((\w*)\s*,\s*(\w*)\)

and the test string:

InitValue(Input1, Input2)

I get:

Full match: InitValue(Input1, Input2)
Group1: Input1
Group2: Input2

Now I would like to capture any number of arguments to the InitValue-method. The number of arguments to InitValue are unknown.

Full match: InitValue(Input1, Input2, ..., Inputn)
Group1: Input1
Group2: Input2
....
Groupn: Inputn

Of course I can't repeat the following pattern in my regular expression since I don't know the number of arguments in advance:

\s*,\s*(\w*)

How do I write a regular expression which outputs n number of capture groups?

I use the regular expression in C#-code (Regex, Match)...

Andy Rehn
  • 131
  • 6

4 Answers4

1

It is possible to do this in .NET - you use a single capture Group, and then you access the Group's Captures collection to see all the items it captured, not just the final Value.

You'll have to write a regex that can repeat the argument-matching group, something like

InitValue\((?:(\w+)\s*(?:,(?!\s*\))|(?=\s*\)))\s*)*\)

Have a play around with the Debuggex Demo to get it to match what you want.

Rawling
  • 49,248
  • 7
  • 89
  • 127
1
static void GetParams()
{
    int x = 0;
    var strings = new[]
    {
        "InitValue()",
        "InitValue(Input1)",
        "InitValue(Input1, Input2, Input3, Input4)"
    };

    var pattern = @"(\w+)\((?:(\w+)(?:,?\s*))*\)";

    foreach (var s in strings)
    {
        WriteLine($"String: '{s}'");
        var match = Regex.Match(s, pattern);
        if (match.Success)
        {
            WriteLine($"\tMethod: '{match.Groups[1].Value}'");
            WriteLine("\tParameters:");
            var captures = match.Groups[2].Captures;
            if (captures.Count > 0)
            {
                x = 0;
                foreach (Capture capture in captures)
                {
                    WriteLine($"\t\tParam {++x}: '{capture.Value}'");
                }
            }
            else
            {
                WriteLine("\t\tNo params found.");
            }

            WriteLine();
        }

        else
            WriteLine("No matches found.");
    }
}

/*
Output:

String: 'InitValue()'
        Method: 'InitValue'
        Parameters:
                No params found.

String: 'InitValue(Input1)'
        Method: 'InitValue'
        Parameters:
                Param 1: 'Input1'

String: 'InitValue(Input1, Input2, Input3, Input4)'
        Method: 'InitValue'
        Parameters:
                Param 1: 'Input1'
                Param 2: 'Input2'
                Param 3: 'Input3'
                Param 4: 'Input4'
*/
JohnyL
  • 6,894
  • 3
  • 22
  • 41
1

.NET supports infinite lookbehind (?<=. Instead of getting capturing groups, another option could be to get the matches instead:

(?<=\bInitValue\([^()]*)[^, ]+(?=[^()]*\))

Explanation

  • (?<= Positive lookbehind, check what is on the left matches:
    • \bInitValue\([^()]* Match wordboundary, InitValue( and then 0+ times not any of ( or )
  • ) Close positive lookbehind
  • [^, \t]+ Negative character class, match 1+ times not a space or comma
  • (?= Positive lookahead to check what is on the right matches:
    • [^()]*\) Match 0+ times not any of ( or ), then match )
  • ) Close positive lookahead

For example:

string pattern = @"(?<=\bInitValue\([^()]*)[^, ]+(?=[^()]*\))";
string str = "InitValue(Input1, Input2, Input3)";            
foreach (Match m in Regex.Matches(str, pattern))
{
    Console.WriteLine(m.Value);
}

Result

Input1
Input2
Input3

See the Regex demo | C# demo

The fourth bird
  • 154,723
  • 16
  • 55
  • 70
0

Don't let anyone tells you what it's impossible and what it's not

enter image description here

You will have to touch it a little bit but I think it can guide you =D.

Edit, answering your question. b.Count will give you the number of matchings.
Edit 2, I post the picture to show the debug info. But here is the code for the sibarist.

string bar = "test, othertest";
Regex reg = new Regex(@"[\w]+");

MatchCollection b = reg.Matches(bar);

string b1 = b[0].Value;
string b2 = b[1].Value;

int numberGroups = b.Count;

Edit 3, as suggested in the comment this is the complete solution, you will need to clear the InitValue(*) part with another Regex or with a Substring

string input = "InitValue(test, othertest, bleh, blehTest, foo)";

Regex regArgs = new Regex(@"(?:InitValue\()(.*)(?:\))");
Match matchArgs = regArgs.Match(input);

string valueArgs = matchArgs.Groups[1].Value;

Regex reg = new Regex(@"[\w]+");

MatchCollection b = reg.Matches(valueArgs);

string b1 = b[0].Value;
string b2 = b[1].Value;

int numberGroups = b.Count;
Nekeniehl
  • 1,633
  • 18
  • 35
  • Please, show how do you apply this technique to the test string: `InitValue(Input1, Input2, Input3, Input4)` – mrzasa Jan 07 '19 at 15:38
  • What do you mean? As I said, this is only ilustrative, not the full solution, but close enough. You can easily delete the `InitValue(*)` with a `Substring`and keep the arguments, if you mean that it is impossible when it's written InitValue, then yes, you are right, but that's far from being impossible =D – Nekeniehl Jan 07 '19 at 15:41