'How do I get the name of captured groups in a C# Regex?

Is there a way to get the name of a captured group in C#?

string line = "No.123456789  04/09/2009  999";
Regex regex = new Regex(@"(?<number>[\d]{9})  (?<date>[\d]{2}/[\d]{2}/[\d]{4})  (?<code>.*)");

GroupCollection groups = regex.Match(line).Groups;

foreach (Group group in groups)
{
    Console.WriteLine("Group: {0}, Value: {1}", ???, group.Value);
}

I want to get this result:

Group: [I don´t know what should go here], Value: 123456789  04/09/2009  999
Group: number, Value: 123456789
Group: date,   Value: 04/09/2009
Group: code,   Value: 999


Solution 1:[1]

Use GetGroupNames to get the list of groups in an expression and then iterate over those, using the names as keys into the groups collection.

For example,

GroupCollection groups = regex.Match(line).Groups;

foreach (string groupName in regex.GetGroupNames())
{
    Console.WriteLine(
       "Group: {0}, Value: {1}",
       groupName,
       groups[groupName].Value);
}

Solution 2:[2]

The cleanest way to do this is by using this extension method:

public static class MyExtensionMethods
{
    public static Dictionary<string, string> MatchNamedCaptures(this Regex regex, string input)
    {
        var namedCaptureDictionary = new Dictionary<string, string>();
        GroupCollection groups = regex.Match(input).Groups;
        string [] groupNames = regex.GetGroupNames();
        foreach (string groupName in groupNames)
            if (groups[groupName].Captures.Count > 0)
                namedCaptureDictionary.Add(groupName,groups[groupName].Value);
        return namedCaptureDictionary;
    }
}


Once this extension method is in place, you can get names and values like this:

    var regex = new Regex(@"(?<year>[\d]+)\|(?<month>[\d]+)\|(?<day>[\d]+)");
    var namedCaptures = regex.MatchNamedCaptures(wikiDate);

    string s = "";
    foreach (var item in namedCaptures)
    {
        s += item.Key + ": " + item.Value + "\r\n";
    }

    s += namedCaptures["year"];
    s += namedCaptures["month"];
    s += namedCaptures["day"];

Solution 3:[3]

Since .NET 4.7, there is Group.Name property available.

Solution 4:[4]

You should use GetGroupNames(); and the code will look something like this:

    string line = "No.123456789  04/09/2009  999";
    Regex regex = 
        new Regex(@"(?<number>[\d]{9})  (?<date>[\d]{2}/[\d]{2}/[\d]{4})  (?<code>.*)");

    GroupCollection groups = regex.Match(line).Groups;

    var grpNames = regex.GetGroupNames();

    foreach (var grpName in grpNames)
    {
        Console.WriteLine("Group: {0}, Value: {1}", grpName, groups[grpName].Value);
    }

Solution 5:[5]

The Regex class is the key to this!

foreach(Group group in match.Groups)
{
    Console.WriteLine("Group: {0}, Value: {1}", regex.GroupNameFromNumber(group.Index), group.Value);
}

http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.groupnamefromnumber.aspx

Solution 6:[6]

To update the existing extension method answer by @whitneyland with one that can handle multiple matches:

public static List<Dictionary<string, string>> MatchNamedCaptures(this Regex regex, string input)
    {
        var namedCaptureList = new List<Dictionary<string, string>>();
        var match = regex.Match(input);

        do
        {
            Dictionary<string, string> namedCaptureDictionary = new Dictionary<string, string>();
            GroupCollection groups = match.Groups;

            string[] groupNames = regex.GetGroupNames();
            foreach (string groupName in groupNames)
            {
                if (groups[groupName].Captures.Count > 0)
                    namedCaptureDictionary.Add(groupName, groups[groupName].Value);
            }

            namedCaptureList.Add(namedCaptureDictionary);
            match = match.NextMatch();
        }
        while (match!=null && match.Success);

        return namedCaptureList;
    }

Usage:

  Regex pickoutInfo = new Regex(@"(?<key>[^=;,]+)=(?<val>[^;,]+(,\d+)?)", RegexOptions.ExplicitCapture);

  var matches = pickoutInfo.MatchNamedCaptures(_context.Database.GetConnectionString());

  string server = matches.Single( a => a["key"]=="Server")["val"];

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Jozef Benikovský
Solution 4 Eran Betzalel
Solution 5 Joel
Solution 6 Kinetic