Кванторы

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

Жадный квантор

Ленивый квантор

Описание

*

*?

Выделить ноль или несколько раз.

+

+?

Выделить один или несколько.

?

??

Выделить ноль или один раз.

{}n

{}?n

Соответствие ровно n раз.

{,}n

{,}?n

Выделяет как минимум n раз.

{n,m}

{n,m}?

Выделяет от n до m раз.

Количества n и m являются целочисленными константами. Обычно кванторы "жадные"; они заставляют обработчик регулярных выражений выделить максимально возможное число вхождений определенного шаблона. Добавление символа ? в квантор делает его отложенным; это приводит к тому, что обработчик регулярных выражений пытается искать так мало вхождений, как это возможно. Полное описание различий между "жадными" и "ленивыми" кванторами см. в разделе Жадные и ленивые кванторы далее в этой теме.

Важное примечаниеВажно

Квантификаторы вложенности (например, шаблон регулярного выражения (a*)*) могут увеличить количество сравнений, которые должен выполнять обработчик регулярных выражений, как экспоненциальная функция количества символов во входной строке.Дополнительные сведения об этом поведении и способах его обхода см. в разделе Поиск с возвратом.

Кванторы регулярных выражений

В следующих разделах перечислены кванторы, поддерживаемые регулярными выражениями платформы .NET Framework.

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

Если в шаблоне регулярных выражений встречаются символы *, +, ?, { и }, то обработчик регулярных выражений интерпретирует их как кванторы или как часть конструкций кванторов, если только они не включаются в класс символов.Чтобы они интерпретировались как символы-литералы за пределами класса символов, необходимо ставить перед ними escape-символ — обратную косую черту.Например, строка \* в шаблоне регулярного выражения интерпретируется как литеральный символ звездочки ("*").

Выделить ноль или несколько раз: *

Квантор * выделяет предыдущие элементы, повторяющиеся ноль или несколько раз. Это свойство эквивалентно квантору {0,}. * — жадный квантор, отложенным эквивалентом которого является квантор *?.

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

Dim pattern As String = "\b91*9*\b"   
Dim input As String = "99 95 919 929 9119 9219 999 9919 91119"
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next     
' The example displays the following output:   
'       '99' found at position 0.
'       '919' found at position 6.
'       '9119' found at position 14.
'       '999' found at position 24.
'       '91119' found at position 33.
string pattern = @"\b91*9*\b";   
string input = "99 95 919 929 9119 9219 999 9919 91119";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:   
//       '99' found at position 0.
//       '919' found at position 6.
//       '9119' found at position 14.
//       '999' found at position 24.
//       '91119' found at position 33.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

91*

Выделяет "9" с последующими символами "1" (если они есть).

9*

Выделить ноль или больше символов "9).

\b

Конец на границе слова.

Выделить один или несколько: +

Квантор + выделяет предыдущие элементы, повторяющиеся один или несколько раз. Этот параметр аналогичен параметру {1,}. + — жадный квантор, отложенным эквивалентом которого является квантор +?.

Например, с помощью регулярного выражения \ban+\w*?\b осуществляется поиск целых слов, которые начинаются с буквы a, за которой следует одна или несколько букв n. В следующем примере показано, как использовать это регулярное выражение. Регулярное выражение соответствует словам an, annual, announcement и antique и не соответствует словам autumn и all.

Dim pattern As String = "\ban+\w*?\b"

Dim input As String = "Autumn is a great time for an annual announcement to all antique collectors."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next   
' The example displays the following output:   
'       'an' found at position 27.
'       'annual' found at position 30.
'       'announcement' found at position 37.
'       'antique' found at position 57.      
string pattern = @"\ban+\w*?\b";

string input = "Autumn is a great time for an annual announcement to all antique collectors.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:   
//       'an' found at position 27.
//       'annual' found at position 30.
//       'announcement' found at position 37.
//       'antique' found at position 57.      

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

