グループ化構成体

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

  • 入力文字列で繰り返し使用されている部分式を照合する。

  • 複数の正規表現言語要素を含む部分式に量指定子を適用する。 量指定子の詳細については、「量指定子」を参照してください。

  • Regex.Replace メソッドおよび Match.Result メソッドによって返される文字列に部分式を含める。

  • Match.Groups プロパティから個々の部分式を取得し、一致したテキスト全体とは別に処理する。

.NET Framework では、次の正規表現グループ化構成体がサポートされます。

  • 一致した部分式

  • 一致した名前付き部分式

  • グループ定義の均等化

  • 非キャプチャ グループ

  • グループ オプション

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

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

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

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

  • 非バックトラッキング部分式

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

一致した部分式

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

( subexpression )

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

メモメモ

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

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

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

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

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

  • プログラムで Match.Groups プロパティによって返される GroupCollection オブジェクトを使用する。 コレクション内の位置 0 にあるメンバーは、正規表現に一致した文字列全体を表します。 後続の各メンバーは、一致した部分式を表します。 詳細については、「グループ化構成体および正規表現オブジェクト」を参照してください。

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

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.
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(\w+)\s(\1)";
      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.

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

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

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

パターン

説明

(\w+)

1 個以上の単語文字に一致します。 これが最初のキャプチャ グループです。

\s

空白文字と一致します。

(\1)

最初のキャプチャ グループの文字列と一致します。 これが 2 番目のキャプチャ グループです。 例では、これをキャプチャ グループに割り当てて、重複する単語の開始位置を Match.Index プロパティから取得できるようにしています。

\W

空白や句読点などの単語文字以外の文字と一致します。 これにより、正規表現パターンが、最初のキャプチャ グループの単語で始まる単語と一致しなくなります。

一致した名前付き部分式

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

(?<name>subexpression)

または

(?'name' subexpression)

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

メモメモ

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

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

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

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

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

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

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

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

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

数値

名前

パターン

0

0 (既定名)

((?<One>abc)\d+)?(?<Two>xyz)(.*)

1

1 (既定名)

((?<One>abc)\d+)

2

2 (既定名)

(.*)

3

One

(?<One>abc)

4

Two

(?<Two>xyz)

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

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'.
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'.

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

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

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

パターン

説明

(?<duplicateWord>\w+)

1 個以上の単語文字に一致します。 このキャプチャ グループに duplicateWord という名前を付けます。

\s

空白文字と一致します。

\k<duplicateWord>

duplicateWord という名前のキャプチャ済みグループの文字列と一致します。

\W

空白や句読点などの単語文字以外の文字と一致します。 これにより、正規表現パターンが、最初のキャプチャ グループの単語で始まる単語と一致しなくなります。

(?<nextWord>\w+)

1 個以上の単語文字に一致します。 このキャプチャ グループに nextWord という名前を付けます。

グループ定義の均等化

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

(?<name1-name2>subexpression)

または

(?'name1-name2' subexpression)

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

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

メモメモ

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

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

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>
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>

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

