正規表現でのグループ化構成体

グループ化構成体は、正規表現の部分式を表し、入力文字列の部分文字列をキャプチャします。 グループ化構成体を使用して、以下を実行できます。

  • 入力文字列で繰り返し使用されている部分式を照合する。
  • 複数の正規表現言語要素を含む部分式に量指定子を適用する。 量指定子について詳しくは、「 Quantifiers」をご覧ください。
  • Regex.Replace メソッドおよび Match.Result メソッドによって返される文字列に部分式を含める。
  • Match.Groups プロパティから個々の部分式を取得し、一致したテキスト全体とは別に処理する。

次の表に、.NET 正規表現エンジンでサポートされているグループ化構成体と、これらの構成体がキャプチャまたは非キャプチャのいずれであるかを示します。

グループ化構成体 キャプチャまたは非キャプチャ
一致した部分式 キャプチャ
一致した名前付き部分式 キャプチャ
グループ定義の均等化 キャプチャ
非キャプチャ グループ 非キャプチャ
グループ オプション 非キャプチャ
ゼロ幅の肯定先読みアサーション 非キャプチャ
ゼロ幅の否定先読みアサーション 非キャプチャ
ゼロ幅の正の後読みアサーション 非キャプチャ
ゼロ幅の負の後読みアサーション 非キャプチャ
アトミック グループ 非キャプチャ

グループと正規表現オブジェクト モデルの詳細については、「 グループ化構成体および正規表現オブジェクト」を参照してください。

一致した部分式

次のグループ化構成体は、一致した部分式をキャプチャします。

(subexpression)

ここで、subexpression は有効な正規表現パターンです。 かっこを使用するキャプチャには、正規表現の左かっこの順番に基づいて、左から右に自動的に 1 から始まる番号が付けられます。 ただし、名前付きキャプチャ グループは、常に、名前なしキャプチャ グループの後の最後に配置されます。 番号が 0 になるキャプチャは、正規表現パターン全体と一致するテキストです。

Note

既定では、 (subexpression) 言語要素が、一致する部分式をキャプチャします。 ただし、正規表現パターン一致メソッドの RegexOptions パラメーターに RegexOptions.ExplicitCapture フラグが含まれる場合や、n オプションがこの部分式に適用される場合は (この記事で後述する「グループ オプション」を参照)、一致した部分式はキャプチャされません。

キャプチャされたグループにアクセスする方法は 4 つあります。

  • 正規表現内で前方参照構成体を使用する。 \number という構文を使うと、一致した部分式が同じ正規表現内で参照されます。ここで、number はキャプチャされた部分式の序数です。

  • 正規表現内で名前付き前方参照構成体を使用する。 \k<name> という構文 (name はキャプチャ グループの名前)、または \k<number> という構文 (number はキャプチャ グループの序数) を使用すると、一致した部分式が同じ正規表現内で参照されます。 キャプチャ グループには、その序数と同じ既定の名前が付いています。 詳細については、このトピックで後述する「 一致した名前付き部分式 」を参照してください。

  • $number 置換シーケンスを、Regex.Replace メソッドまたは Match.Result メソッドの呼び出しで使用する。ここで、number はキャプチャされた部分式の序数です。

  • プログラムで GroupCollection プロパティによって返される Match.Groups オブジェクトを使用する。 コレクション内の位置 0 にあるメンバーは、正規表現に一致した文字列全体を表します。 後続の各メンバーは、一致した部分式を表します。 詳しくは、「 Grouping Constructs and Regular Expression Objects 」セクションをご覧ください。

次の例は、テキスト内で重複している単語を識別する正規表現を示しています。 正規表現パターンの 2 つのキャプチャ グループは、2 つの重複する単語を表します。 2 番目の単語は、入力文字列内の開始位置を報告するためにキャプチャされます。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(\w+)\s(\1)\W";
      string input = "He said that that was the the correct answer.";
      foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
         Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.",
                           match.Groups[1].Value, match.Groups[1].Index, match.Groups[2].Index);
   }
}
// The example displays the following output:
//       Duplicate 'that' found at positions 8 and 13.
//       Duplicate 'the' found at positions 22 and 26.
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "(\w+)\s(\1)\W"
        Dim input As String = "He said that that was the the correct answer."
        For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
            Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.", _
                              match.Groups(1).Value, match.Groups(1).Index, match.Groups(2).Index)
        Next
    End Sub
End Module
' The example displays the following output:
'       Duplicate 'that' found at positions 8 and 13.
'       Duplicate 'the' found at positions 22 and 26.

正規表現パターンは次のとおりです。

(\w+)\s(\1)\W

次の表に、正規表現パターンがどのように解釈されるかを示します。

パターン 説明
(\w+) 1 つ以上の単語文字に一致します。 これが最初のキャプチャ グループです。
\s 空白文字と一致します。
(\1) 最初のキャプチャ グループの文字列と一致します。 これが 2 番目のキャプチャ グループです。 例では、これをキャプチャ グループに割り当てて、重複する単語の開始位置を Match.Index オブジェクトを使用する。
\W 空白や句読点などの単語文字以外の文字と一致します。 これにより、正規表現パターンが、最初のキャプチャ グループの単語で始まる単語と一致しなくなります。

一致した名前付き部分式

次のグループ化構成体は、一致した部分式をキャプチャし、その部分式に名前または番号でアクセスできるようにします。

(?<name>subexpression)

または

(?'name'subexpression)

ここで、name は有効なグループ名、subexpression は有効な正規表現パターンです。 name は区切り記号を含まず、先頭が数字以外である必要があります。

Note

正規表現パターン一致メソッドの RegexOptions パラメーターに RegexOptions.ExplicitCapture フラグが含まれる場合や、 n オプションがこの部分式に適用される場合は (このトピックで後述する「 グループ オプション 」を参照)、部分式をキャプチャする唯一の方法は、キャプチャ グループの名前を明示的に指定することです。