an+

Выделяет "a" с последующими символами "n" один или несколько раз.

\w*?

Выделяет буквенный символа минимальное количество раз (если они есть).

\b

Конец на границе слова.

Выделить ноль или один раз: ?

Квантор ? выделяет предыдущие элементы, повторяющиеся ноль или один раз. Этот параметр аналогичен параметру {0,1}. ? — жадный квантор, отложенным эквивалентом которого является квантор ??.

Например, с помощью регулярного выражения \ban?\b осуществляется поиск целых слов, которые начинаются с буквы a, за которой следует одна буква n или не следует ни одной такой буквы. Иными словами, предпринимается попытка найти слова a и an. В следующем примере показано, как использовать это регулярное выражение.

Dim pattern As String = "\ban?\b"
Dim input As String = "An amiable animal with a large snount and an animated nose."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next  
' The example displays the following output:   
'       'An' found at position 0.
'       'a' found at position 23.
'       'an' found at position 42.
string pattern = @"\ban?\b";
string input = "An amiable animal with a large snount and an animated nose.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:   
//        'An' found at position 0.
//        'a' found at position 23.
//        'an' found at position 42.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

an?

Выделяет "a" с последующими символами "n" (если они есть).

\b

Конец на границе слова.

Выделяет строго n раз: {n}

Квантор {n} выделяет предыдущий элемент ровно n раз, где n — это любое целое число. {n} – жадный квантор, отложенным эквивалентом которого является квантор {n}?.

Например, с помощью регулярного выражения \b\d+\,\d{3}\b осуществляется поиск границы слова, за которой следует один или более десятичных знаков, еще три десятичных знака и граница слова. В следующем примере показано, как использовать это регулярное выражение.

Dim pattern As String = "\b\d+\,\d{3}\b"
Dim input As String = "Sales totaled 103,524 million in January, " + _
                      "106,971 million in February, but only " + _
                      "943 million in March."
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next     
' The example displays the following output:   
'       '103,524' found at position 14.
'       '106,971' found at position 45.
string pattern = @"\b\d+\,\d{3}\b";
string input = "Sales totaled 103,524 million in January, " + 
                      "106,971 million in February, but only " + 
                      "943 million in March.";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:   
//        '103,524' found at position 14.
//        '106,971' found at position 45.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

\d+

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

\,

Выделяет символ запятой.

\d{3}

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

\b

Конец на границе слова.

Выделяет как минимум n раз: {n,}

Квантор {n,} выделяет предыдущий элемент хотя бы n раз, где n — это любое целое число. {n,} – жадный квантор, отложенным эквивалентом которого является квантор {n}?.

Например, с помощью регулярного выражения \b\d{2,}\b\D+ осуществляется поиск границы слова, за которой следует по крайней мере два десятичных знака, граница слова и знак, не являющийся числом. В следующем примере показано, как использовать это регулярное выражение. Регулярное выражение не соответствует фразе "7 days", потому что фраза содержит всего один десятичный знак, но соответствует фразам "10 weeks and 300 years".

 Dim pattern As String = "\b\d{2,}\b\D+"  
 Dim input As String = "7 days, 10 weeks, 300 years"
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next 
' The example displays the following output:
'       '10 weeks, ' found at position 8.
'       '300 years' found at position 18.
string pattern = @"\b\d{2,}\b\D+";   
string input = "7 days, 10 weeks, 300 years";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        '10 weeks, ' found at position 8.
//        '300 years' found at position 18.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

\d{2,}

Выделяет хотя бы две десятичных цифры.

\b

Соответствует границе слова.

\D+

Выделяет хотя бы одну цифру, не являющуюся десятичной .

Выделяет от n до m раз: {n, m}

Квантор {n,m} выделяет предыдущий элемент минимум n раз, но не больше m раз, где n и m — целые числа. {n,m} – жадный квантор, отложенным эквивалентом которого является квантор {n,m}?.

