Конструкции группирования

Конструкции группирования отображают части выражений регулярных выражений и захватывают части строки входной строки. Можно использовать конструкции группирования в следующих целях.

  • Сопоставить часть выражения, которая повторяется во входной строке.

  • Примените квантификатор к части выражения, которая имеет несколько языковых элементов регулярных выражений. Дополнительные сведения о кванторах см. в разделе Кванторы.

  • Включите часть выражения в строку, которая возвращается методами Regex.Replace и Match.Result.

  • Извлеките отдельные части выражения из свойства Match.Groups и обрабатывайте их отдельно от сопоставленного текста в целом.

Платформа .NET Framework поддерживает следующие конструкции группирования в регулярных выражениях:

  • Сопоставленные части выражений

  • Именованные сопоставленные части выражений

  • Сбалансированные определения групп

  • Группы без выделения

  • Параметры группы

  • Утверждения положительного просмотра вперед нулевой ширины

  • Утверждения отрицательного просмотра вперед нулевой ширины

  • Утверждения положительного просмотра назад нулевой ширины

  • Утверждения отрицательного просмотра назад нулевой ширины

  • Части выражений поиска без возврата

  • Конструкции группировки и объекты регулярных выражений

Сопоставленные части выражений

Следующая конструкция группирования захватывает соответствующую часть выражения:

( часть_выражения )

где часть выражения — это любой допустимый шаблон регулярного выражения. Записывает, что использование скобок нумеруется автоматически слева направо, основываясь на порядке открывающих скобок в регулярном выражении, начиная с 1. Захват с номером 0 – это текст, соответствующий всему шаблону регулярного выражения.

ПримечаниеПримечание

Если параметр RegexOptions метода сопоставления шаблона регулярного выражения включает флаг RegexOptions.ExplicitCapture или если параметр n применяется к этой части выражения (см. раздел Параметры группы далее в этой теме), то совпадающая часть выражения не захватывается.

Можно получить доступ к группам записи четырьмя способами:

  • С помощью конструкции обратной ссылки в регулярном выражении. Для ссылки на соответствующую часть выражения в том же регулярном выражении используется синтаксис \номер, где номер – это порядковый номер захваченной части выражения.

  • С помощью конструкции именованной обратной ссылки в регулярном выражении. Для ссылки на соответствующую часть выражения в том же регулярном выражении используется синтаксис \k<номер>, где номер – это порядковый номер захваченной части выражения. Захваченная часть выражения получает имя по умолчанию, идентичное ее порядковому номеру. Дополнительные сведения см. в разделе Именованные соответствующие части выражений.

  • С помощью последовательности замены $номер в вызове метода Regex.Replace или Match.Result, где номер – это порядковый номер захваченной части выражения.

  • Программно с помощью объекта GroupCollection, возвращаемого свойством Match.Groups. Элемент в позиции 0 коллекции представляет полное соответствие регулярного выражения. Каждый последующий элемент представляет соответствующую часть выражения. Дополнительные сведения см. в подразделе Конструкции группировки и объекты регулярных выражений.

В следующем примере приводится регулярное выражение, которое определяет повторяющиеся слова в тексте. Две группы записи шаблона регулярного выражения представляют два экземпляра повторяющегося слова. Второй экземпляр записывается, чтобы отметить его начальное положение во входной строке.

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

Совпадение с одним или несколькими символами слова. Это первая группа записи.

\s

Соответствует пробелу.

(\1)

Сопоставить строку в первой захваченной группе. Это вторая группа записи. В примере эта группа назначается захваченной группе, так что начальная позиция повторяющегося слова может быть получена из свойства Match.Index.

\W

Сопоставить с небуквенным символом, включая пробелы и знаки препинания. Это не позволяет шаблону регулярного выражения выделять слова, которые начинаются со слова из первой группы записи.

Именованные сопоставленные части выражений

Следующая конструкция группирования захватывает соответствующую часть выражения и позволяет получить к ней доступ по имени или номеру:

(?<name>subexpression)

или

(?'name' subexpression)

где имя является допустимым именем группы, а часть выражения — любой допустимый шаблон регулярного выражения. имя не должно содержать знаков пунктуации и не может начинаться с цифры.

ПримечаниеПримечание

Если параметр RegexOptions метода сопоставления шаблона регулярного выражения включает флаг RegexOptions.ExplicitCapture или если параметр n применяется к этой части выражения (см. раздел Параметры группы далее в этой теме), то единственный способ захвата части выражения состоит в явном названии захваченных групп.

Существуют следующие способы доступа к именованным группам записи:

  • С помощью конструкции именованной обратной ссылки в регулярном выражении. Для ссылки на соответствующую часть выражения в том же регулярном выражении используется синтаксис \k<имя>, где имя – это имя захваченной части выражения.

  • С помощью конструкции обратной ссылки в регулярном выражении. Для ссылки на соответствующую часть выражения в том же регулярном выражении используется синтаксис \номер, где номер – это порядковый номер захваченной части выражения. Именованные соответствующие части выражений нумеруются последовательно слева направо после соответствующих частей выражений.

  • С помощью последовательности замены ${имя} в вызове метода Regex.Replace или Match.Result, где имя – это имя захваченной части выражения.

  • С помощью последовательности замены $номер> в вызове метода Regex.Replace или Match.Result, где номер – это порядковый номер захваченной части выражения.

  • Программно с помощью объекта 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

One

(?<One>abc)

4

Два

(?<Two>xyz)

В следующем примере демонстрируется регулярное выражение, определяющее повторяющиеся слова и слова, непосредственно следующие за каждым повторяющимся словом. Шаблон регулярного выражения определяет две именованных части выражения: duplicateWord, которое представляет повторяющиеся слова, и nextWord, которое представляет слово, следующее за повторяющимся словом.

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

Совпадение с одним или несколькими символами слова. Назовите эту группу записи duplicateWord.

\s

Соответствует пробелу.

\k<duplicateWord>

Сопоставить строку из захваченной группы с именем duplicateWord.

\W

Сопоставить с небуквенным символом, включая пробелы и знаки препинания. Это не позволяет шаблону регулярного выражения выделять слова, которые начинаются со слова из первой группы записи.

(?<nextWord>\w+)

Совпадение с одним или несколькими символами слова. Назовите эту группу записи nextWord.

Сбалансированные определения групп

Сбалансированное определение группы удаляет определение ранее определенной группы и сохраняет в текущей группе интервал между ранее определенной группой и текущей группой. Эта конструкция группирования имеет следующий формат:

(?<name1-name2>subexpression)

или

(?'name1-name2' subexpression)

где имя1 — текущая группа (необязательно), имя2 — это предварительно определенная группа, часть выражения — любой допустимый шаблон регулярного выражения. Сбалансированное определение группы удаляет определение группы имя2 и сохраняет интервал между имя2 и имя1 в группе имя1. Если группа имя2 не определена, то сопоставление возвращается. Поскольку после удаления последнего определения имя2 открывается предыдущее определение имя2, эта конструкция позволяет использовать набор выделяемых областей для группы имя2 как счетчик для отслеживания вложенных конструкций, таких как круглые скобки или открывающие и закрывающие квадратные скобки.

Сбалансированное определение группы использует имя2 как стек. Начальный символ каждой вложенной конструкции помещается в эту группу и в ее коллекцию Group.Captures. При выделении закрывающего символа соответствующий ему открывающий символ удаляется из группы и значение Captures коллекции уменьшается на единицу. После сопоставления открывающих и закрывающих символов всех вложенных конструкций имя1 является пустым.

ПримечаниеПримечание

После изменения регулярного выражения в следующем примере для использования соответствующего открывающего и закрывающего символа вложенной конструкции можно использовать его для обработки большинства вложенных конструкций, таких как математические выражения или строки программного кода, включающие несколько вложенных вызовов методов.