キャプチャされた名前付きグループには次の方法でアクセスできます。

  • 正規表現内で名前付き前方参照構成体を使用する。 \k<name> という構文を使用すると、一致した部分式が同じ正規表現内で参照されます。ここで、name はキャプチャされた部分式の名前です。

  • 正規表現内で前方参照構成体を使用する。 \number という構文を使うと、一致した部分式が同じ正規表現内で参照されます。ここで、number はキャプチャされた部分式の序数です。 一致した名前付き部分式には、一致した部分式の後、左から右に連続した番号が付けられます。

  • ${name} 置換シーケンスを、Regex.Replace メソッドまたは Match.Result メソッドの呼び出しで使用する。ここで、name はキャプチャされた部分式の名前です。

  • $number 置換シーケンスを、Regex.Replace メソッドまたは Match.Result メソッドの呼び出しで使用する。ここで、number はキャプチャされた部分式の序数です。

  • プログラムで GroupCollection プロパティによって返される Match.Groups オブジェクトを使用する。 コレクション内の位置 0 にあるメンバーは、正規表現に一致した文字列全体を表します。 後続の各メンバーは、一致した部分式を表します。 キャプチャされた名前付きグループは、キャプチャされた番号付きグループの後にコレクションに格納されます。

  • プログラムで GroupCollection オブジェクトのインデクサー (C# の場合) またはその Item[] プロパティ (Visual Basic の場合) に部分式名を指定する。

簡単な正規表現パターンで、プログラムまたは正規表現言語構文を使用して番号付き (名前のない) グループおよび名前付きグループをどのように参照できるかを示します。 正規表現 ((?<One>abc)\d+)?(?<Two>xyz)(.*) からは、次のように番号と名前の付いたキャプチャ グループが作成されます。 最初のキャプチャ グループ (番号 0) は、常にパターン全体を指します。 (名前付きグループは常に一番最後になります)。

number 名前 パターン
0 0 (既定名) ((?<One>abc)\d+)?(?<Two>xyz)(.*)
1 1 (既定名) ((?<One>abc)\d+)
2 2 (既定名) (.*)
3 1 つ (?<One>abc)
4 2 つ (?<Two>xyz)

次の例は、重複している単語、および重複している各単語の直後にある単語を識別する正規表現を示しています。 この正規表現パターンでは、重複している単語を表す duplicateWord と、重複している単語の後にある単語を表す nextWord の、2 つの名前付き部分式が定義されています。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)";
      string input = "He said that that was the the correct answer.";
      foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
         Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.",
                           match.Groups["duplicateWord"].Value, match.Groups["duplicateWord"].Index,
                           match.Groups["nextWord"].Value);
   }
}
// The example displays the following output:
//       A duplicate 'that' at position 8 is followed by 'was'.
//       A duplicate 'the' at position 22 is followed by 'correct'.
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)"
        Dim input As String = "He said that that was the the correct answer."
        Console.WriteLine(Regex.Matches(input, pattern, RegexOptions.IgnoreCase).Count)
        For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
            Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.", _
                              match.Groups("duplicateWord").Value, match.Groups("duplicateWord").Index, _
                              match.Groups("nextWord").Value)
        Next
    End Sub
End Module
' The example displays the following output:
'    A duplicate 'that' at position 8 is followed by 'was'.
'    A duplicate 'the' at position 22 is followed by 'correct'.

正規表現パターンは次のとおりです。

(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)

次の表に、正規表現がどのように解釈されるかを示します。

パターン 説明
(?<duplicateWord>\w+) 1 つ以上の単語文字に一致します。 このキャプチャ グループに duplicateWordという名前を付けます。
\s 空白文字と一致します。
\k<duplicateWord> duplicateWordという名前のキャプチャ済みグループの文字列と一致します。
\W 空白や句読点などの単語文字以外の文字と一致します。 これにより、正規表現パターンが、最初のキャプチャ グループの単語で始まる単語と一致しなくなります。
(?<nextWord>\w+) 1 つ以上の単語文字に一致します。 このキャプチャ グループに nextWordという名前を付けます。

1 つの正規表現で同じグループ名を繰り返すことができます。 たとえば、次の例で示すように、複数のグループに digit という名前を付けることができます。 名前が重複する場合、 Group オブジェクトの値は、入力文字列の最後の正常なキャプチャによって決定されます。 さらに、グループ名が重複されない場合と同じように、各キャプチャについての情報が CaptureCollection 格納されます。

次の例では、正規表現 \D+(?<digit>\d+)\D+(?<digit>\d+)?digitという名前のグループの 2 回の出現が含まれています。 最初の digit という名前のグループは、1 桁以上の数字をキャプチャします。 2 番目の digit という名前のグループは、1 桁以上の数字の 0 回か 1 回の出現をキャプチャします。 例の出力が示すように、2 番目のキャプチャ グループがテキストと正常に一致する場合、そのテキストの値は Group オブジェクトの値を定義します。 2 番目のキャプチャ グループが入力文字列と一致しない場合、最後に成功した一致の値によって Group オブジェクトの値が定義されます。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      String pattern = @"\D+(?<digit>\d+)\D+(?<digit>\d+)?";
      String[] inputs = { "abc123def456", "abc123def" };
      foreach (var input in inputs) {
         Match m = Regex.Match(input, pattern);
         if (m.Success) {
            Console.WriteLine("Match: {0}", m.Value);
            for (int grpCtr = 1; grpCtr < m.Groups.Count; grpCtr++) {
               Group grp = m.Groups[grpCtr];
               Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value);
               for (int capCtr = 0; capCtr < grp.Captures.Count; capCtr++)
                  Console.WriteLine("   Capture {0}: {1}", capCtr,
                                    grp.Captures[capCtr].Value);
            }
         }
         else {
            Console.WriteLine("The match failed.");
         }
         Console.WriteLine();
      }
   }
}
// The example displays the following output:
//       Match: abc123def456
//       Group 1: 456
//          Capture 0: 123
//          Capture 1: 456
//
//       Match: abc123def
//       Group 1: 123
//          Capture 0: 123
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "\D+(?<digit>\d+)\D+(?<digit>\d+)?"
        Dim inputs() As String = {"abc123def456", "abc123def"}
        For Each input As String In inputs
            Dim m As Match = Regex.Match(input, pattern)
            If m.Success Then
                Console.WriteLine("Match: {0}", m.Value)
                For grpCtr As Integer = 1 to m.Groups.Count - 1
                    Dim grp As Group = m.Groups(grpCtr)
                    Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value)
                    For capCtr As Integer = 0 To grp.Captures.Count - 1
                        Console.WriteLine("   Capture {0}: {1}", capCtr,
                                          grp.Captures(capCtr).Value)
                    Next
                Next
            Else
                Console.WriteLine("The match failed.")
            End If
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'       Match: abc123def456
'       Group 1: 456
'          Capture 0: 123
'          Capture 1: 456
'
'       Match: abc123def
'       Group 1: 123
'          Capture 0: 123