В следующем примере с помощью регулярного выражения (00\s){2,4} осуществляется поиск от двух до четырех вхождений двух нулей, за которыми следует пробел. Обратите внимание, что в конце входной строки имеются пять вхождений этого фрагмента при максимуме в четыре вхождения. Однако только начало этой части строки (до пробела и пятой пары нулей) соответствует шаблону регулярного выражения.

Dim pattern As String = "(00\s){2,4}"
Dim input As String = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00"
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next 
' The example displays the following output:
'       '00 00 ' found at position 8.
'       '00 00 00 ' found at position 23.
'       '00 00 00 00 ' found at position 35.
string pattern = @"(00\s){2,4}";
string input = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        '00 00 ' found at position 8.
//        '00 00 00 ' found at position 23.
//        '00 00 00 00 ' found at position 35.

Выделить ноль или несколько раз (ленивое совпадение): *?

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

В следующем примере с помощью регулярного выражения \b\w*?oo\w*?\b осуществляется поиск всех слов, содержащих строку oo.

 Dim pattern As String = "\b\w*?oo\w*?\b"
 Dim input As String = "woof root root rob oof woo woe"
 For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
    Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
 Next 
 ' The example displays the following output:
'       'woof' found at position 0.
'       'root' found at position 5.
'       'root' found at position 10.
'       'oof' found at position 19.
'       'woo' found at position 23.
 string pattern = @"\b\w*?oo\w*?\b";
 string input = "woof root root rob oof woo woe";
 foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
    Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

 //  The example displays the following output:
//        'woof' found at position 0.
//        'root' found at position 5.
//        'root' found at position 10.
//        'oof' found at position 19.
//        'woo' found at position 23.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

\w*?

Соответствует нулю или минимально возможному числу буквенных символов.

oo

Выделить строку "oo".

\w*?

Соответствует нулю или минимально возможному числу буквенных символов.

\b

Завершить на границе слова.

Выделить один или несколько раз (ленивое совпадение): +?

Квантор +? совпадает с предыдущим элементом один или несколько раз, но как можно меньшее число раз. Это ленивый квантор, дополняющий жадный квантор +.

Например, с помощью регулярного выражения \b\w+?\b осуществляется поиск одного или нескольких символов, разделенных границами слов. В следующем примере показано, как использовать это регулярное выражение.

 Dim pattern As String = "\b\w+?\b"
 Dim input As String = "Aa Bb Cc Dd Ee Ff"
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next 
' The example displays the following output:
'       'Aa' found at position 0.
'       'Bb' found at position 3.
'       'Cc' found at position 6.
'       'Dd' found at position 9.
'       'Ee' found at position 12.
'       'Ff' found at position 15.
string pattern = @"\b\w+?\b";
string input = "Aa Bb Cc Dd Ee Ff";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        'Aa' found at position 0.
//        'Bb' found at position 3.
//        'Cc' found at position 6.
//        'Dd' found at position 9.
//        'Ee' found at position 12.
//        'Ff' found at position 15.

Выделить ноль или один раз (ленивое совпадение): ??

Квантор ?? совпадает с предыдущим элементом 0 или 1 раз, но как можно меньшее число раз. Это ленивый квантор, дополняющий жадный квантор ?.