В следующем примере используется сбалансированное определение группы, выделяющее левые и правые угловые скобки (<>) во входной строке. В примере определяются две именованные группы, Open и Close, которые используются в качестве стека для отслеживания соответствующих пар угловых скобок. Каждая записанная левая угловая скобка помещается в коллекцию захвата группы 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)(?!))$

Регулярное выражение интерпретируется следующим образом:

Шаблон

Описание

^

Начинайте с первого символа строки.

[^<>]*

Сопоставить ноль или более символов, не являющихся левыми или правыми угловыми скобками.

(?'Open'<)

Сопоставить с левой угловой скобкой и назначить группе с именем Open.

[^<>]*

Сопоставить ноль или более символов, не являющихся левыми или правыми угловыми скобками.

((?'Open'<)[^<>]*) +

Сопоставить одно или несколько вхождений левой угловой скобки, за которой следуют ноль или более символов, не являющихся левыми или правыми угловыми скобками. Это вторая группа записи.

(?'Close-Open'>)

Сопоставить правую угловую скобку, назначить подстроку между группой Open и текущей группой группе Close и удалить определение группы Open.

[^<>]*

Сопоставить ноль или более вхождений любого символа, не являющегося левой или правой угловой скобкой.

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

Сопоставить одно или несколько вхождений правой угловой скобки, за которой следуют ноль или более вхождений символов, не являющихся левыми или правыми угловыми скобками. При выделении правой угловой скобки задайте подстроку между группой Open и текущей группой Close, а затем удалите определение группы Open. Это третья группа записи.

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

Сопоставить ноль или более вхождений следующего шаблона: одна или несколько левых угловых скобок, за которыми следует ноль или более символов, не являющихся угловыми скобками, за которыми следует одна или несколько правых угловых скобок, за которыми следует ноль или более символов, не являющихся угловыми скобками. При выделении правой угловой скобки удалите определение группы Open и задайте подстроку между группой Open и текущей группой Close. Это первая группа записи.

(?(Open)(?!))

Если группа Open существует, сопоставьте вопросительный знак и восклицательный знак. Если группа Open определена, то сопоставление завершается неудачно, что указывает на несбалансированность угловых скобок.

$

Соответствует концу входной строки.

Окончательная часть выражения, (?(Open)(?!)), указывает, являются ли вложенные конструкции во входной строке должным образом сбалансированными (например, соответствует ли каждой левой угловой скобке правая угловая скобка). В ней используется условное сопоставление на основе допустимой захваченной группы. Дополнительные сведения см. в разделе Конструкции изменения. Если группа Open определена, то обработчик регулярных выражений пытается сопоставить часть выражения (?!) во входной строке. Группа Open должна быть определена только в том случае, если вложенные конструкции не сбалансированы. Таким образом, шаблон для сравнения во входной строке должен быть таким, что не может встречаться в входной строке, что приводит к ошибке сравнения.

В этом примере, обработчик регулярных выражений вычисляет строку ввода "<abc><mno<xyz>>", как это показано в следующей таблице.

Step

Шаблон

Результат

1

^

Начинает поиск соответствия с начале строки ввода

2

[^<>]*

Ищет символы, отличные от угловых скобок, до левой угловой скобки; не находит соответствий.

3

(((?'Open'<)

Выделяет левую угловую скобку в "<abc>" и назначает ее группе Open.

4

[^<>]*

Поиск соответствия последовательности символов "abc".

5

)+

"<abc" — значение второй захваченной группы.

Следующий символ во входной строке — это не левая угловая скобка, поэтому обработчик регулярных выражений не переходит к части шаблона (?'Open'<)[^<>]*).

6

((?'Close-Open'>)

Выделяет конечную правую угловую скобку в "<abc>", назначает "abc" (подстрока между группой Open и правой угловой скобкой) группе Close и удаляет текущее значение ("<") группы Open, делая ее пустой.

7

[^<>]*

Ищет символы, отличные от угловых скобок, после правой угловой скобки; не находит соответствий.

8

)+