次の表に、正規表現がどのように解釈されるかを示します。

パターン 説明
\D+ 1 個以上の 10 進数以外の文字と一致します。
(?<digit>\d+) 1 個以上の 10 進数の文字と一致します。 一致を digit という名前のグループに割り当てます。
\D+ 1 個以上の 10 進数以外の文字と一致します。
(?<digit>\d+)? 1 つ以上の 10 進数の文字の 0 回または 1 回の出現と一致します。 一致を digit という名前のグループに割り当てます。

グループ定義の均等化

グループ定義の均等化では、既に定義されていたグループの定義を削除し、既に定義されていたグループと現在のグループの間隔を現在のグループに格納します。 このグループ化構成体の形式は次のとおりです。

(?<name1-name2>subexpression)

または

(?'name1-name2' subexpression)

ここで、name1 は現在のグループ (省略可能)、name2 は前で定義されているグループ、subexpression は有効な正規表現パターンです。 グループ定義の均等化では、 name2 の定義を削除し、 name2name1 の間隔を name1に格納します。 name2 グループが定義されていない場合、一致はバックトラックされます。 name2 の最後の定義を削除すると、 name2の以前の定義がわかるため、この構成体によって、かっこや左右の角かっこなど入れ子になった構成体を追跡するカウンターとして name2 グループのキャプチャのスタックを使用できます。

グループ定義の均等化では、 name2 をスタックとして使用します。 入れ子になった各構成体の開始文字が、グループとその Group.Captures コレクションに配置されます。 終了文字が一致すると、対応する開始文字がグループから削除され、 Captures コレクションが 1 つ減らされます。 入れ子になったすべての構成体の開始文字と終了文字が一致したら、name2 は空になります。

Note

入れ子になった構成体の適切な開始文字と終了文字を使用するように次の例の正規表現を変更すると、その正規表現を使用して、複数の入れ子になったメソッド呼び出しを含む数式やプログラム コード行などのほとんどの入れ子になった構成体を処理できるようになります。

次の例では、グループ定義の均等化を使用して、入力文字列内の左と右の山かっこ (<>) を一致させています。 この例では、一致する山かっこのペアを追跡するスタックのように使用される Open および Closeという 2 つの名前付きグループを定義しています。 キャプチャされた各左山かっこは Open グループのキャプチャ コレクションに挿入され、キャプチャされた各右山かっこは Close グループのキャプチャ コレクションに挿入されます。 グループ定義の均等化によって、各左山かっこに一致する右山かっこが存在することが確認されます。 存在しない場合、最後のサブパターンの (?(Open)(?!))は、 Open グループが空でない場合 (したがって、いくつかの入れ子になった構成体に右山かっこがない場合) にのみ評価されます。 最後のサブパターンが評価されると、 (?!) サブパターンが必ず失敗するゼロ幅の否定先読みアサーションであるため、照合は失敗します。

using System;
using System.Text.RegularExpressions;

class Example
{
   public static void Main()
   {
      string pattern = "^[^<>]*" +
                       "(" +
                       "((?'Open'<)[^<>]*)+" +
                       "((?'Close-Open'>)[^<>]*)+" +
                       ")*" +
                       "(?(Open)(?!))$";
      string input = "<abc><mno<xyz>>";

      Match m = Regex.Match(input, pattern);
      if (m.Success == true)
      {
         Console.WriteLine("Input: \"{0}\" \nMatch: \"{1}\"", input, m);
         int grpCtr = 0;
         foreach (Group grp in m.Groups)
         {
            Console.WriteLine("   Group {0}: {1}", grpCtr, grp.Value);
            grpCtr++;
            int capCtr = 0;
            foreach (Capture cap in grp.Captures)
            {
                Console.WriteLine("      Capture {0}: {1}", capCtr, cap.Value);
                capCtr++;
            }
          }
      }
      else
      {
         Console.WriteLine("Match failed.");
      }
    }
}
// The example displays the following output:
//    Input: "<abc><mno<xyz>>"
//    Match: "<abc><mno<xyz>>"
//       Group 0: <abc><mno<xyz>>
//          Capture 0: <abc><mno<xyz>>
//       Group 1: <mno<xyz>>
//          Capture 0: <abc>
//          Capture 1: <mno<xyz>>
//       Group 2: <xyz
//          Capture 0: <abc
//          Capture 1: <mno
//          Capture 2: <xyz
//       Group 3: >
//          Capture 0: >
//          Capture 1: >
//          Capture 2: >
//       Group 4:
//       Group 5: mno<xyz>
//          Capture 0: abc
//          Capture 1: xyz
//          Capture 2: mno<xyz>
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "^[^<>]*" & _
                                "(" + "((?'Open'<)[^<>]*)+" & _
                                "((?'Close-Open'>)[^<>]*)+" + ")*" & _
                                "(?(Open)(?!))$"
        Dim input As String = "<abc><mno<xyz>>"
        Dim rgx AS New Regex(pattern) '
        Dim m As Match = Regex.Match(input, pattern)
        If m.Success Then
            Console.WriteLine("Input: ""{0}"" " & vbCrLf & "Match: ""{1}""", _
                               input, m)
            Dim grpCtr As Integer = 0
            For Each grp As Group In m.Groups
                Console.WriteLine("   Group {0}: {1}", grpCtr, grp.Value)
                grpCtr += 1
                Dim capCtr As Integer = 0
                For Each cap As Capture In grp.Captures
                    Console.WriteLine("      Capture {0}: {1}", capCtr, cap.Value)
                    capCtr += 1
                Next
            Next
        Else
            Console.WriteLine("Match failed.")
        End If
    End Sub
End Module
' The example displays the following output:
'       Input: "<abc><mno<xyz>>"
'       Match: "<abc><mno<xyz>>"
'          Group 0: <abc><mno<xyz>>
'             Capture 0: <abc><mno<xyz>>
'          Group 1: <mno<xyz>>
'             Capture 0: <abc>
'             Capture 1: <mno<xyz>>
'          Group 2: <xyz
'             Capture 0: <abc
'             Capture 1: <mno
'             Capture 2: <xyz
'          Group 3: >
'             Capture 0: >
'             Capture 1: >
'             Capture 2: >
'          Group 4:
'          Group 5: mno<xyz>
'             Capture 0: abc
'             Capture 1: xyz
'             Capture 2: mno<xyz>