Например, регулярное выражение ^\s*(System.)??Console.Write(Line)??\(?? пытается сопоставить строки "Console.Write" или "Console.WriteLine". Строка может также включать System. перед Console, за ней может следовать открывающая скобка. Искомый текст должен находиться в начале строки, хотя перед ним может стоять пробел. В следующем примере показано, как использовать это регулярное выражение.

Dim pattern As String = "^\s*(System.)??Console.Write(Line)??\(??"
Dim input As String = "System.Console.WriteLine(""Hello!"")" + vbCrLf + _
                      "Console.Write(""Hello!"")" + vbCrLf + _
                      "Console.WriteLine(""Hello!"")" + vbCrLf + _
                      "Console.ReadLine()" + vbCrLf + _
                      "   Console.WriteLine"
For Each match As Match In Regex.Matches(input, pattern, _
                                         RegexOptions.IgnorePatternWhitespace Or RegexOptions.IgnoreCase Or RegexOptions.MultiLine)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next 
' The example displays the following output:
'       'System.Console.Write' found at position 0.
'       'Console.Write' found at position 36.
'       'Console.Write' found at position 61.
'       '   Console.Write' found at position 110.
string pattern = @"^\s*(System.)??Console.Write(Line)??\(??";
string input = "System.Console.WriteLine(\"Hello!\")\n" + 
                      "Console.Write(\"Hello!\")\n" + 
                      "Console.WriteLine(\"Hello!\")\n" + 
                      "Console.ReadLine()\n" + 
                      "   Console.WriteLine";
foreach (Match match in Regex.Matches(input, pattern, 
                                      RegexOptions.IgnorePatternWhitespace | 
                                      RegexOptions.IgnoreCase | 
                                      RegexOptions.Multiline))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        'System.Console.Write' found at position 0.
//        'Console.Write' found at position 36.
//        'Console.Write' found at position 61.
//        '   Console.Write' found at position 110.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

^

Выделить начало входного потока.

\s*

Сопоставить нулю или нескольким символам пробела.

(System.)??

Выделить ноль или одно вхождение строки "System.".

Console.Write

Соответствует строке "Console.Write".

(Line)??

Выделить ноль или одно вхождение строки "Line".

\(??

Выделить ноль или одно вхождение открывающей скобки.

Выделяет строго n раз (ленивое совпадение): {n}?

Квантор {n}? выделяет предыдущий элемент ровно n раз, где n — это любое целое число. Это ленивый квантор, дополняющий жадный квантор {n}+.

В следующем примере регулярное выражение \b(\w{3,}?\.){2}?\w{3,}?\b используется для определения адреса веб-сайта. Обратите внимание, что есть совпадение с www.microsoft.com и msdn.microsoft.com, но нет совпадения с mywebsite или mycompany.com.

 Dim pattern As String = "\b(\w{3,}?\.){2}?\w{3,}?\b"
 Dim input As String = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com"
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next     
' The example displays the following output:
'       'www.microsoft.com' found at position 0.
'       'msdn.microsoft.com' found at position 18.
string pattern = @"\b(\w{3,}?\.){2}?\w{3,}?\b";
string input = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        'www.microsoft.com' found at position 0.
//        'msdn.microsoft.com' found at position 18.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

(\w{3,}? \.)

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

(\w{3,}? \.){2}?

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

\b

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

Выделяет как минимум n раз (ленивое совпадение): {n,}?

Квантор {n,}? выделяет предыдущий элемент хотя бы n раз (где n — это любое целое число), но как можно меньшее количество раз. Это ленивый квантор, дополняющий жадный квантор {n,}.

См. пример использования квантора {n}? в предыдущем разделе. В регулярном выражении из этого примера квантор {n,} используется для поиска строки, состоящей по крайней мере из трех знаков, после которых стоит точка.

Выделяет от n до m раз (ленивое совпадение): {n, m}?

Квантор {n,m}? выделяет предыдущий элемент от n до m раз (где n и m — целые числа), но как можно меньшее число раз. Это ленивый квантор, дополняющий жадный квантор {n,m}.

В следующем примере регулярное выражение \b[A-Z](\w*\s+){1,10}?[.!?] соответствует фразам, содержащим от одного до десяти слов. Ему соответствуют все приложения исходной строки кроме одного предложения, длина которого составляет 18 слов.

Dim pattern As String = "\b[A-Z](\w*\s?){1,10}?[.!?]"
Dim input As String = "Hi. I am writing a short note. Its purpose is " + _
                      "to test a regular expression that attempts to find " + _
                      "sentences with ten or fewer words. Most sentences " + _
                      "in this note are short."
For Each match As Match In Regex.Matches(input, pattern)
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next 
' The example displays the following output:
'       'Hi.' found at position 0.
'       'I am writing a short note.' found at position 4.
'       'Most sentences in this note are short.' found at position 132.
string pattern = @"\b[A-Z](\w*?\s*?){1,10}[.!?]";
string input = "Hi. I am writing a short note. Its purpose is " + 
                      "to test a regular expression that attempts to find " + 
                      "sentences with ten or fewer words. Most sentences " + 
                      "in this note are short.";
foreach (Match match in Regex.Matches(input, pattern))
   Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

//  The example displays the following output:
//        'Hi.' found at position 0.
//        'I am writing a short note.' found at position 4.
//        'Most sentences in this note are short.' found at position 132.

В следующей таблице представлено определение шаблона регулярных выражений.

Шаблон

Описание

\b

Начало на границе слова.

[A-Z]

Выделяет символ верхнего регистра от А до Z.

(\w*\s+)

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

{1,10}?

Выделить предыдущий шаблон от 1 до 10 раз, но как можно меньшее число раз.

[.!?]

Выделяет любой из знаков препинания ".", "!" или "?".

Жадные и ленивые квантификаторы

У некоторых квантификаторов есть две версии.

  • Жадная версия.

    Жадный квантор пытается найти максимально возможное число соответствий элемента.

  • Нежадная (ленивая) версия.

    При использовании нежадных кванторов предпринимается попытка найти минимально возможное число соответствий элемента. Чтобы превратить "жадный" квантификатор в "отложенный" квантификатор, достаточно добавить ?.

Представьте простое регулярное выражение, позволяющее находить последние четыре цифры в числовой строке, например в номере кредитной карты. Версия этого выражения с жадным квантификатором * будет иметь вид \b.*([0-9]{4})\b. Однако если строка содержит два числа, то с помощью такого регулярного выражения будут найдены только последние четыре цифры второго числа, как показано в следующем примере.

Dim greedyPattern As String = "\b.*([0-9]{4})\b"
Dim input1 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input1, greedypattern)
   Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next
' The example displays the following output:
'       Account ending in ******1999.
string greedyPattern = @"\b.*([0-9]{4})\b";
string input1 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input1, greedyPattern))
   Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);