^[^<>]*(((?'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 グループが定義されている場合は、正規表現エンジンによって、入力文字列内で部分式 (?!) の照合が試行されます。 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 は有効な正規表現パターンです。 非キャプチャ グループ構成体は、通常、量指定子がグループに適用されるがグループによってキャプチャされた部分文字列は対象にならない場合に使用されます。

メモメモ

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

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

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.
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.

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

パターン

説明

\b

ワード境界から照合を開始します。

(?:\w+)

1 個以上の単語文字に一致します。 一致したテキストをキャプチャされたグループに代入しません。

\W*

0 個以上の単語文字に使用されない文字と一致します。

(?:\b(?:\w+)\W*)+

ワード境界から始まる 1 個以上の単語文字、および 0 個以上の単語文字に使用されない文字が 1 回以上続くパターンと一致します。 一致したテキストをキャプチャされたグループに代入しません。

\.

ピリオドと一致します。

グループ オプション

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

(?imnsx-imnsx: subexpression )

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

メモメモ

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

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

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

パターン

説明

\b

ワード境界から照合を開始します。

(?ix: d \w+)

大文字と小文字を区別しない一致を使用してこのパターンの空白を無視し、"d" の後に単語文字に使用される文字が 1 個以上続くパターンと一致します。

\s

空白文字と一致します。

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.      
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.      

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

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

(?= subexpression )

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

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

次の例では、ゼロ幅の肯定先読みアサーションを使用して、入力文字列内の動詞 "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'.
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'.

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

パターン

説明

\b

ワード境界から照合を開始します。

\w+

1 個以上の単語文字に一致します。

(?=\sis\b)

単語文字に使用される文字の後に、空白文字とワード境界で終了する文字列 "is" が続くかどうかを確認します。 該当する場合は一致と見なされます。

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

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

(?! subexpression )

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

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

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

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
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

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

パターン

説明

\b

ワード境界から照合を開始します。

(?!un)

次の 2 文字が "un" であるかどうかを確認します。 該当しない場合は一致と考えられます。

\w+

1 個以上の単語文字に一致します。

\b

ワード境界で照合を終了します。

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

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
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

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

パターン

説明

\b

ワード境界から照合を開始します。

\w+

1 個以上の単語文字に一致します。

\b

ワード境界で照合を終了します。

\p{P})

次の文字が区切り記号 (ピリオドやコンマなど) ではない場合は一致と見なされます。

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

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

(?<= subexpression )

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

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

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

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
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

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

パターン

説明

\d{2}

2 桁の 10 進数と一致します。

{?<=\b20)

ワード境界で 2 桁の 10 進数の前に 10 進数 "20" がある場合は照合を続行します。

\b

ワード境界で照合を終了します。

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

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

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

(?<! subexpression )

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

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

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

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
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

正規表現パターン (?<!(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" の後に空白が続くパターン以外が一致の前にある場合は、一致と見なされます。

非バックトラッキング部分式

次のグループ化構成体は、非バックトラッキング部分式を表します。"最長" 部分式とも呼ばれます。

(?> subexpression )

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

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

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

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

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

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
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

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

パターン

説明

(\w)

単語文字に使用される 1 文字と一致し、その文字を 1 番目のキャプチャ グループに代入します。

\1+

最初にキャプチャされた部分文字列の値と 1 回以上一致します。

.

任意の文字と一致します。

\b

ワード境界で照合を終了します。

(?>(\w)\1+)

重複する単語文字の 1 回以上の出現と一致しますが、バックトラックしてワード境界の最後の文字と一致することはありません。

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

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

  • コレクション内の最初の Group オブジェクト (インデックス 0 の位置にあるオブジェクト) は、一致した文字列全体を表します。

  • 次の Group オブジェクト セットは、名前のない (番号付き) キャプチャ グループを表します。 正規表現で定義されている順序で左から右に並びます。 これらのグループのインデックス値の範囲は、1 からコレクション内の名前のないキャプチャ グループの数までです。 特定のグループのインデックスは、その番号付き前方参照と同等です。 前方参照の詳細については、「前方参照構成体」を参照してください。

  • 最後の Group オブジェクト セットは、名前付きキャプチャ グループを表します。 正規表現で定義されている順序で左から右に並びます。 最初の名前付きキャプチャ グループのインデックス値は、最後の名前のないキャプチャ グループのインデックスよりも 1 大きい数値になります。 正規表現に名前のないキャプチャ グループがない場合、最初の名前付きキャプチャ グループのインデックス値は 0 になります。

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

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

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
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

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

パターン

説明

\b

ワード境界から照合を開始します。

(\w+)

1 個以上の単語文字に一致します。 これらの文字が集まって、単語を形成します これが 2 番目のキャプチャ グループです。

\W+

1 個以上の単語文字に使用されない文字と一致します。

(\w+)\W+)+

1 個以上の単語文字、および 1 個以上の単語文字に使用されない文字が 1 回以上続くパターンと一致します。 これが最初のキャプチャ グループです。

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

参照

概念

バックトラッキング

その他の技術情報

正規表現言語要素