正規表現パターンは次のとおりです。

^[^<>]*(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)*(?(Open)(?!))$

この正規表現パターンは、次のように解釈されます。

パターン 説明
^ 文字列の先頭から始まります。
[^<>]* 左または右の山かっこではない 0 個以上の文字と一致します。
(?'Open'<) 左山かっこと一致し、そのかっこを Openという名前のグループに代入します。
[^<>]* 左または右の山かっこではない 0 個以上の文字と一致します。
((?'Open'<)[^<>]*)+ 左山かっこの後に左または右の山かっこではない 0 個以上の文字が続くパターンの 1 回以上の出現と一致します。 これが 2 番目のキャプチャ グループです。
(?'Close-Open'>) 右山かっこと一致し、 Open グループと現在のグループの間の部分文字列を Close グループに代入して、 Open グループの定義を削除します。
[^<>]* 左または右の山かっこではない任意の文字の 0 回以上の出現と一致します。
((?'Close-Open'>)[^<>]*)+ 右山かっこの後に左または右の山かっこではない任意の文字の 0 回以上の出現が続くパターンの 1 回以上の出現と一致します。 右山かっこと一致したときに、 Open グループと現在のグループの間の部分文字列を Close グループに代入して、 Open グループの定義を削除します。 これが 3 番目のキャプチャ グループです。
(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)* 左山かっこの 1 回以上の出現の後に山かっこではない 0 個以上の文字が続き、その後に右山かっこの 1 回以上の出現が続き、その後に山かっこ以外の 0 回以上の出現が続くパターンの 0 回以上の出現と一致します。 右山かっこと一致したときに、 Open グループの定義を削除して、 Open グループと現在のグループの間の部分文字列を Close グループに代入します。 これが最初のキャプチャ グループです。
(?(Open)(?!)) Open グループが存在し、空の文字列が一致する場合、照合を破棄してください。ただし、文字列内での正規表現エンジンの位置は進めないでください。 これはゼロ幅の否定先読みアサーションです。 空の文字列が常に入力文字列に暗黙的に存在するため、この照合は必ず失敗します。 この照合の失敗は、山かっこの数が一致していないことを示します。
$ 入力文字列の末尾と一致します。

最後の部分式の (?(Open)(?!))は、入力文字列内の入れ子の構成体の数が一致しているかどうかを示します (各左山かっこに一致する右山かっこが存在するかどうかなど)。 詳しくは、代替コンストラクトをご覧ください。 Open グループが定義されている場合は、正規表現エンジンによって、入力文字列内で部分式 (?!) の照合が試行されます。 Open グループは、入れ子の構成体の数が一致していない場合にのみ定義する必要があります。 したがって、入力文字列で照合されるパターンでは、照合は常に失敗します。 この場合、(?!) は、常に失敗するゼロ幅の否定先読みアサーションです。入力文字列内の次の位置に、必ず空の文字列が暗黙的に存在するためです。

この例では、正規表現エンジンによって、次の表に示すように入力文字列 "<abc><mno<xyz>>" が評価されます。

手順 パターン 結果
1 ^ 入力文字列の先頭から照合を開始します。
2 [^<>]* 左山かっこの前にある山かっこではない文字を検索します。一致する項目は見つかりません。
3 (((?'Open'<) "<abc>" の左山かっこと一致し、そのかっこを Open グループに代入します。
4 [^<>]* "abc" と一致します。
5 )+ "<abc" が 2 番目のキャプチャ グループの値になります。

入力文字列内の次の文字は左山かっこではないので、正規表現エンジンは (?'Open'<)[^<>]*) サブパターンに戻りません。
6 ((?'Close-Open'>) "<abc>" の右山かっこと一致し、Open グループと右山かっこの間の部分文字列である "abc" を Close グループに代入して、Open グループの現在の値 ("<") を削除してグループを空にします。
7 [^<>]* 右山かっこの後にある山かっこではない文字を検索します。一致する項目は見つかりません。
8 )+ 3 番目のキャプチャ グループの値は ">" です。

入力文字列内の次の文字は右山かっこではないので、正規表現エンジンは ((?'Close-Open'>)[^<>]*) サブパターンに戻りません。
9 )* 最初のキャプチャ グループの値は "<abc>" です。

