56

How can I convert the list of match result from regex into List<string>? I have this function but it always generate an exception,

Unable to cast object of type 'System.Text.RegularExpressions.Match' to type 'System.Text.RegularExpressions.CaptureCollection'.

public static List<string> ExtractMatch(string content, string pattern)
{
    List<string> _returnValue = new List<string>();
    Match _matchList = Regex.Match(content, pattern);
    while (_matchList.Success)
    {
        foreach (Group _group in _matchList.Groups)
        {
            foreach (CaptureCollection _captures in _group.Captures) // error
            {
                foreach (Capture _cap in _captures)
                {
                    _returnValue.Add(_cap.ToString());
                }
            }
        }
    }
    return _returnValue;
}

If I have this string,

I have a dog and a cat.

regex

dog|cat

I want that the function will return of result into List<string>

dog
cat
SkyDrive
  • 1,445
  • 4
  • 15
  • 24
  • This previous answer may help: http://stackoverflow.com/questions/5767605/looping-through-regex-matches – martinwnet Oct 04 '12 at 15:09
  • 1
    did try that but i always get `foreach statement cannot operate on variables of type 'System.Text.RegularExpressions.Match' because 'System.Text.RegularExpressions.Match' does not contain a public definition for 'GetEnumerator'` – SkyDrive Oct 04 '12 at 15:16

6 Answers6

127

With the Regex you have, you need to use Regex.Matches to get the final list of strings like you want:

MatchCollection matchList = Regex.Matches(Content, Pattern);
var list = matchList.Cast<Match>().Select(match => match.Value).ToList();
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • 1
    to retain multiple groups, see my answer below http://stackoverflow.com/a/21123574/1037948 – drzaus Jan 14 '14 at 20:41
17

To get just a list of Regex matches, you may:

var lookfor = @"something (with) multiple (pattern) (groups)";
var found = Regex.Matches(source, lookfor, regexoptions);
var captured = found
                // linq-ify into list
                .Cast<Match>()
                // flatten to single list
                .SelectMany(o =>
                    // linq-ify
                    o.Groups.Cast<Capture>()
                        // don't need the pattern
                        .Skip(1)
                        // select what you wanted
                        .Select(c => c.Value));

This will "flatten" all the captured values down to a single list. To maintain capture groups, use Select rather than SelectMany to get a list of lists.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
drzaus
  • 24,171
  • 16
  • 142
  • 201
6

A possible solution using Linq:

using System.Linq;
using System.Text.RegularExpressions;

static class Program {
    static void Main(string[] aargs) {
        string value = "I have a dog and a cat.";
        Regex regex = new Regex("dog|cat");
        var matchesList = (from Match m in regex.Matches(value) select m.Value).ToList();
    }
}
Paolo Tedesco
  • 55,237
  • 33
  • 144
  • 193
1

Here's another solution that will fit into your code well.

while (_matchList.Success)
{
    _returnValue.Add(_matchList.Value);
    _matchList = _matchList.NextMatch();
}
Kendall Frey
  • 43,130
  • 20
  • 110
  • 148
0

Historically the Regex collections have not implemented the generic collection interfaces, and the LINQ extension methods you're using operate on the generic interfaces. MatchCollection was updated in .NET Core to implement IList, and thus can be used with the Selectextension method, but when you move to .NET Standard 2.0, that interface implementation isn't there, and thus you can't just callSelect. Instead, you'll need to use the LINQ Cast or OfType extensions to convert to an IEnumerable, and then you can use Select on that. Hope that helps.

Example

Regex wordMatcher = new Regex(@"\p{L}+");
return wordMatcher.Matches(text).Cast<Match>().Select(c => c.Value);

Regex wordMatcher = new Regex(@"\p{L}+");
return wordMatcher.Matches(text).OfType<Match>().Select(c => c.Value);
Jaydeep Shil
  • 1,894
  • 22
  • 21
-2
var regex = new Regex("{([A-Za-z])*}");
var result= regex.Matches(text).Where(p => p.Success).Select(p => p.Value).ToList();
Ming Li
  • 27
  • 1
  • 2