Значение третьей группы записи равно ">".

Следующий символ во входной строке — это не правая угловая скобка, поэтому обработчик регулярных выражений не переходит к части шаблона ((?'Close-Open'>)[^<>]*).

9

)*

Значение первой группы записи равно "<abc>".

Следующий символ во входной строке — это левая угловая скобка, поэтому обработчик регулярных выражений переходит к части шаблона (((?'Open'<).

10

(((?'Open'<)

Выделяет левую угловую скобку в "<mno>" и назначает ее группе Open. Теперь у коллекции Group.Captures одно значение ("<").

11

[^<>]*

Поиск соответствия последовательности символов "mno".

12

)+

"<mno" — значение второй захваченной группы.

Следующий символ во входной строке — это левая угловая скобка, поэтому обработчик регулярных выражений переходит к части шаблона (?'Open'<)[^<>]*).

13

(((?'Open'<)

Выделяет левую угловую скобку в "<xyz>" и назначает ее группе Open. Коллекция Group.Captures Open группы теперь включает два элемента: левую угловую скобку из "<mno>" и левую угловую скобку из "<xyz>".

14

[^<>]*

Поиск соответствия последовательности символов "xyz".

15

)+

"<xyz" — значение второй захваченной группы.

Следующий символ во входной строке — это не левая угловая скобка, поэтому обработчик регулярных выражений не переходит к части шаблона (?'Open'<)[^<>]*).

16

((?'Close-Open'>)

Выделяет правую угловую скобку в "<xyz>". " xyz", задает подстроку между группой Open и правой угловой скобкой группе Close и удаляет текущее значение группы Open. Значением предыдущей записи (левый угол скобка в "<mno>") становится текущее значение группы Open. Коллекция Captures Open группы теперь включает один элемент: левую угловую скобку из "<xyz>".

17

[^<>]*

Ищет символы, отличные от угловых скобок; не находит соответствий.

18

)+

Значение третьей группы записи равно ">".

Следующий символ во входной строке — это правая угловая скобка, поэтому обработчик регулярных выражений переходит к части шаблона ((?'Close-Open'>)[^<>]*).

19

((?'Close-Open'>)

Выделяет конечную правую угловую скобку в "xyz>>", назначает "mno<xyz>" (подстрока между группой Open и правой угловой скобкой) группе Close и удаляет текущее значение группы Open. Группа Open сейчас пуста.

20

[^<>]*

Ищет символы, отличные от угловых скобок; не находит соответствий.

21

)+

Значение третьей группы записи равно ">".

Следующий символ во входной строке — это не правая угловая скобка, поэтому обработчик регулярных выражений не переходит к части шаблона ((?'Close-Open'>)[^<>]*).

22

)*

Значение первой группы записи равно "<mno<xyz>>".

Следующий символ во входной строке — это не левая угловая скобка, поэтому обработчик регулярных выражений не переходит к части шаблона (((?'Open'<).

23

(?(Open)(?!))

Группа Open не определена, поэтому не выполняется попытка поиска соответствия.

24

$

Выделяет конец строки ввода.

Группы без выделения

Следующая конструкция группирования не выполняет захват подстроки, соответствующей части выражения:

(?: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+)

Совпадение с одним или несколькими символами слова. Не следует назначать совпадающий текст захваченной группе.

\W*

Выделяет ноль или больше буквенных символов.

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

Сопоставить шаблон из одного или нескольких буквенных символов, начинающийся на границе слова, за которым следует одна или несколько групп из ноля или более небуквенных символов. Не следует назначать совпадающий текст захваченной группе.

\.

Совпадение с точкой.

Параметры группы

Следующая конструкция группирования применяет или отключает заданные параметры в части выражения:

(?imnsx-imnsx: часть_выражения )

где часть выражения — это любой допустимый шаблон регулярного выражения. Например, (?i-s:) включает учет регистра и делает невозможным однострочный режим. Дополнительные сведения о встроенных параметрах, которые можно задавать, см. в разделе Параметры регулярных выражений.

ПримечаниеПримечание

Можно указать параметры, применяемые ко всему регулярному выражению, а не часть выражения, с помощью конструктора класса System.Text.RegularExpressions.Regex или статического метода.Можно также указать встроенные параметры, применяемые после определенного момента в регулярном выражении с помощью конструкции языка (?imnsx-imnsx).

Конструкция параметров группы не является захваченной группой. Т. е. несмотря на то что любая часть строки, захваченная частью выражения, включается в сопоставление, она не включается в захваченную группу и не используется для заполнения объекта GroupCollection.

Например, в регулярном выражении \b(?ix: d \w+)\s из следующего примера используются встроенные параметры в конструкции группировки для включения сопоставления без учета регистра и игнорирования пробела шаблона при идентификации всех слов, начинающихся с буквы "d". Возможные интерпретации регулярного выражения определены в следующей таблице.

Шаблон

Описание

\b

Совпадение должно начинаться на границе слова.

(?ix: d \w+)

Используя выделение без учета регистра и пропуская пробелы в этом шаблоне, выделяется символ "d", за которым следует один или нескольких буквенных символов.

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

Утверждения положительного просмотра вперед нулевой ширины

Следующая конструкция группирования определяет утверждение положительного просмотра вперед нулевой ширины:

(?= часть_выражения )

где часть выражения — это любой шаблон регулярного выражения. Чтобы сопоставление было успешно, входная строка должна соответствовать шаблону регулярного выражения в части выражения, хотя сопоставленная подстрока не включается в результат сопоставления. Утверждение положительного просмотра вперед нулевой ширины не возвращается.

Как правило, утверждение положительного просмотра вперед нулевой ширины находится в конце шаблона регулярного выражения. Оно определяет подстроку, которая должна быть найдена в конце строки для возникновения соответствия, но которая не должна быть включена в соответствие. Шаблон также удобно использовать для ограничения количества поисков с возвратом. Можно использовать утверждение положительного просмотра вперед нулевой ширины, чтобы гарантировать, что та или иная зафиксированная группа начинается с текста, соответствующего подмножеству шаблона, определенного для этой зафиксированной группы. Например, если группа записи сопоставляет последовательные символы слова, можно использовать утверждение положительного просмотра вперед нулевой ширины, чтобы потребовать, что первый символ должен быть алфавитным символом верхнего регистра.

В следующем примере используется утверждение положительного просмотра вперед нулевой ширины для поиска слова, стоящего перед глаголом "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+

Совпадение с одним или несколькими символами слова.

(?=\sis\b)

Определите, следуют ли за словообразующими символами пробел и строка "is", которая заканчивается на границе слова. Если это так, то сопоставление является успешным.

Утверждения отрицательного просмотра вперед нулевой ширины

Следующая конструкция группирования определяет утверждение отрицательного просмотра вперед нулевой ширины:

(?! часть_выражения )

где часть выражения — это любой шаблон регулярного выражения. Чтобы сопоставление было успешно, входная строка не должна соответствовать шаблону регулярного выражения в части выражения, хотя сопоставленная строка не включается в результат сопоставления.

Утверждение отрицательного просмотра вперед нулевой ширины обычно используется в начале или в конце регулярного выражения. В начале регулярного выражения оно определяет конкретный шаблон, который не должен быть сопоставлен, когда начало регулярного выражения определяет похожий, но более общий шаблон для сопоставления. В этом случае шаблон часто используется для ограничения количества поисков с возвратом. В конце регулярного выражения оно может задавать часть выражения, которая не может находиться в конце совпадения.

В следующем примере определяется регулярное выражение, использующее утверждение просмотра вперед нулевой ширины в начале регулярного выражения для поиска соответствия слов, которые не начинаются с "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)

Определите, являются ли следующие два знака знаками "un". Если нет, то соответствие возможно.

\w+

Совпадение с одним или несколькими символами слова.

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

Совпадение с одним или несколькими символами слова.

\b

Совпадение должно заканчиваться на границе слова.

\p{P})

Если следующий символ не является знаком пунктуации (таким как точка или запятая), то поиск соответствия завершается успешно.

Утверждения положительного просмотра назад нулевой ширины

Следующая конструкция группирования определяет утверждение положительного просмотра назад нулевой ширины:

(?<= часть_выражения )

где часть выражения — это любой шаблон регулярного выражения. Чтобы сопоставление было успешно, часть выражения должна находиться во входной строке слева от текущей позиции, хотя subexpression не включается в результат сопоставления. Утверждение положительного просмотра назад нулевой ширины не возвращается.

Утверждение положительного просмотра вперед нулевой ширины обычно используется в начале или в конце регулярного выражения. Шаблон, который они определяют, является предпосылкой для сопоставления, но при этом не частью результата поиска соответствия.

Например, в следующем примере выполняется сопоставление двух последних цифр года для двадцать первого века (т. е. перед соответствующей строкой должны находиться цифры "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}

Совпадение с двумя десятичными цифрами.

{?<=\b20)

Продолжить поиск соответствия, если перед двумя десятичными цифрами находятся цифры "20" на границе слова.

\b

Совпадение должно заканчиваться на границе слова.

Утверждения положительного просмотра назад нулевой ширины также используются для ограничения поиска с возвратом, если последний символ или символы в записанной группе должны являться подмножеством символов, соответствующих шаблону регулярного положения группы. Например, если группа записывает все последовательные символы слова, можно использовать утверждение положительного просмотра назад нулевой ширины, чтобы потребовать, что последний символ должен быть алфавитным.

Утверждения отрицательного просмотра назад нулевой ширины

Следующая конструкция группирования определяет утверждение отрицательного просмотра назад нулевой ширины:

(?<! часть_выражения )

где часть выражения — это любой шаблон регулярного выражения. Чтобы сопоставление было успешно, часть выражения не должна находиться во входной строке слева от текущей позиции. Однако в результат поиска соответствия не включается ни одной подстроки, которая не соответствует subexpression.

Утверждение отрицательного просмотра назад нулевой ширины обычно используется в начале или в конце регулярного выражения. Шаблон, который они определяют, исключает соответствие в следующей строке. Они также используются для ограничения обратного отслеживания, если последний символ или символы в зафиксированной группе не должны являться одним или несколькими символами, соответствующими шаблону регулярных выражений этой группы. Например, если группа записывает все последовательные символы слова, можно использовать утверждение положительного просмотра назад нулевой ширины, чтобы потребовать, что последний символ не должен быть символом подчеркивания (_).

В следующем примере выполняется сопоставление даты любого дня недели, который не является выходным (т. е. это не суббота и не воскресенье).

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+

Соответствует одному или нескольким буквенным символам, за которыми следует пробел.

\d{1,2},

Сопоставить одну или две десятичные цифры, за которыми следует знак пробела и запятая.

\d{4}\b

Сопоставить четыре десятичные цифры и завершить сопоставление на границе слова.

(?<!(Saturday|Sunday) )

Если перед совпадением через пробел присутствует что-либо, отличное от строк "Saturday" или "Sunday", то поиск соответствия успешен.

Части выражений поиска без возврата

Следующая конструкция группирования представляет часть выражения для поиска без возврата (также известную как "жадная" часть выражения):

(?> часть_выражения )

где часть выражения — это любой шаблон регулярного выражения.

Обычно, если регулярное выражение содержит необязательный или альтернативный шаблон соответствия и поиск соответствие завершается неудачно, обработчик регулярных выражений может разрешать разветвление в нескольких направлениях для поиска соответствия входной строки с шаблоном. Если соответствие не найдено при приеме первой ветви, то обработчик регулярных выражений может создать резервную копию или вернуться в точку, где было обнаружено первое соответствие, и попытаться выполнить поиск соответствия с помощью второй ветви. Этот процесс может продолжаться до тех пор, пока не проверены все ветви.

Языковая конструкция (?>часть выражения) отключает поиск с возвратом. Обработчик регулярных выражений будет выделять столько символов во входной строке, сколько он может. Если дальнейшие соответствия невозможны, нет возврата для изменения совпадений шаблона. (То есть часть выражения соответствует только тем строкам, которые соответствовали бы одной этой части выражения; не делаются попытки сопоставить строку на основе этой части выражения и какой-либо следующей за ней части выражения.)

Рекомендуется использовать этот параметр, если известно, что поиск с возвратом не удастся. Предотвращение выполнения обработчиком регулярных выражений ненужного поиска улучшает производительность.

В следующем примере показывается, как часть выражения для поиска без возврата изменяет результаты соответствия шаблону. Регулярное выражение для поиска с возвратом успешно сопоставляет повторяющиеся символы, за которыми следует один или несколько одинаковых символов на границе слова, а регулярное выражение для поиска без возврата – нет.

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+

Сопоставить значение первой захваченной подстроки один или несколько раз.

.

Сопоставить любой символ.

\b

Совпадение должно заканчиваться на границе слова.

(?>(\w)\1+)

Сопоставить одно или несколько вхождений повторяющегося словообразующего символа, но не возвращаться для сопоставления последнего символа на границе слова.

Конструкции группировки и объекты регулярных выражений

Подстроки, которые сопоставляются захваченной группой регулярного выражения, представлены объектами System.Text.RegularExpressions.Group, которые могут быть извлечены из объекта System.Text.RegularExpressions.GroupCollection, возвращаемого свойством Match.Groups. Объект GroupCollection заполняется следующим образом:

  • Первый объект Group в коллекции (объект с индексом 0) представляет полное соответствие.

  • Следующий набор объектов Group представляет неименованные (нумерованные) группы записи. Они отображаются в том порядке, в каком они заданы в регулярном выражении, т. е. слева направо. Значения индекса этих групп находятся в диапазоне от 1 до количества неименованных захваченных групп в коллекции. (Индекс определенной группы эквивалентен ее нумерованной обратной ссылке. Дополнительные сведения об обратных ссылках см. в разделе Конструкции обратных ссылок).

  • Окончательный набор объектов Group представляет именованные захваченные группы. Они отображаются в том порядке, в каком они заданы в регулярном выражении, т. е. слева направо. Значение индекса первой именованной захваченной группы на единицу больше значения индекса последней неименованной захваченной группы. Если в регулярном выражении отсутствуют неименованные захваченные группы, значение индекса первой именованной захваченной группы равно нулю.

Если в захваченной группе применяется квантор, то свойства Capture.Value, Capture.Index и Capture.Length соответствующего объекта Group отражают последнюю подстроку, записанную захваченной группой. Можно получить полный набор подстрок, записанных группами с кванторами из объекта CaptureCollection, который возвращается свойством Group.Captures.

В следующем примере объясняется отношение объектов 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+)

Совпадение с одним или несколькими символами слова. Вместе эти символы формируют слово. Это вторая группа записи.

\W+

Совпадение с одним или несколькими символами, которые не являются буквой.

(\w+)\W+)+

Сопоставить шаблон из одного или нескольких буквенных символов, за которым следует одна или несколько групп из одного или более небуквенных символов. Это первая группа записи.

Первая захваченная группа соответствует каждому слову предложения. Вторая группа записи выделяет каждое слово вместе со знаками препинания и пробелами после слова. Объект Group, индекс которого равен 2, предоставляет сведения о тексте, выделенном второй группой захвата. Полный набор слов, записанных группой захвата, доступен в объекте CaptureCollection, возвращаемом свойством Group.Captures.

См. также

Основные понятия

Элементы языка регулярных выражений

Поиск с возвратом