MatchCollectionクラスでLinqを使うおまじない


はじめに

 基本的には、「Linqを使いたいけど、IEnumerable<T>じゃなくてIEnumerableで宣言されているから使えない!」という場合の話です。
 あとクエリ構文でなくメソッド構文の話です。

ソースコード

        static void Main(string[] args)
        {
            string input = "abc123 bbb222 abc789";
            string pattern = @"(..)c(\d{3})";

            MatchCollection matches = Regex.Matches(input, pattern);

            var matches2 = matches.Cast<Match>().Select(x => x.Groups.Cast<Group>());

            foreach(var str in matches2.SelectMany(x => x))
            {
                Console.WriteLine(str);
            }
        }

出力結果

abc123
ab
123
abc789
ab
789

解説

 MatchCollectionクラスは図のようにリストのリストを持つ階層構造になっています。さらに、MatchCollectionとGroupCollectionはIEnumerable型のためこのままではLinqを用いることができません。
 そのため以下のような変換を行います。

var matches2 = matches.Cast<Match>().Select(x => x.Groups.Cast<Group>());

 MatchCollectionクラスは複数のMatchクラスのインスタンスを持つため.Cast<Match>()を用いることにより、IEnumerableからIEnumerable<T>に変換できます。 同様にx.GroupsもIEnumerableからIEnumerable<T>に変換できます。