入力文字列内の次の文字は左山かっこなので、正規表現エンジンは (((?'Open'<) サブパターンに戻ります。
10 (((?'Open'<) "<mno" の左山かっこと一致し、そのかっこを Open グループに代入します。 その Group.Captures コレクションには、現在、単一の値 "<" が含まれています。
11 [^<>]* "mno" と一致します。
12 )+ "<mno" が 2 番目のキャプチャ グループの値になります。

入力文字列内の次の文字は左山かっこなので、正規表現エンジンは (?'Open'<)[^<>]*) サブパターンに戻ります。
13 (((?'Open'<) "<xyz>" の左山かっこと一致し、そのかっこを Open グループに代入します。 現在、Open グループの Group.Captures コレクションには、"<mno" の左山かっこと "<xyz>" の左山かっこの 2 つのキャプチャが含まれています。
14 [^<>]* "xyz" と一致します。
15 )+ "<xyz" が 2 番目のキャプチャ グループの値になります。

入力文字列内の次の文字は左山かっこではないので、正規表現エンジンは (?'Open'<)[^<>]*) サブパターンに戻りません。
16 ((?'Close-Open'>) "<xyz>" の右山かっこと一致します。 "xyz" は Open グループと右山かっこの間の部分文字列を Close グループに代入して、 Open グループの現在の値を削除します。 前のキャプチャの値 ("<mno" の左山かっこ) が Open グループの現在の値になります。 Open グループの Captures コレクションには、現在、単一のキャプチャ ("<xyz>" の左山かっこ) が含まれています。
17 [^<>]* 山かっこではない文字を検索します。一致する項目は見つかりません。
18 )+ 3 番目のキャプチャ グループの値は ">" です。

入力文字列内の次の文字は右山かっこなので、正規表現エンジンは ((?'Close-Open'>)[^<>]*) サブパターンに戻ります。
19 ((?'Close-Open'>) "xyz>>" の最後の右山かっこと一致し、"mno<xyz>" (Open グループと右山かっこの間の部分文字列) を Close グループに代入して、Open グループの現在の値を削除します。 Open グループは空になります。
20 [^<>]* 山かっこではない文字を検索します。一致する項目は見つかりません。
21 )+ 3 番目のキャプチャ グループの値は ">" です。

入力文字列内の次の文字は右山かっこではないので、正規表現エンジンは ((?'Close-Open'>)[^<>]*) サブパターンに戻りません。
22 )* 最初のキャプチャ グループの値は "<mno<xyz>>" です。

入力文字列内の次の文字は左山かっこではないので、正規表現エンジンは (((?'Open'<) サブパターンに戻りません。
23 (?(Open)(?!)) Open グループは定義されていないので、照合は試行されません。
24 $ 入力文字列の末尾と一致します。

非キャプチャ グループ

次のグループ化構成体では、部分式と一致する部分文字列はキャプチャされません。

(?:subexpression)

ここで、subexpression は有効な正規表現パターンです。 非キャプチャ グループ構成体は、通常、量指定子がグループに適用されるがグループによってキャプチャされた部分文字列は対象にならない場合に使用されます。

Note

正規表現に入れ子になったグループ化構成体が含まれる場合、外側の非キャプチャ グループ構成体は内側の入れ子になったグループ構成体には適用されません。

次の例は、非キャプチャ グループを含む正規表現を示しています。 出力には、キャプチャされたグループは含まれません。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?:\b(?:\w+)\W*)+\.";
      string input = "This is a short sentence.";
      Match match = Regex.Match(input, pattern);
      Console.WriteLine("Match: {0}", match.Value);
      for (int ctr = 1; ctr < match.Groups.Count; ctr++)
         Console.WriteLine("   Group {0}: {1}", ctr, match.Groups[ctr].Value);
   }
}
// The example displays the following output:
//       Match: This is a short sentence.
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "(?:\b(?:\w+)\W*)+\."
        Dim input As String = "This is a short sentence."
        Dim match As Match = Regex.Match(input, pattern)
        Console.WriteLine("Match: {0}", match.Value)
        For ctr As Integer = 1 To match.Groups.Count - 1
            Console.WriteLine("   Group {0}: {1}", ctr, match.Groups(ctr).Value)
        Next
    End Sub
End Module
' The example displays the following output:
'       Match: This is a short sentence.

正規表現 (?:\b(?:\w+)\W*)+\. は、ピリオドで終了する文と一致します。 この正規表現は個々の単語ではなく文に焦点を合わせているので、グループ化構成体は量指定子としてのみ使用されます。 この正規表現パターンの解釈を次の表に示します。

パターン 説明
\b ワード境界から照合を開始します。
(?:\w+) 1 つ以上の単語文字に一致します。 一致したテキストをキャプチャされたグループに代入しません。
\W* 0 個以上の単語文字に使用されない文字と一致します。
(?:\b(?:\w+)\W*)+ ワード境界から始まる 1 個以上の単語文字、および 0 個以上の単語文字に使用されない文字が 1 回以上続くパターンと一致します。 一致したテキストをキャプチャされたグループに代入しません。
\. ピリオドと一致します。

グループ オプション

次のグループ化構成体は、指定したオプションを部分式に適用または無効にします。

(?imnsx-imnsx:subexpression)

ここで、subexpression は有効な正規表現パターンです。 たとえば、 (?i-s:) によって、大文字小文字の区別が有効になり単一行モードが無効になります。 指定できるインライン オプションの詳細については、「 正規表現のオプション」を参照してください。

Note

System.Text.RegularExpressions.Regex クラス コンストラクターまたは静的メソッドを使用すると、部分式ではなく正規表現全体に適用されるオプションを指定できます。 また、 (?imnsx-imnsx) 言語コンストラクトを使うと、正規表現内の特定の位置より後に適用されるインライン オプションを指定できます。

グループ オプション構成体はキャプチャ グループではありません。 つまり、 subexpression によってキャプチャされる文字列の一部は一致に含まれますが、キャプチャ グループに含まれることも GroupCollection オブジェクトにデータを設定するために使用されることもありません。

たとえば、次の例の正規表現 \b(?ix: d \w+)\s では、グループ化構成体のインライン オプションを使用して、文字 "d" で始まるすべての単語を識別するときに、大文字と小文字を区別しない一致を有効にすると同時に、パターンの空白を無視します。 正規表現は、次の表に示すように定義されています。

パターン 説明
\b ワード境界から照合を開始します。
(?ix: d \w+) 大文字と小文字を区別しない一致を使用してこのパターンの空白を無視し、"d" の後に単語文字に使用される文字が 1 個以上続くパターンと一致します。
\s 空白文字と一致します。
string pattern = @"\b(?ix: d \w+)\s";
string input = "Dogs are decidedly good pets.";

foreach (Match match in Regex.Matches(input, pattern))
    Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index);
// The example displays the following output:
//    'Dogs // found at index 0.
//    'decidedly // found at index 9.
Dim pattern As String = "\b(?ix: d \w+)\s"
Dim input As String = "Dogs are decidedly good pets."

For Each match As Match In Regex.Matches(input, pattern)
    Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
Next
' The example displays the following output:
'    'Dogs ' found at index 0.
'    'decidedly ' found at index 9.      

ゼロ幅の肯定先読みアサーション

次のグループ化構成体は、ゼロ幅の肯定先読みアサーションを定義します。

(?=subexpression)

ここで、subexpression は正規表現パターンです。 一致と見なされるためには、入力文字列が subexpressionの正規表現パターンと一致する必要がありますが、一致した部分文字列は一致結果には含まれません。 ゼロ幅の肯定先読みアサーションはバックトラックしません。

通常、ゼロ幅の肯定先読みアサーションは正規表現パターンの末尾にあります。 一致と見なされるには文字列の末尾にある必要がありますが、一致には含まれない部分文字列を定義します。 これは、過度なバックトラッキングを防ぐためにも役立ちます。 ゼロ幅の肯定先読みアサーションを使用して、特定のキャプチャされたグループの先頭テキストが、そのキャプチャされたグループに対して定義されたパターンのサブセットと一致するテキストになるようにすることができます。 たとえば、キャプチャ グループが連続する単語文字と一致する場合に、ゼロ幅の肯定先読みアサーションを使用して、先頭の文字がアルファベット大文字になるように要求できます。