// The example displays the following output:
//       Account ending in ******1999.

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

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

Dim lazyPattern As String = "\b.*?([0-9]{4})\b"
Dim input2 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input2, lazypattern)
   Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next     
' The example displays the following output:
'       Account ending in ******3333.
'       Account ending in ******1999.
string lazyPattern = @"\b.*?([0-9]{4})\b";
string input2 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input2, lazyPattern))
   Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);

// The example displays the following output:
//       Account ending in ******3333.
//       Account ending in ******1999.

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

Кванторы и пустые соответствия

Квантификаторы *, + и {n,m}, а также их "отложенные" аналоги никогда не повторяются после пустого соответствия, если найдено минимальное количество фиксаций. Это правило предотвращает вхождение квантификаторов в бесконечные циклы при пустых соответствиях частей выражений, если максимальное количество возможных фиксаций группы бесконечно или приближено к бесконечному.

Например, в следующем коде показан результат вызова метода Regex.Match с шаблоном регулярного выражения (a?)*, который соответствует ноль или один символ "a" ноль или более раз. Обратите внимание, что отдельная группа записи записывает каждое вхождение "а", как и String.Empty, но второго пустого совпадения нет, потому что первое пустое совпадение предписывает квантификатору прекратить повторение.

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "(a?)*"
      Dim input As String = "aaabbb"
      Dim match As Match = Regex.Match(input, pattern)
      Console.WriteLine("Match: '{0}' at index {1}", 
                        match.Value, match.Index)
      If match.Groups.Count > 1 Then
         Dim groups As GroupCollection = match.Groups
         For grpCtr As Integer = 1 To groups.Count - 1
            Console.WriteLine("   Group {0}: '{1}' at index {2}", 
                              grpCtr, 
                              groups(grpCtr).Value,
                              groups(grpCtr).Index)
            Dim captureCtr As Integer = 0
            For Each capture As Capture In groups(grpCtr).Captures
               captureCtr += 1
               Console.WriteLine("      Capture {0}: '{1}' at index {2}", 
                                 captureCtr, capture.Value, capture.Index)
            Next
         Next 
      End If   
   End Sub