次の例では、ゼロ幅の肯定先読みアサーションを使用して、入力文字列内の動詞 "is" の前にある単語を照合します。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"\b\w+(?=\sis\b)";
      string[] inputs = { "The dog is a Malamute.",
                          "The island has beautiful birds.",
                          "The pitch missed home plate.",
                          "Sunday is a weekend day." };

      foreach (string input in inputs)
      {
         Match match = Regex.Match(input, pattern);
         if (match.Success)
            Console.WriteLine("'{0}' precedes 'is'.", match.Value);
         else
            Console.WriteLine("'{0}' does not match the pattern.", input);
      }
   }
}
// The example displays the following output:
//    'dog' precedes 'is'.
//    'The island has beautiful birds.' does not match the pattern.
//    'The pitch missed home plate.' does not match the pattern.
//    'Sunday' precedes 'is'.
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "\b\w+(?=\sis\b)"
        Dim inputs() As String = {"The dog is a Malamute.", _
                                   "The island has beautiful birds.", _
                                   "The pitch missed home plate.", _
                                   "Sunday is a weekend day."}

        For Each input As String In inputs
            Dim match As Match = Regex.Match(input, pattern)
            If match.Success Then
                Console.WriteLine("'{0}' precedes 'is'.", match.Value)
            Else
                Console.WriteLine("'{0}' does not match the pattern.", input)
            End If
        Next
    End Sub
End Module
' The example displays the following output:
'       'dog' precedes 'is'.
'       'The island has beautiful birds.' does not match the pattern.
'       'The pitch missed home plate.' does not match the pattern.
'       'Sunday' precedes 'is'.

この正規表現 \b\w+(?=\sis\b) の解釈を次の表に示します。

パターン 説明
\b ワード境界から照合を開始します。
\w+ 1 つ以上の単語文字に一致します。
(?=\sis\b) 単語文字に使用される文字の後に、空白文字とワード境界で終了する文字列 "is" が続くかどうかを確認します。 該当する場合は一致と見なされます。

ゼロ幅の否定先読みアサーション

次のグループ化構成体は、ゼロ幅の否定先読みアサーションを定義します。

(?!subexpression)

ここで、subexpression は正規表現パターンです。 一致と見なされるためには、入力文字列が subexpressionの正規表現パターンと一致しない必要がありますが、一致した文字列は一致結果には含まれません。

通常、ゼロ幅の否定先読みアサーションは正規表現の先頭または末尾で使用されます。 正規表現の先頭の場合は、類似してもより一般的なパターンを照合するように正規表現の先頭で定義されているときに、一致しない必要がある特定のパターンを定義できます。 この場合は、バックトラッキングを制限するためによく使用されます。 正規表現の末尾の場合は、一致の末尾に出現できない部分式を定義できます。

次の例では、正規表現の先頭でゼロ幅の先読みアサーションを使用して、"un" で始まらない単語を照合する正規表現を定義します。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"\b(?!un)\w+\b";
      string input = "unite one unethical ethics use untie ultimate";
      foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
         Console.WriteLine(match.Value);
   }
}
// The example displays the following output:
//       one
//       ethics
//       use
//       ultimate
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "\b(?!un)\w+\b"
        Dim input As String = "unite one unethical ethics use untie ultimate"
        For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
            Console.WriteLine(match.Value)
        Next
    End Sub
End Module
' The example displays the following output:
'       one
'       ethics
'       use
'       ultimate

この正規表現 \b(?!un)\w+\b の解釈を次の表に示します。

パターン 説明
\b ワード境界から照合を開始します。
(?!un) 次の 2 文字が "un" であるかどうかを確認します。 該当しない場合は一致と考えられます。
\w+ 1 つ以上の単語文字に一致します。
\b ワード境界で照合を終了します。

次の例では、正規表現の末尾でゼロ幅の先読みアサーションを使用して、区切り文字で終わらない単語を照合する正規表現を定義します。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"\b\w+\b(?!\p{P})";
      string input = "Disconnected, disjointed thoughts in a sentence fragment.";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine(match.Value);
   }
}
// The example displays the following output:
//       disjointed
//       thoughts
//       in
//       a
//       sentence
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "\b\w+\b(?!\p{P})"
        Dim input As String = "Disconnected, disjointed thoughts in a sentence fragment."
        For Each match As Match In Regex.Matches(input, pattern)
            Console.WriteLine(match.Value)
        Next
    End Sub
End Module
' The example displays the following output:
'       disjointed
'       thoughts
'       in
'       a
'       sentence

この正規表現 \b\w+\b(?!\p{P}) の解釈を次の表に示します。

パターン 説明
\b ワード境界から照合を開始します。
\w+ 1 つ以上の単語文字に一致します。
\b ワード境界で照合を終了します。
\p{P}) 次の文字が区切り記号 (ピリオドやコンマなど) ではない場合は一致と見なされます。

ゼロ幅の正の後読みアサーション

次のグループ化構成体は、ゼロ幅の正の後読みアサーションを定義します。

(?<=subexpression)

ここで、subexpression は正規表現パターンです。 一致と見なされるためには、 subexpression が入力文字列の現在の位置の左側に出現する必要がありますが、 subexpression は一致結果には含まれません。 ゼロ幅の正の後読みアサーションはバックトラックしません。

通常、ゼロ幅の正の後読みアサーションは正規表現の先頭で使用されます。 定義されるパターンは一致の事前条件ですが、一致結果には含まれません。

たとえば、次の例では、21 世紀の西暦下 2 桁を照合します (つまり、一致する文字列の前に数字 "20" がある必要があります)。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "2010 1999 1861 2140 2009";
      string pattern = @"(?<=\b20)\d{2}\b";

      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine(match.Value);
   }
}
// The example displays the following output:
//       10
//       09
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim input As String = "2010 1999 1861 2140 2009"
        Dim pattern As String = "(?<=\b20)\d{2}\b"

        For Each match As Match In Regex.Matches(input, pattern)
            Console.WriteLine(match.Value)
        Next
    End Sub
End Module
' The example displays the following output:
'       10
'       09