End Module
' The example displays the following output:
'       Match: 'aaa' at index 0
'          Group 1: '' at index 3
'             Capture 1: 'a' at index 0
'             Capture 2: 'a' at index 1
'             Capture 3: 'a' at index 2
'             Capture 4: '' at index 3
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = "(a?)*";
      string input = "aaabbb";
      Match match = Regex.Match(input, pattern);
      Console.WriteLine("Match: '{0}' at index {1}", 
                        match.Value, match.Index);
      if (match.Groups.Count > 1) {
         GroupCollection groups = match.Groups;
         for (int grpCtr = 1; grpCtr <= groups.Count - 1; grpCtr++) {
            Console.WriteLine("   Group {0}: '{1}' at index {2}", 
                              grpCtr, 
                              groups[grpCtr].Value,
                              groups[grpCtr].Index);
            int captureCtr = 0;
            foreach (Capture capture in groups[grpCtr].Captures) {
               captureCtr++;
               Console.WriteLine("      Capture {0}: '{1}' at index {2}", 
                                 captureCtr, capture.Value, capture.Index);
            }
         } 
      }   
   }
}
// The example displays the following output:
//       Match: 'aaa' at index 0
//          Group 1: '' at index 3
//             Capture 1: 'a' at index 0
//             Capture 2: 'a' at index 1
//             Capture 3: 'a' at index 2
//             Capture 4: '' at index 3

Чтобы увидеть практическое различие между группой фиксации, определяющей минимальное и максимальное количество фиксаций, и группой, определяющей фиксированное количество фиксаций, воспользуйтесь шаблонами регулярных выражений (a\1|(?(1)\1)){0,2} и (a\1|(?(1)\1)){2}. Оба регулярных выражения состоят из одной группы записи, которая определяется, как показано в следующей таблице.

Шаблон

Описание

(a\1

Каждое из выражений сопоставляет "a" вместе со значением первой группы записи ...

|(?(1)

… или проверьте, была ли определена первая записанная группа. (Обратите внимание, что конструкция (?(1) не определяет группу записи.)

\1))

Если первая сохраненная группа существует, сопоставьте ее значение. Если группа не существует, группа будет соответствовать String.Empty.

Первое регулярное выражение пытается сопоставить этот шаблон от 0 до двух раз; второе, ровно два раза. Поскольку первый шаблон достигает своего минимального количества записей при первой записи значения String.Empty, он не повторяет попытку сопоставить a\1; квантификатор {0,2} допускает только пустые соответствия в последней итерации. Напротив, второе регулярное выражение соответствует "а", потому что оно вычисляет a\1 второй раз; минимальное число итераций (2) предписывает обработчику выполнять повтор после пустого соответствия.

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern, input As String

      pattern = "(a\1|(?(1)\1)){0,2}"
      input = "aaabbb" 

      Console.WriteLine("Regex pattern: {0}", pattern)
      Dim match As Match = Regex.Match(input, pattern)
      Console.WriteLine("Match: '{0}' at position {1}.", 
                        match.Value, match.Index)
      If match.Groups.Count > 1 Then
         For groupCtr As Integer = 1 To match.Groups.Count - 1
            Dim group As Group = match.Groups(groupCtr)         
            Console.WriteLine("   Group: {0}: '{1}' at position {2}.", 
                              groupCtr, group.Value, group.Index)
            Dim captureCtr As Integer = 0
            For Each capture As Capture In group.Captures
               captureCtr += 1
               Console.WriteLine("      Capture: {0}: '{1}' at position {2}.", 
                                 captureCtr, capture.Value, capture.Index)
            Next   
         Next
      End If
      Console.WriteLine()

      pattern = "(a\1|(?(1)\1)){2}"
      Console.WriteLine("Regex pattern: {0}", pattern)
      match = Regex.Match(input, pattern)
         Console.WriteLine("Matched '{0}' at position {1}.", 
                           match.Value, match.Index)
      If match.Groups.Count > 1 Then
         For groupCtr As Integer = 1 To match.Groups.Count - 1
            Dim group As Group = match.Groups(groupCtr)         
            Console.WriteLine("   Group: {0}: '{1}' at position {2}.", 
                              groupCtr, group.Value, group.Index)
            Dim captureCtr As Integer = 0
            For Each capture As Capture In group.Captures
               captureCtr += 1
               Console.WriteLine("      Capture: {0}: '{1}' at position {2}.", 
                                 captureCtr, capture.Value, capture.Index)
            Next   
         Next
      End If
   End Sub
End Module
' The example displays the following output:
'       Regex pattern: (a\1|(?(1)\1)){0,2}
'       Match: '' at position 0.
'          Group: 1: '' at position 0.
'             Capture: 1: '' at position 0.
'       
'       Regex pattern: (a\1|(?(1)\1)){2}
'       Matched 'a' at position 0.
'          Group: 1: 'a' at position 0.
'             Capture: 1: '' at position 0.
'             Capture: 2: 'a' at position 0.
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern, input;

      pattern = @"(a\1|(?(1)\1)){0,2}";
      input = "aaabbb"; 

      Console.WriteLine("Regex pattern: {0}", pattern);
      Match match = Regex.Match(input, pattern);
      Console.WriteLine("Match: '{0}' at position {1}.", 
                        match.Value, match.Index);
      if (match.Groups.Count > 1) {
         for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
         {
            Group group = match.Groups[groupCtr];         
            Console.WriteLine("   Group: {0}: '{1}' at position {2}.", 
                              groupCtr, group.Value, group.Index);
            int captureCtr = 0;
            foreach (Capture capture in group.Captures) {
               captureCtr++;
               Console.WriteLine("      Capture: {0}: '{1}' at position {2}.", 
                                 captureCtr, capture.Value, capture.Index);
            }   
         }
      }
      Console.WriteLine();

      pattern = @"(a\1|(?(1)\1)){2}";
      Console.WriteLine("Regex pattern: {0}", pattern);
      match = Regex.Match(input, pattern);
         Console.WriteLine("Matched '{0}' at position {1}.", 
                           match.Value, match.Index);
      if (match.Groups.Count > 1) {
         for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
         {
            Group group = match.Groups[groupCtr];         
            Console.WriteLine("   Group: {0}: '{1}' at position {2}.", 
                              groupCtr, group.Value, group.Index);
            int captureCtr = 0;
            foreach (Capture capture in group.Captures) {
               captureCtr++;
               Console.WriteLine("      Capture: {0}: '{1}' at position {2}.", 
                                 captureCtr, capture.Value, capture.Index);
            }   
         }
      }
   }
}
// The example displays the following output:
//       Regex pattern: (a\1|(?(1)\1)){0,2}
//       Match: '' at position 0.
//          Group: 1: '' at position 0.
//             Capture: 1: '' at position 0.
//       
//       Regex pattern: (a\1|(?(1)\1)){2}
//       Matched 'a' at position 0.
//          Group: 1: 'a' at position 0.
//             Capture: 1: '' at position 0.
//             Capture: 2: 'a' at position 0.

См. также

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

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

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

Журнал изменений

Дата

Журнал

Причина

Октябрь 2010

Добавлен подраздел о квантификаторах и пустых соответствиях.

Улучшение информации.