この正規表現パターン (?<=\b20)\d{2}\b の解釈を次の表に示します。

パターン 説明
\d{2} 2 桁の 10 進数と一致します。
(?<=\b20) ワード境界で 2 桁の 10 進数の前に 10 進数 "20" がある場合は照合を続行します。
\b ワード境界で照合を終了します。

ゼロ幅の正の後読みアサーションは、キャプチャされたグループの最後の文字がそのグループの正規表現パターンと一致する文字のサブセットになる必要がある場合に、バックトラッキングを制限するためにも使用されます。 たとえば、グループが連続するすべての単語文字をキャプチャする場合に、ゼロ幅の正の後読みアサーションを使用して、最後の文字がアルファベットになるように要求できます。

ゼロ幅の負の後読みアサーション

次のグループ化構成体は、ゼロ幅の負の後読みアサーションを定義します。

(?<!subexpression)

ここで、subexpression は正規表現パターンです。 一致と見なされるためには、 subexpression が入力文字列の現在の位置の左側に出現しない必要があります。 ただし、 subexpression と一致しない部分文字列は一致結果には含まれません。

通常、ゼロ幅の負の後読みアサーションは正規表現の先頭で使用されます。 定義されるパターンでは、後に続く文字列内の一致が除外されます。 このアサーションは、キャプチャされたグループの最後の文字がそのグループの正規表現パターンと一致する 1 つ以上の文字にならない必要がある場合に、バックトラッキングを制限するためにも使用されます。 たとえば、グループが連続するすべての単語文字をキャプチャする場合に、ゼロ幅の正の後読みアサーションを使用して、最後の文字がアンダースコア (_) にならないように要求できます。

次の例では、週末でない (土曜日や日曜日でない) 曜日の日付を照合します。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string[] dates = { "Monday February 1, 2010",
                         "Wednesday February 3, 2010",
                         "Saturday February 6, 2010",
                         "Sunday February 7, 2010",
                         "Monday, February 8, 2010" };
      string pattern = @"(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b";

      foreach (string dateValue in dates)
      {
         Match match = Regex.Match(dateValue, pattern);
         if (match.Success)
            Console.WriteLine(match.Value);
      }
   }
}
// The example displays the following output:
//       February 1, 2010
//       February 3, 2010
//       February 8, 2010
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim dates() As String = {"Monday February 1, 2010", _
                                  "Wednesday February 3, 2010", _
                                  "Saturday February 6, 2010", _
                                  "Sunday February 7, 2010", _
                                  "Monday, February 8, 2010"}
        Dim pattern As String = "(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b"

        For Each dateValue As String In dates
            Dim match As Match = Regex.Match(dateValue, pattern)
            If match.Success Then
                Console.WriteLine(match.Value)
            End If
        Next
    End Sub
End Module
' The example displays the following output:
'       February 1, 2010
'       February 3, 2010
'       February 8, 2010

この正規表現パターン (?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b の解釈を次の表に示します。

パターン 説明
\b ワード境界から照合を開始します。
\w+ 1 個以上の単語文字の後に空白文字が続くパターンと一致します。
\d{1,2}, 1 桁または 2 桁の 10 進数の後に空白文字とコンマが続くパターンと一致します。
\d{4}\b 4 桁の 10 進数と一致し、ワード境界で照合を終了します。
(?<!(Saturday|Sunday) ) 文字列 "Saturday" または "Sunday" の後に空白が続くパターン以外が一致の前にある場合は、一致と見なされます。

アトミック グループ

次のグループ化構成体は、アトミック グループを表します (他の正規表現エンジンでは、非バックトラッキング部分式、アトミック部分式、または 1 回のみの部分式として知られています)。

(?>subexpression)

ここで、subexpression は正規表現パターンです。

通常、正規表現にオプションまたは代替の一致パターンが含まれる場合に一致する文字列が見つからなかったときは、正規表現エンジンは複数の方向に分岐することで入力文字列とパターンを照合できます。 最初の分岐で一致する文字列が見つからなかった場合、正規表現エンジンは最初に一致した時点まで戻り (バックトラック)、2 番目の分岐を使用して照合を試みることができます。 すべての分岐が試されるまでこの処理を続行できます。

インデックスが 2 の (?>subexpression) 言語コンストラクトでは、バックトラッキングが無効になります。 正規表現エンジンは、入力文字列内の文字をできるだけ多く照合します。 一致する文字列が見つからなくなっても、バックトラックして代替パターン一致を試みることはありません。 つまり、部分式はその部分式単体と一致する文字列のみと一致します。部分式とその後続の部分式に基づく文字列の照合は試行しません。

バックトラッキングが成功しないことがわかっている場合は、このオプションを使用することをお勧めします。 正規表現エンジンで不要な検索が実行されないようにすることで、パフォーマンスが向上します。

次の例は、アトミック グループによってパターン一致の結果がどのように変わるかを示しています。 バックトラッキング正規表現は、ワード境界で一連の文字の繰り返しの後に同じ文字がもう一度出現するパターンと一致しますが、非バックトラッキング正規表現は一致しません。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string[] inputs = { "cccd.", "aaad", "aaaa" };
      string back = @"(\w)\1+.\b";
      string noback = @"(?>(\w)\1+).\b";

      foreach (string input in inputs)
      {
         Match match1 = Regex.Match(input, back);
         Match match2 = Regex.Match(input, noback);
         Console.WriteLine("{0}: ", input);

         Console.Write("   Backtracking : ");
         if (match1.Success)
            Console.WriteLine(match1.Value);
         else
            Console.WriteLine("No match");

         Console.Write("   Nonbacktracking: ");
         if (match2.Success)
            Console.WriteLine(match2.Value);
         else
            Console.WriteLine("No match");
      }
   }
}
// The example displays the following output:
//    cccd.:
//       Backtracking : cccd
//       Nonbacktracking: cccd
//    aaad:
//       Backtracking : aaad
//       Nonbacktracking: aaad
//    aaaa:
//       Backtracking : aaaa
//       Nonbacktracking: No match
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim inputs() As String = {"cccd.", "aaad", "aaaa"}
        Dim back As String = "(\w)\1+.\b"
        Dim noback As String = "(?>(\w)\1+).\b"

        For Each input As String In inputs
            Dim match1 As Match = Regex.Match(input, back)
            Dim match2 As Match = Regex.Match(input, noback)
            Console.WriteLine("{0}: ", input)

            Console.Write("   Backtracking : ")
            If match1.Success Then
                Console.WriteLine(match1.Value)
            Else
                Console.WriteLine("No match")
            End If

            Console.Write("   Nonbacktracking: ")
            If match2.Success Then
                Console.WriteLine(match2.Value)
            Else
                Console.WriteLine("No match")
            End If
        Next
    End Sub
End Module
' The example displays the following output:
'    cccd.:
'       Backtracking : cccd
'       Nonbacktracking: cccd
'    aaad:
'       Backtracking : aaad
'       Nonbacktracking: aaad
'    aaaa:
'       Backtracking : aaaa
'       Nonbacktracking: No match

非バックトラッキング正規表現 (?>(\w)\1+).\b は、次の表に示すように定義されています。

パターン 説明
(\w) 単語文字に使用される 1 文字と一致し、その文字を 1 番目のキャプチャ グループに代入します。
\1+ 最初にキャプチャされた部分文字列の値と 1 回以上一致します。
. 任意の文字と一致します。
\b ワード境界で照合を終了します。
(?>(\w)\1+) 重複する単語文字の 1 回以上の出現と一致しますが、バックトラックしてワード境界の最後の文字と一致することはありません。

グループ化構成体および正規表現オブジェクト

正規表現キャプチャ グループと一致する部分文字列は、 System.Text.RegularExpressions.Group オブジェクトで表されます。このオブジェクトは、 System.Text.RegularExpressions.GroupCollection プロパティによって返される Match.Groups オブジェクトから取得できます。 GroupCollection オブジェクトの値は次のように設定されます。

  • コレクション内の最初の Group オブジェクト (インデックス 0 の位置にあるオブジェクト) は、一致した文字列全体を表します。
  • 次の Group オブジェクト セットは、名前のない (番号付き) キャプチャ グループを表します。 正規表現で定義されている順序で左から右に並びます。 これらのグループのインデックス値の範囲は、1 からコレクション内の名前のないキャプチャ グループの数までです。 (特定のグループのインデックスは、番号付き逆参照と同じです。逆参照の詳細については、「前方参照構成体」を参照してください)。
  • 最後の Group オブジェクト セットは、名前付きキャプチャ グループを表します。 正規表現で定義されている順序で左から右に並びます。 最初の名前付きキャプチャ グループのインデックス値は、最後の名前のないキャプチャ グループのインデックスよりも 1 大きい数値になります。 正規表現に名前のないキャプチャ グループがない場合、最初の名前付きキャプチャ グループのインデックス値は 1 になります。

量指定子をキャプチャ グループに適用する場合、対応する Group オブジェクトの Capture.ValueCapture.Index、および Capture.Length の各プロパティには、キャプチャ グループによってキャプチャされた最後の部分文字列が反映されます。 量指定子を持つグループによってキャプチャされたすべての部分文字列は、 CaptureCollection プロパティによって返される Group.Captures オブジェクトから取得できます。

次の例では、 Group オブジェクトと Capture オブジェクトの関係を明確にします。

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(\b(\w+)\W+)+";
      string input = "This is a short sentence.";
      Match match = Regex.Match(input, pattern);
      Console.WriteLine("Match: '{0}'", match.Value);
      for (int ctr = 1; ctr < match.Groups.Count; ctr++)
      {
         Console.WriteLine("   Group {0}: '{1}'", ctr, match.Groups[ctr].Value);
         int capCtr = 0;
         foreach (Capture capture in match.Groups[ctr].Captures)
         {
            Console.WriteLine("      Capture {0}: '{1}'", capCtr, capture.Value);
            capCtr++;
         }
      }
   }
}
// The example displays the following output:
//       Match: 'This is a short sentence.'
//          Group 1: 'sentence.'
//             Capture 0: 'This '
//             Capture 1: 'is '
//             Capture 2: 'a '
//             Capture 3: 'short '
//             Capture 4: 'sentence.'
//          Group 2: 'sentence'
//             Capture 0: 'This'
//             Capture 1: 'is'
//             Capture 2: 'a'
//             Capture 3: 'short'
//             Capture 4: 'sentence'
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "(\b(\w+)\W+)+"
        Dim input As String = "This is a short sentence."
        Dim match As Match = Regex.Match(input, pattern)
        Console.WriteLine("Match: '{0}'", match.Value)
        For ctr As Integer = 1 To match.Groups.Count - 1
            Console.WriteLine("   Group {0}: '{1}'", ctr, match.Groups(ctr).Value)
            Dim capCtr As Integer = 0
            For Each capture As Capture In match.Groups(ctr).Captures
                Console.WriteLine("      Capture {0}: '{1}'", capCtr, capture.Value)
                capCtr += 1
            Next
        Next
    End Sub
End Module
' The example displays the following output:
'       Match: 'This is a short sentence.'
'          Group 1: 'sentence.'
'             Capture 0: 'This '
'             Capture 1: 'is '
'             Capture 2: 'a '
'             Capture 3: 'short '
'             Capture 4: 'sentence.'
'          Group 2: 'sentence'
'             Capture 0: 'This'
'             Capture 1: 'is'
'             Capture 2: 'a'
'             Capture 3: 'short'
'             Capture 4: 'sentence'

正規表現パターン (\b(\w+)\W+)+ は、文字列から単語を個別に抽出します。 このパターンは、次の表に示すように定義されています。

パターン 説明
\b ワード境界から照合を開始します。
(\w+) 1 つ以上の単語文字に一致します。 これらの文字が集まって、単語を形成します これが 2 番目のキャプチャ グループです。
\W+ 1 個以上の単語文字に使用されない文字と一致します。
(\b(\w+)\W+) 1 個以上の単語文字、および 1 個以上の単語文字に使用されない文字が 1 回以上続くパターンと一致します。 これが最初のキャプチャ グループです。

2 番目のキャプチャ グループは、文の各単語と一致します。 最初のキャプチャ グループは、各単語およびその単語に続く句読点や空白と一致します。 インデックスが 2 の Group オブジェクトは、2 番目のキャプチャ グループと一致したテキストの情報を保持します。 キャプチャ グループによってキャプチャされたすべての単語は、 CaptureCollection プロパティによって返される Group.Captures オブジェクトから取得できます。

関連項目