Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
По умолчанию сравнение входной строки с любыми литеральными символами в шаблоне регулярного выражения учитывает регистр, пробелы в шаблоне регулярного выражения интерпретируются как литеральные символы пробелов, а группы захвата в регулярном выражении могут именоваться автоматически, а также явно. Вы можете изменить эти и некоторые другие аспекты поведения регулярного выражения по умолчанию с помощью параметров регулярного выражения. Некоторые из этих параметров, перечисленных в следующей таблице, могут быть включены в состав шаблона регулярных выражений, или они могут быть предоставлены System.Text.RegularExpressions.Regex конструктору класса или методу System.Text.RegularExpressions.RegexOptions сопоставления статических шаблонов в качестве значения перечисления.
ЧленRegexOptions |
Встроенный символ | Действие | Дополнительные сведения |
---|---|---|---|
None | Недоступно | Использовать поведение по умолчанию. | Параметры по умолчанию |
IgnoreCase | i |
Использовать сравнение без учета регистра. | Сопоставление без учета регистра |
Multiline | m |
Используйте многострочный режим, где ^ и $ укажите начало и конец каждой строки (вместо начала и конца входной строки). |
Многострочный режим |
Singleline | s |
Использовать однострочный режим, где точка (.) соответствует любому символу (а не каждому символу, кроме \n ). |
Однострочный режим |
ExplicitCapture | n |
Не захватывать неименованные группы. К допустимым захватам относятся только явно именованные или нумерованные группы в формате (?< имя> часть выражения) . |
Только явные записи |
Compiled | Недоступно | Скомпилировать регулярное выражение в сборку. | Скомпилированные регулярные выражения |
IgnorePatternWhitespace | x |
Исключить неэкранированные пробелы из шаблона и включить комментарии после символа решетки (# ). |
Игнорировать пробелы |
RightToLeft | Недоступно | Изменить направление поиска. Поиск идет справа налево, а не слева направо. | Режим справа налево |
ECMAScript | Недоступно | Включить поведение, совместимое с ECMAScript, для выражения. | Поведение сопоставления ECMAScript |
CultureInvariant | Недоступно | Игнорировать культурные различия в языке. | Сравнение с использованием инвариантной культуры |
NonBacktracking | Недоступно | Сопоставление с использованием подхода, который позволяет избежать обратного отслеживания и гарантирует обработку за линейное время относительно длины входных данных. (Доступно в .NET 7 и более поздних версиях.) | Режим без возврата |
Указание параметров
Параметры регулярных выражений можно указать одним из трех способов:
В параметре
options
конструктора класса System.Text.RegularExpressions.Regex или статичного метода сопоставления шаблона (Shared
в Visual Basic), например Regex(String, RegexOptions) или Regex.Match(String, String, RegexOptions). Параметрoptions
— побитовое сложение (логическое ИЛИ) значений перечисления System.Text.RegularExpressions.RegexOptions.Когда параметры передаются экземпляру Regex с помощью параметра
options
конструктора класса, они присваиваются свойству System.Text.RegularExpressions.RegexOptions. Однако свойство System.Text.RegularExpressions.RegexOptions не отражает параметры встроенные непосредственно в шаблон регулярного выражения.Это показывается в следующем примере. В нем параметр
options
метода Regex.Match(String, String, RegexOptions) используется для включения сопоставления без учета регистра и игнорирования пробелов в шаблоне при выявлении слов, начинающихся с буквы "d".string pattern = @"d \w+ \s"; string input = "Dogs are decidedly good pets."; RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace; foreach (Match match in Regex.Matches(input, pattern, options)) Console.WriteLine($"'{match.Value}// found at index {match.Index}."); // The example displays the following output: // 'Dogs // found at index 0. // 'decidedly // found at index 9.
Dim pattern As String = "d \w+ \s" Dim input As String = "Dogs are decidedly good pets." Dim options As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.IgnorePatternWhitespace For Each match As Match In Regex.Matches(input, pattern, options) 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.
Применяя встроенные параметры в шаблоне регулярного выражения с помощью синтаксиса
(?imnsx-imnsx)
. Параметр применяется к шаблону с момента его определения и действует либо до конца шаблона, либо до точки, в которой другая встроенная опция обнуляет параметр. Обратите внимание на то, что свойство System.Text.RegularExpressions.RegexOptions экземпляра Regex не отражает этих встроенных параметров. Дополнительные сведения см. в разделе Другие конструкции.Это показывается в следующем примере. В нем используются встроенные опции для включения сопоставления без учета регистра букв и игнорирования пробелов в шаблоне при определении слов, начинающихся с буквы "d".
string pattern = @"(?ix) d \w+ \s"; string input = "Dogs are decidedly good pets."; foreach (Match match in Regex.Matches(input, pattern)) Console.WriteLine($"'{match.Value}// found at index {match.Index}."); // The example displays the following output: // 'Dogs // found at index 0. // 'decidedly // found at index 9.
Dim pattern As String = "\b(?ix) d \w+ \s" Dim input As String = "Dogs are decidedly good pets." For Each match As Match In Regex.Matches(input, pattern) Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index) Next ' The example displays the following output: ' 'Dogs ' found at index 0. ' 'decidedly ' found at index 9.
Применяя встроенные параметры в определенной конструкции группировки в шаблоне регулярного выражения с помощью синтаксиса
(?imnsx-imnsx:
часть выражения)
. Если перед набором параметров знак отсутствует, он включается; если перед набором параметров стоит знак минуса, набор отключается. (?
является фиксированной частью синтаксиса языковой конструкции, которая требуется независимо от того, включены или отключены параметры.) Этот параметр применяется только к этой группе. Дополнительные сведения см. в разделе Конструкции группировки.Это показывается в следующем примере. В нем используются встроенные опции в конструкции группировки для включения сопоставления без учета регистра и игнорирования пробелов в шаблоне при определении слов, начинающихся с буквы "d".
string pattern = @"\b(?ix: d \w+)\s"; string input = "Dogs are decidedly good pets."; foreach (Match match in Regex.Matches(input, pattern)) Console.WriteLine($"'{match.Value}// found at index {match.Index}."); // The example displays the following output: // 'Dogs // found at index 0. // 'decidedly // found at index 9.
Dim pattern As String = "\b(?ix: d \w+)\s" Dim input As String = "Dogs are decidedly good pets." For Each match As Match In Regex.Matches(input, pattern) Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index) Next ' The example displays the following output: ' 'Dogs ' found at index 0. ' 'decidedly ' found at index 9.
Если параметры указываются в строке, знак минуса (-
) перед параметром или набором параметров, отключает соответствующие параметры. Например, встроенная конструкция (?ix-ms)
включает параметры RegexOptions.IgnoreCase и RegexOptions.IgnorePatternWhitespace и отключает параметры RegexOptions.Multiline и RegexOptions.Singleline. Все параметры регулярного выражения по умолчанию отключены.
Примечание.
Если параметры регулярного выражения, указанные в параметре options
конструктора или вызове метода, конфликтуют со встроенными параметрами в шаблоне регулярного выражения, используются последние.
Следующие пять параметров регулярного выражения можно задавать одновременно в параметрах метода и в строке:
Следующие пять параметров регулярного выражения можно задавать в параметре options
, но не в строке:
Определение вариантов
Вы можете определить, какие параметры были предоставлены объекту Regex при создании его экземпляра, получив значение свойства Regex.Options только для чтения.
Чтобы проверить наличие любого параметра, кроме RegexOptions.None, выполните операцию AND со значением свойства Regex.Options и значением RegexOptions, которое вас интересует. Затем проверьте, равен ли результат значению RegexOptions. Следующий пример проверяет, задан ли параметр RegexOptions.IgnoreCase.
if ((rgx.Options & RegexOptions.IgnoreCase) == RegexOptions.IgnoreCase)
Console.WriteLine("Case-insensitive pattern comparison.");
else
Console.WriteLine("Case-sensitive pattern comparison.");
If (rgx.Options And RegexOptions.IgnoreCase) = RegexOptions.IgnoreCase Then
Console.WriteLine("Case-insensitive pattern comparison.")
Else
Console.WriteLine("Case-sensitive pattern comparison.")
End If
Чтобы проверить наличие параметра RegexOptions.None, определите, равно ли значение свойства Regex.Options значению RegexOptions.None, как показано в следующем примере.
if (rgx.Options == RegexOptions.None)
Console.WriteLine("No options have been set.");
If rgx.Options = RegexOptions.None Then
Console.WriteLine("No options have been set.")
End If
В следующих разделах перечислены параметры, поддерживаемые регулярными выражениями .NET.
Параметры по умолчанию
Параметр RegexOptions.None указывает, что ни один параметр не задан, а механизм регулярных выражений использует поведение по умолчанию. Это включает следующее:
Шаблон интерпретируется как каноническое, а не регулярное выражение ECMAScript.
Во входной строке шаблон регулярного выражения сопоставляется слева направо.
При сравнениях учитывается регистр.
Элементы
^
языка$
указывают начало и конец входной строки. Входная строка может заканчиваться завершающим символом новой строки\n
.Языковой элемент
.
соответствует каждому символу, кроме\n
.Любой пробел в шаблоне регулярного выражения интерпретируется как буквальный пробел.
При сравнении шаблона со входной строкой используются принятые в текущей культуре соглашения.
Группы захвата в шаблоне регулярного выражения могут быть как явными, так и неявными.
Примечание.
Параметр RegexOptions.None не имеет встроенного эквивалента. Если параметры регулярного выражения применяются в строке, поведение по умолчанию восстанавливается для каждого параметра, за счет отключения того или иного параметра. Например, (?i)
включает сравнение без учета регистра, а (?-i)
восстанавливает сравнение с учетом регистра по умолчанию.
Так как параметр RegexOptions.None представляет поведение механизма регулярных выражений по умолчанию, он редко явно указывается в вызове метода. Вместо этого вызывается конструктор или статический метод сопоставления шаблона без параметра options
.
Сопоставление без учета регистра
Параметр IgnoreCase или встроенный параметр i
обеспечивает сопоставление без учета регистра. По умолчанию используются соглашения о написании регистра в соответствии с текущей культурой.
Следующий пример определяет шаблон регулярного выражения, \bthe\w*\b
, который сопоставляет все слова, начинающиеся со строки "the". Так как первый вызов метода Match использует сравнение с учетом регистра по умолчанию, в выходных данных указывается о том, что строка "The" в начале предложения не была сопоставлена. Совпадение происходит, если метод Match вызывается с опциями IgnoreCase.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"\bthe\w*\b";
string input = "The man then told them about that event.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine($"Found {match.Value} at index {match.Index}.");
Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnoreCase))
Console.WriteLine($"Found {match.Value} at index {match.Index}.");
}
}
// The example displays the following output:
// Found then at index 8.
// Found them at index 18.
//
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "\bthe\w*\b"
Dim input As String = "The man then told them about that event."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern, _
RegexOptions.IgnoreCase)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found then at index 8.
' Found them at index 18.
'
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.
Следующий пример изменяет шаблон регулярного выражения из предыдущего примера, чтобы использовать встроенные опции вместо параметра options
, обеспечивая сравнение без учета регистра. Первый шаблон определяет регистронезависимую опцию в конструкции группировки, касающейся только буквы "t" в строке "the". Так как конструкция указана в начале шаблона, второй шаблон применяет параметр игнорирования регистра ко всему регулярному выражению.
using System;
using System.Text.RegularExpressions;
public class CaseExample
{
public static void Main()
{
string pattern = @"\b(?i:t)he\w*\b";
string input = "The man then told them about that event.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine($"Found {match.Value} at index {match.Index}.");
Console.WriteLine();
pattern = @"(?i)\bthe\w*\b";
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnoreCase))
Console.WriteLine($"Found {match.Value} at index {match.Index}.");
}
}
// The example displays the following output:
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
//
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
Imports System.Text.RegularExpressions
Module CaseExample
Public Sub Main()
Dim pattern As String = "\b(?i:t)he\w*\b"
Dim input As String = "The man then told them about that event."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
Console.WriteLine()
pattern = "(?i)\bthe\w*\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.
'
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.
Многострочный режим
Параметр RegexOptions.Multiline или встроенный параметр m
позволяет механизму регулярных выражений обрабатывать входную строку, которая состоит из нескольких строк. Он изменяет интерпретацию ^
элементов и $
языков, чтобы они указывали начало и конец строки, а не начало и конец входной строки.
По умолчанию $
будет удовлетворено только в конце входной строки. Если вы укажете параметр RegexOptions.Multiline, он будет удовлетворен символом новой строки (\n
) или концом входной строки.
Ни в одном случае $
не распознает комбинацию символов возврата каретки/перевода строки (\r\n
).
$
всегда игнорирует возврат каретки (\r
). Чтобы завершить совпадение либо \r\n
или \n
, используйте подвыражение \r?$
вместо просто $
. Обратите внимание, что это сделает \r
часть матча.
Следующий пример извлекает имена и баллы боулингистов и добавляет их в коллекцию SortedList<TKey,TValue>, сортируя их по убыванию. Метод Matches вызывается два раза. В первом вызове метода используется регулярное выражение ^(\w+)\s(\d+)$
, параметры не заданы. Как видно в результатах, совпадения не найдены, так как механизм регулярных выражений не может сопоставить входной шаблон с началом и концом входной строки. Во втором вызове метода регулярное выражение меняется на ^(\w+)\s(\d+)\r?$
и задаются параметры RegexOptions.Multiline. Как видно в результатах, имена и баллы успешно сопоставляются, а баллы отображаются по убыванию.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Multiline1Example
{
public static void Main()
{
SortedList<int, string> scores = new SortedList<int, string>(new DescendingComparer1<int>());
string input = "Joe 164\n" +
"Sam 208\n" +
"Allison 211\n" +
"Gwen 171\n";
string pattern = @"^(\w+)\s(\d+)$";
bool matched = false;
Console.WriteLine("Without Multiline option:");
foreach (Match match in Regex.Matches(input, pattern))
{
scores.Add(Int32.Parse(match.Groups[2].Value), (string)match.Groups[1].Value);
matched = true;
}
if (!matched)
Console.WriteLine(" No matches.");
Console.WriteLine();
// Redefine pattern to handle multiple lines.
pattern = @"^(\w+)\s(\d+)\r*$";
Console.WriteLine("With multiline option:");
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))
scores.Add(Int32.Parse(match.Groups[2].Value), (string)match.Groups[1].Value);
// List scores in descending order.
foreach (KeyValuePair<int, string> score in scores)
Console.WriteLine($"{score.Value}: {score.Key}");
}
}
public class DescendingComparer1<T> : IComparer<T>
{
public int Compare(T x, T y)
{
return Comparer<T>.Default.Compare(x, y) * -1;
}
}
// The example displays the following output:
// Without Multiline option:
// No matches.
//
// With multiline option:
// Allison: 211
// Sam: 208
// Gwen: 171
// Joe: 164
Imports System.Collections.Generic
Imports System.Text.RegularExpressions
Module Multiline1Example
Public Sub Main()
Dim scores As New SortedList(Of Integer, String)(New DescendingComparer1(Of Integer)())
Dim input As String = "Joe 164" + vbCrLf +
"Sam 208" + vbCrLf +
"Allison 211" + vbCrLf +
"Gwen 171" + vbCrLf
Dim pattern As String = "^(\w+)\s(\d+)$"
Dim matched As Boolean = False
Console.WriteLine("Without Multiline option:")
For Each match As Match In Regex.Matches(input, pattern)
scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
matched = True
Next
If Not matched Then Console.WriteLine(" No matches.")
Console.WriteLine()
' Redefine pattern to handle multiple lines.
pattern = "^(\w+)\s(\d+)\r*$"
Console.WriteLine("With multiline option:")
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)
scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
Next
' List scores in descending order.
For Each score As KeyValuePair(Of Integer, String) In scores
Console.WriteLine("{0}: {1}", score.Value, score.Key)
Next
End Sub
End Module
Public Class DescendingComparer1(Of T) : Implements IComparer(Of T)
Public Function Compare(x As T, y As T) As Integer _
Implements IComparer(Of T).Compare
Return Comparer(Of T).Default.Compare(x, y) * -1
End Function
End Class
' The example displays the following output:
' Without Multiline option:
' No matches.
'
' With multiline option:
' Allison: 211
' Sam: 208
' Gwen: 171
' Joe: 164
Шаблон регулярного выражения ^(\w+)\s(\d+)\r*$
определяется, как показано в следующей таблице.
Расписание | Описание |
---|---|
^ |
Начало с первого символа строки. |
(\w+) |
Совпадение с одним или несколькими символами слова. Это первая группа захвата. |
\s |
Соответствует символу пробела. |
(\d+) |
Совпадает с одной или несколькими десятичными цифрами. Это вторая группа захвата данных. |
\r? |
Найдите ноль или один символ возврата каретки. |
$ |
Заканчивается в конце строки. |
Следующий пример аналогичен предыдущему, но он использует встроенный параметр (?m)
для включения многострочного режима.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Multiline2Example
{
public static void Main()
{
SortedList<int, string> scores = new SortedList<int, string>(new DescendingComparer<int>());
string input = "Joe 164\n" +
"Sam 208\n" +
"Allison 211\n" +
"Gwen 171\n";
string pattern = @"(?m)^(\w+)\s(\d+)\r*$";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))
scores.Add(Convert.ToInt32(match.Groups[2].Value), match.Groups[1].Value);
// List scores in descending order.
foreach (KeyValuePair<int, string> score in scores)
Console.WriteLine($"{score.Value}: {score.Key}");
}
}
public class DescendingComparer<T> : IComparer<T>
{
public int Compare(T x, T y)
{
return Comparer<T>.Default.Compare(x, y) * -1;
}
}
// The example displays the following output:
// Allison: 211
// Sam: 208
// Gwen: 171
// Joe: 164
Imports System.Collections.Generic
Imports System.Text.RegularExpressions
Module Multiline2Example
Public Sub Main()
Dim scores As New SortedList(Of Integer, String)(New DescendingComparer(Of Integer)())
Dim input As String = "Joe 164" + vbCrLf +
"Sam 208" + vbCrLf +
"Allison 211" + vbCrLf +
"Gwen 171" + vbCrLf
Dim pattern As String = "(?m)^(\w+)\s(\d+)\r*$"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)
scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
Next
' List scores in descending order.
For Each score As KeyValuePair(Of Integer, String) In scores
Console.WriteLine("{0}: {1}", score.Value, score.Key)
Next
End Sub
End Module
Public Class DescendingComparer(Of T) : Implements IComparer(Of T)
Public Function Compare(x As T, y As T) As Integer _
Implements IComparer(Of T).Compare
Return Comparer(Of T).Default.Compare(x, y) * -1
End Function
End Class
' The example displays the following output:
' Allison: 211
' Sam: 208
' Gwen: 171
' Joe: 164
Однострочный режим
Параметр RegexOptions.Singleline или встроенный параметр s
позволяет механизму регулярных выражений обрабатывать входную строку так, будто она состоит из одной строки. Это делается путем изменения поведения элемента языка () периода.
, чтобы он соответствовал каждому символу вместо сопоставления каждого символа, за исключением нового символа \n
.
В следующем примере показано, как поведение языкового элемента .
меняется при использовании параметра RegexOptions.Singleline. Регулярное выражение ^.+
начинается с начала строки и соответствует любому знаку. По умолчанию совпадение заканчивается в конце первой строки; шаблон регулярного выражения соответствует символу \r
возврата каретки, но он не соответствует \n
. Поскольку параметр RegexOptions.Singleline интерпретирует всю входную строку как единую строку, он сопоставляет каждый символ в строке ввода, включая \n
.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = "^.+";
string input = "This is one line and" + Environment.NewLine + "this is the second.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(Regex.Escape(match.Value));
Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Singleline))
Console.WriteLine(Regex.Escape(match.Value));
}
}
// The example displays the following output:
// This\ is\ one\ line\ and\r
//
// This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "^.+"
Dim input As String = "This is one line and" + vbCrLf + "this is the second."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(Regex.Escape(match.Value))
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.SingleLine)
Console.WriteLine(Regex.Escape(match.Value))
Next
End Sub
End Module
' The example displays the following output:
' This\ is\ one\ line\ and\r
'
' This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.
Следующий пример аналогичен предыдущему, но он использует встроенный параметр (?s)
для включения однострочного режима.
using System;
using System.Text.RegularExpressions;
public class SingleLineExample
{
public static void Main()
{
string pattern = "(?s)^.+";
string input = "This is one line and" + Environment.NewLine + "this is the second.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(Regex.Escape(match.Value));
}
}
// The example displays the following output:
// This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.
Imports System.Text.RegularExpressions
Module SingleLineExample
Public Sub Main()
Dim pattern As String = "(?s)^.+"
Dim input As String = "This is one line and" + vbCrLf + "this is the second."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(Regex.Escape(match.Value))
Next
End Sub
End Module
' The example displays the following output:
' This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.
Только явные захваты
По умолчанию захватываемые группы определяются с помощью круглых скобок в шаблоне регулярного выражения. Именованным группам назначается имя или номер с помощью параметра языка (?<
имя>
часть выражения)
. Неименованные группы доступны по индексу. В объекте GroupCollection неименованные группы идут перед именованными.
Конструкции группировки часто используются только для применения квантификаторов к нескольким языковым элементам, а захваченные подстроки не представляют интереса. Например, если следующее регулярное выражение,
\b\(?((\w+),?\s?)+[\.!?]\)?
Предназначено только для извлечения из документа предложений, которые оканчиваются на точку, восклицательный или вопросительный знак. Интерес представляет только полученное предложение (в объекте Match). а отдельные слова в коллекции — нет.
Захватываемые группы, которые не используются впоследствии, могут потреблять много ресурсов, так как механизм регулярных выражений должен заполнить объекты GroupCollection и CaptureCollection коллекции. В качестве альтернативы можно использовать параметр RegexOptions.ExplicitCapture или встроенный параметр n
, чтобы указать, что допустимыми захватами являются только явно именованные или нумерованные группы, обозначенными конструкцией (?<
имя>
часть выражения)
.
Следующий пример отображает сведения о сопоставлениях, возвращаемых шаблоном регулярного выражения \b\(?((\w+),?\s?)+[\.!?]\)?
, если метод Match вызывается с параметром RegexOptions.ExplicitCapture или без него. Как видно в результатах выполнения первого вызова метода, механизм регулярных выражений полностью заполняет объекты коллекции GroupCollection и CaptureCollection данными о выделенных подстроках. Так как второй метод вызывается с параметром options
, для которого задано значение RegexOptions.ExplicitCapture, он не записывает информацию о группах.
using System;
using System.Text.RegularExpressions;
public class Explicit1Example
{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b\(?((?>\w+),?\s?)+[\.!?]\)?";
Console.WriteLine("With implicit captures:");
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine($"The match: {match.Value}");
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine($" Group {groupCtr}: {group.Value}");
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine($" Capture {captureCtr}: {capture.Value}");
captureCtr++;
}
}
}
Console.WriteLine();
Console.WriteLine("With explicit captures only:");
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.ExplicitCapture))
{
Console.WriteLine($"The match: {match.Value}");
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine($" Group {groupCtr}: {group.Value}");
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine($" Capture {captureCtr}: {capture.Value}");
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// With implicit captures:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// Group 1: sentence
// Capture 0: This
// Capture 1: is
// Capture 2: the
// Capture 3: first
// Capture 4: sentence
// Group 2: sentence
// Capture 0: This
// Capture 1: is
// Capture 2: the
// Capture 3: first
// Capture 4: sentence
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// Group 1: masterpiece
// Capture 0: Is
// Capture 1: it
// Capture 2: the
// Capture 3: beginning
// Capture 4: of
// Capture 5: a
// Capture 6: literary
// Capture 7: masterpiece
// Group 2: masterpiece
// Capture 0: Is
// Capture 1: it
// Capture 2: the
// Capture 3: beginning
// Capture 4: of
// Capture 5: a
// Capture 6: literary
// Capture 7: masterpiece
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// Group 1: not
// Capture 0: I
// Capture 1: think
// Capture 2: not
// Group 2: not
// Capture 0: I
// Capture 1: think
// Capture 2: not
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
// Group 1: paragraph
// Capture 0: Instead,
// Capture 1: it
// Capture 2: is
// Capture 3: a
// Capture 4: nonsensical
// Capture 5: paragraph
// Group 2: paragraph
// Capture 0: Instead
// Capture 1: it
// Capture 2: is
// Capture 3: a
// Capture 4: nonsensical
// Capture 5: paragraph
//
// With explicit captures only:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions
Module Explicit1Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph."
Dim pattern As String = "\b\(?((?>\w+),?\s?)+[\.!?]\)?"
Console.WriteLine("With implicit captures:")
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
Console.WriteLine()
Console.WriteLine("With explicit captures only:")
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.ExplicitCapture)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' With implicit captures:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' Group 1: sentence
' Capture 0: This
' Capture 1: is
' Capture 2: the
' Capture 3: first
' Capture 4: sentence
' Group 2: sentence
' Capture 0: This
' Capture 1: is
' Capture 2: the
' Capture 3: first
' Capture 4: sentence
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' Group 1: masterpiece
' Capture 0: Is
' Capture 1: it
' Capture 2: the
' Capture 3: beginning
' Capture 4: of
' Capture 5: a
' Capture 6: literary
' Capture 7: masterpiece
' Group 2: masterpiece
' Capture 0: Is
' Capture 1: it
' Capture 2: the
' Capture 3: beginning
' Capture 4: of
' Capture 5: a
' Capture 6: literary
' Capture 7: masterpiece
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' Group 1: not
' Capture 0: I
' Capture 1: think
' Capture 2: not
' Group 2: not
' Capture 0: I
' Capture 1: think
' Capture 2: not
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.
' Group 1: paragraph
' Capture 0: Instead,
' Capture 1: it
' Capture 2: is
' Capture 3: a
' Capture 4: nonsensical
' Capture 5: paragraph
' Group 2: paragraph
' Capture 0: Instead
' Capture 1: it
' Capture 2: is
' Capture 3: a
' Capture 4: nonsensical
' Capture 5: paragraph
'
' With explicit captures only:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.
Шаблон регулярного выражения \b\(?((?>\w+),?\s?)+[\.!?]\)?
определяется, как показано в следующей таблице.
Расписание | Описание |
---|---|
\b |
Начните с границы слова. |
\(? |
Соответствует нулю или одному вхождению открывающей круглой скобки ("("). |
(?>\w+),? |
Сопоставляется один или несколько словообразующих символов, за которыми следует ноль или одна запятая. При сопоставлении словообразующих символов обратный поиск не применяется. |
\s? |
Совпадение с нулем или одним символом пробела. |
((\w+),?\s?)+ |
Совпадение одного или нескольких символов, нуля или одной запятой, и нуля или одного пробела происходит один или несколько раз. |
[\.!?]\)? |
Сопоставляются любые из трех знаков пунктуации, за которыми следует ноль или одна закрывающая круглая скобка (")"). |
Вы также можете использовать элемент (?n)
в тексте, чтобы подавить автоматическое выделение. Следующий пример изменяет предыдущий шаблон регулярного выражения, чтобы использовать встроенный элемент (?n)
вместо параметра RegexOptions.ExplicitCapture.
using System;
using System.Text.RegularExpressions;
public class Explicit2Example
{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"(?n)\b\(?((?>\w+),?\s?)+[\.!?]\)?";
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine($"The match: {match.Value}");
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine($" Group {groupCtr}: {group.Value}");
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine($" Capture {captureCtr}: {capture.Value}");
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions
Module Explicit2Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph."
Dim pattern As String = "(?n)\b\(?((?>\w+),?\s?)+[\.!?]\)?"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.
Наконец, вы можете использовать встроенный элемент группы (?n:)
, чтобы отключить автоматический захват для каждой группы отдельно. Следующий пример изменяет предыдущий шаблон, чтобы отключить безымянные захваты во внешней группе, ((?>\w+),?\s?)
. Обратите внимание, что при этом подавляются неименованные выделения, в том числе и во внутренней группе.
using System;
using System.Text.RegularExpressions;
public class Explicit3Example
{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b\(?(?n:(?>\w+),?\s?)+[\.!?]\)?";
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine($"The match: {match.Value}");
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine($" Group {groupCtr}: {group.Value}");
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine($" Capture {captureCtr}: {capture.Value}");
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions
Module Explicit3Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph."
Dim pattern As String = "\b\(?(?n:(?>\w+),?\s?)+[\.!?]\)?"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.
Скомпилированные регулярные выражения
Примечание.
По возможности используйте созданные источником регулярные выражения вместо их компиляции с помощью параметра RegexOptions.Compiled. Генерация исходного кода может помочь вашему приложению быстрее запускаться, работать быстрее и быть более оптимизированным. Чтобы узнать, когда возможно создание источника, см. статью "Когда его использовать".
По умолчанию регулярные выражения в .NET интерпретируются. Когда создается экземпляр объекта Regex или вызывается статичный метод Regex, шаблон регулярного выражения преобразуется в набор настраиваемых кодов операций, а интерпретатор использует их для выполнения регулярного выражения. Это связано с компромиссом: стоимость инициализации подсистемы регулярных выражений сводится к минимуму за счет производительности во время выполнения.
Вместо интерпретируемых регулярных выражений можно использовать скомпилированные регулярные выражения, указав параметр RegexOptions.Compiled. В этом случае, когда шаблон передается обработчику регулярных выражений, он анализируется в набор опкодов, а затем преобразуется в общий промежуточный язык (CIL), который можно передать непосредственно в среду CLR. Скомпилированные регулярные выражения повышают производительность во время выполнения, но за счет более длительной инициализации.
Примечание.
Чтобы скомпилировать регулярное выражение, необходимо передать значение RegexOptions.Compiled параметру options
конструктора класса Regex или статичного метода сопоставления шаблона. Он недоступен в качестве встроенной опции.
Вы можете использовать скомпилированные регулярные выражения в вызовах как статических, так и экземплярных регулярных выражений. В статичных регулярных выражениях параметр RegexOptions.Compiled передается в параметр options
метода сопоставления шаблона регулярного выражения. В экземпляре регулярных выражений он передается в options
параметр конструктора класса Regex. В обоих случаях это повышает производительность.
Однако такой рост производительности возможен только в следующих условиях:
Объект Regex, представляющий определенное регулярное выражение, используется в нескольких вызовах методов сопоставления шаблона регулярного выражения.
Объект Regex не может выходить за область применения, поэтому его можно использовать повторно.
Статическое регулярное выражение используется в нескольких вызовах методов сопоставления шаблона регулярного выражения. (Рост производительности возможен, так как регулярные выражения, используемые в вызовах статичных методов, кэшируются механизмом регулярных выражений.)
Примечание.
Параметр RegexOptions.Compiled не связан с устаревшим Regex.CompileToAssembly методом, который создает сборку специального назначения, содержащую предопределенные скомпилированные регулярные выражения.
Игнорировать пробелы
По умолчанию пробел в шаблоне регулярного выражения важен; он заставляет механизм регулярных выражений сопоставлять символ пробела во входной строке. Поэтому регулярные выражения "\b\w+\s
" и "\b\w+
" практически аналогичны. Кроме того, если в шаблоне регулярного выражения найден символ номера (#), он интерпретируется как символ, которому следует найти соответствие.
Параметр RegexOptions.IgnorePatternWhitespace или встроенный параметр x
меняет такое поведение следующим образом:
Неэкранированный пробел в шаблоне регулярного выражения игнорируется. Чтобы включить символы пробела в шаблон регулярного выражения, их нужно экранировать (например, как
\s
или "\
").Символ решетки (#) интерпретируется как начало комментария, а не как обычный символ. Весь текст в шаблоне регулярного выражения от
#
символа до следующего\n
или конца строки интерпретируется как комментарий.
Но в следующих случаях пробелы в регулярном выражении не игнорируются, даже если указан параметр RegexOptions.IgnorePatternWhitespace.
Пробел внутри класса символов всегда интерпретируется буквально. Например, шаблон регулярного выражения
[ .,;:]
сопоставляет любой отдельный символ пробела, точки, запятой, точки с запятой или двоеточия.Пробел не допускается в пределах квантификаторов в квадратных скобках, таких как
{
n}
,{
n,}
и{
n,
m}
. Например, шаблон регулярного выражения\d{1, 3}
не сопоставляет последовательности цифр из одной до трех цифр, так как он содержит пробел.Пробел не допускается в последовательности символов, представляющей языковую конструкцию. Например:
Языковой элемент
(?:
subexpression)
представляет собой незахватываемую группу, и в части(?:
элемента не могут присутствовать внутренние пробелы. Шаблон(? :
часть выражения)
вызывает исключение ArgumentException во время выполнения, так как механизм регулярных выражений не может проанализировать шаблон, а шаблону( ?:
часть выражения)
не удается сопоставить часть выражения.Языковой элемент
\p{
name}
, представляющий категорию Юникода или именованный блок, не может содержать пробелы в части\p{
элемента. Если все-таки добавить пробел, элемент вызовет ошибку ArgumentException во время выполнения.
Включение этого параметра позволяет упростить регулярные выражения, синтаксический анализ и понимание которых зачастую вызывают затруднения. Это улучшает читаемость и позволяет документировать регулярное выражение.
В этом примере определяется следующий шаблон регулярного выражения:
\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.
Этот шаблон похож на тот, что определен в разделе Только явные захваты, за исключением того, что он использует параметр RegexOptions.IgnorePatternWhitespace для игнорирования пробелов в шаблоне.
using System;
using System.Text.RegularExpressions;
public class Whitespace1Example
{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// This is the first sentence.
// Is it the beginning of a literary masterpiece?
// I think not.
// Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions
Module Whitespace1Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph."
Dim pattern As String = "\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' This is the first sentence.
' Is it the beginning of a literary masterpiece?
' I think not.
' Instead, it is a nonsensical paragraph.
Следующий пример использует встроенный параметр (?x)
для игнорирования пробелов в шаблоне.
using System;
using System.Text.RegularExpressions;
public class Whitespace2Example
{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"(?x)\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// This is the first sentence.
// Is it the beginning of a literary masterpiece?
// I think not.
// Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions
Module Whitespace2Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph."
Dim pattern As String = "(?x)\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence."
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:
' This is the first sentence.
' Is it the beginning of a literary masterpiece?
' I think not.
' Instead, it is a nonsensical paragraph.
Режим "справа налево"
По умолчанию механизм регулярных выражений выполняет поиск слева направо. Направление поиска можно изменить с помощью параметра RegexOptions.RightToLeft. Поиск справа налево автоматически начинается в последней позиции символа строки. Для методов сопоставления шаблонов, включающих параметр начальной позиции, например Regex.Match(String, Int32), указанная начальная позиция является индексом самой правой позиции символа, с которой начинается поиск.
Примечание.
Чтобы включить режим "справа налево", необходимо передать значение RegexOptions.RightToLeft параметру options
конструктора класса Regex или статичного метода сопоставления шаблона. Недоступен в виде встроенной опции.
Пример
Регулярное выражение \bb\w+\s
соответствует словам с двумя или более символами, начинающимися с буквы "b" и за которым следует символ пробела. В следующем примере входная строка состоит из трех слов, которые содержат одну или несколько букв "b". Первое и второе слова начинаются с "b", а третье слово заканчивается "b". Как показано в выходных данных из примера поиска справа налево, только первые и вторые слова соответствуют шаблону регулярного выражения, а второе слово сопоставляется первым.
using System;
using System.Text.RegularExpressions;
public class RTL1Example
{
public static void Main()
{
string pattern = @"\bb\w+\s";
string input = "build band tab";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.RightToLeft))
Console.WriteLine($"'{match.Value}' found at position {match.Index}.");
}
}
// The example displays the following output:
// 'band ' found at position 6.
// 'build ' found at position 0.
Imports System.Text.RegularExpressions
Module RTL1Example
Public Sub Main()
Dim pattern As String = "\bb\w+\s"
Dim input As String = "build band tab"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.RightToLeft)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' 'band ' found at position 6.
' 'build ' found at position 0.
Порядок оценки
Параметр RegexOptions.RightToLeft изменяет направление поиска, а также изменяет порядок, в котором вычисляется шаблон регулярного выражения. В поиске справа налево шаблон поиска считывается справа налево. Это различие важно, так как это может повлиять на такие вещи, как группы записи и обратные ссылки. Например, выражение Regex.Match("abcabc", @"\1(abc)", RegexOptions.RightToLeft)
находит совпадение abcabc
, но в поиске слева направо (Regex.Match("abcabc", @"\1(abc)", RegexOptions.None)
), совпадение не найдено. Это связано с тем, что (abc)
элемент должен быть оценен перед нумерованным элементом записи группы (\1
) для поиска соответствия.
Утверждения Lookahead и lookbehind
Расположение совпадения для утверждения lookahead ((?=subexpression)
) или lookbehind ((?<=subexpression)
) не изменяется в поиске справа налево. Утверждения предварительного просмотра проверяют вправо от текущего расположения совпадения; утверждения отложенного просмотра проверяют влево от текущего расположения совпадения.
Совет
Независимо от того, является ли поиск справа налево или нет, ретроспективы реализуются с помощью поиска справа налево, начиная с текущего места совпадения.
Например, регулярное выражение (?<=\d{1,2}\s)\w+,\s\d{4}
использует оператор lookbehind для проверки даты, идущей перед названием месяца. Затем регулярное выражение сопоставляет месяц и год. Сведения об условных выражениях предсмотр и послесмотр см. в статье Конструкции группировки.
using System;
using System.Text.RegularExpressions;
public class RTL2Example
{
public static void Main()
{
string[] inputs = { "1 May, 1917", "June 16, 2003" };
string pattern = @"(?<=\d{1,2}\s)\w+,\s\d{4}";
foreach (string input in inputs)
{
Match match = Regex.Match(input, pattern, RegexOptions.RightToLeft);
if (match.Success)
Console.WriteLine($"The date occurs in {match.Value}.");
else
Console.WriteLine($"{input} does not match.");
}
}
}
// The example displays the following output:
// The date occurs in May, 1917.
// June 16, 2003 does not match.
Imports System.Text.RegularExpressions
Module RTL2Example
Public Sub Main()
Dim inputs() As String = {"1 May, 1917", "June 16, 2003"}
Dim pattern As String = "(?<=\d{1,2}\s)\w+,\s\d{4}"
For Each input As String In inputs
Dim match As Match = Regex.Match(input, pattern, RegexOptions.RightToLeft)
If match.Success Then
Console.WriteLine("The date occurs in {0}.", match.Value)
Else
Console.WriteLine("{0} does not match.", input)
End If
Next
End Sub
End Module
' The example displays the following output:
' The date occurs in May, 1917.
' June 16, 2003 does not match.
Шаблон регулярного выражения определяется, как показано в следующей таблице.
Расписание | Описание |
---|---|
(?<=\d{1,2}\s) |
Перед началом сопоставления должны идти одна или две десятичные цифры, за которыми следует пробел. |
\w+ |
Совпадение одной или нескольких буквенных символов. |
, |
Соответствует одному символу запятой. |
\s |
Соответствует символу пробела. |
\d{4} |
Совпадают 4 десятичных цифры. |
Поведение сопоставления ECMAScript
По умолчанию механизм регулярных выражений использует каноническое поведение при сопоставлении шаблона регулярного выражения с входным текстом. Однако вы можете указать движку регулярных выражений использовать поведение сопоставления ECMAScript, задав параметр RegexOptions.ECMAScript.
Примечание.
Чтобы включить поведение ECMAScript, необходимо передать значение RegexOptions.ECMAScript параметру options
конструктора класса Regex или статичного метода сопоставления шаблона. Этот параметр не может быть использован в качестве встроенной опции.
Параметр RegexOptions.ECMAScript может использоваться только вместе с параметрами RegexOptions.IgnoreCase и RegexOptions.Multiline. При использовании любого другого варианта в регулярном выражении возникает исключение ArgumentOutOfRangeException.
Поведение ECMAScript и канонических регулярных выражений отличается в трех аспектах: синтаксис класса символов, самоссылающиеся группы захвата и интерпретация восьмеричных значений в сравнении с обратными ссылками.
Синтаксис класса символов. Так как канонические регулярные выражения поддерживают Юникод, а ECMAScript — нет, синтаксис классов символов в ECMAScript более ограничен, а некоторые языковые элементы класса символов обладают другим значением. Например, ECMAScript не поддерживает такие языковые элементы, как категория Юникода или элементы блока
\p
и\P
. Аналогичным образом, элемент\w
, который сопоставляет символ слова, эквивалентен классу символов[a-zA-Z_0-9]
при использовании ECMAScript и[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]
при стандартном поведении. Дополнительные сведения см. в разделе Классы символов.Следующий пример иллюстрирует разницу между каноническим соответствием шаблону и ECMAScript. В нем определяется регулярное выражение,
\b(\w+\s*)+
, сопоставляющее слова, за которыми следуют пробелы. Входные данные состоят из двух строк, одна из которых использует латиницу, а другая — кириллицу. Как видно из результата, при вызове метода Regex.IsMatch(String, String, RegexOptions), использующего сопоставление ECMAScript, не удается сопоставить слова на кириллице, а при вызове метода, использующего каноническое сопоставление — удается.using System; using System.Text.RegularExpressions; public class EcmaScriptExample { public static void Main() { string[] values = { "целый мир", "the whole world" }; string pattern = @"\b(\w+\s*)+"; foreach (var value in values) { Console.Write("Canonical matching: "); if (Regex.IsMatch(value, pattern)) Console.WriteLine($"'{value}' matches the pattern."); else Console.WriteLine($"{value} does not match the pattern."); Console.Write("ECMAScript matching: "); if (Regex.IsMatch(value, pattern, RegexOptions.ECMAScript)) Console.WriteLine($"'{value}' matches the pattern."); else Console.WriteLine($"{value} does not match the pattern."); Console.WriteLine(); } } } // The example displays the following output: // Canonical matching: 'целый мир' matches the pattern. // ECMAScript matching: целый мир does not match the pattern. // // Canonical matching: 'the whole world' matches the pattern. // ECMAScript matching: 'the whole world' matches the pattern.
Imports System.Text.RegularExpressions Module Ecma1Example Public Sub Main() Dim values() As String = {"целый мир", "the whole world"} Dim pattern As String = "\b(\w+\s*)+" For Each value In values Console.Write("Canonical matching: ") If Regex.IsMatch(value, pattern) Then Console.WriteLine("'{0}' matches the pattern.", value) Else Console.WriteLine("{0} does not match the pattern.", value) End If Console.Write("ECMAScript matching: ") If Regex.IsMatch(value, pattern, RegexOptions.ECMAScript) Then Console.WriteLine("'{0}' matches the pattern.", value) Else Console.WriteLine("{0} does not match the pattern.", value) End If Console.WriteLine() Next End Sub End Module ' The example displays the following output: ' Canonical matching: 'целый мир' matches the pattern. ' ECMAScript matching: целый мир does not match the pattern. ' ' Canonical matching: 'the whole world' matches the pattern. ' ECMAScript matching: 'the whole world' matches the pattern.
Самоссылочные группы захвата Класс захвата регулярного выражения с обратной ссылкой на себя необходимо обновлять при каждой итерации захвата. Как показано в следующем примере, эта функция позволяет регулярному выражению
((a+)(\1) ?)+
сопоставлять входную строку "aa aaaa aaaaaa" при использовании ECMAScript, но не при каноническом сопоставлении.using System; using System.Text.RegularExpressions; public class EcmaScript2Example { static string pattern; public static void Main() { string input = "aa aaaa aaaaaa "; pattern = @"((a+)(\1) ?)+"; // Match input using canonical matching. AnalyzeMatch(Regex.Match(input, pattern)); // Match input using ECMAScript. AnalyzeMatch(Regex.Match(input, pattern, RegexOptions.ECMAScript)); } private static void AnalyzeMatch(Match m) { if (m.Success) { Console.WriteLine($"'{pattern}' matches {m.Value} at position {m.Index}."); int grpCtr = 0; foreach (Group grp in m.Groups) { Console.WriteLine($" {grpCtr}: '{grp.Value}'"); grpCtr++; int capCtr = 0; foreach (Capture cap in grp.Captures) { Console.WriteLine($" {capCtr}: '{cap.Value}'"); capCtr++; } } } else { Console.WriteLine("No match found."); } Console.WriteLine(); } } // The example displays the following output: // No match found. // // '((a+)(\1) ?)+' matches aa aaaa aaaaaa at position 0. // 0: 'aa aaaa aaaaaa ' // 0: 'aa aaaa aaaaaa ' // 1: 'aaaaaa ' // 0: 'aa ' // 1: 'aaaa ' // 2: 'aaaaaa ' // 2: 'aa' // 0: 'aa' // 1: 'aa' // 2: 'aa' // 3: 'aaaa ' // 0: '' // 1: 'aa ' // 2: 'aaaa '
Imports System.Text.RegularExpressions Module Ecma2Example Dim pattern As String Public Sub Main() Dim input As String = "aa aaaa aaaaaa " pattern = "((a+)(\1) ?)+" ' Match input using canonical matching. AnalyzeMatch(Regex.Match(input, pattern)) ' Match input using ECMAScript. AnalyzeMatch(Regex.Match(input, pattern, RegexOptions.ECMAScript)) End Sub Private Sub AnalyzeMatch(m As Match) If m.Success Then Console.WriteLine("'{0}' matches {1} at position {2}.", pattern, m.Value, m.Index) Dim grpCtr As Integer = 0 For Each grp As Group In m.Groups Console.WriteLine(" {0}: '{1}'", grpCtr, grp.Value) grpCtr += 1 Dim capCtr As Integer = 0 For Each cap As Capture In grp.Captures Console.WriteLine(" {0}: '{1}'", capCtr, cap.Value) capCtr += 1 Next Next Else Console.WriteLine("No match found.") End If Console.WriteLine() End Sub End Module ' The example displays the following output: ' No match found. ' ' '((a+)(\1) ?)+' matches aa aaaa aaaaaa at position 0. ' 0: 'aa aaaa aaaaaa ' ' 0: 'aa aaaa aaaaaa ' ' 1: 'aaaaaa ' ' 0: 'aa ' ' 1: 'aaaa ' ' 2: 'aaaaaa ' ' 2: 'aa' ' 0: 'aa' ' 1: 'aa' ' 2: 'aa' ' 3: 'aaaa ' ' 0: '' ' 1: 'aa ' ' 2: 'aaaa '
Определение регулярного выражения показано в следующей таблице.
Расписание Описание (a+) Соответствие букве "a" один или более раз. Это вторая группа записи. (\1) Сопоставление подстроки, выделенной первой захватываемой группой. Это третья группа захвата. ? Соответствует нулю или одному символу пробела. ((a+)(\1) ?)+ Один или несколько раз выделяется шаблон из одной или нескольких букв "a", за которыми следует строка, сопоставляющая первую захватываемую группу, за которой следует ноль или один символ пробела. Это первая группа захвата. Разрешение неоднозначности между восьмеричными Escape-символами и обратными ссылками. В следующей таблице представлены общие сведения об отличиях интерпретации восьмеричных чисел и обратных ссылок при использовании канонических регулярных выражений и ECMAScript.
Регулярное выражение Каноническое поведение Поведение ECMAScript \0
с последующими 0-2 восьмеричными цифрамиИнтерпретируется как восьмеричное число. Например, \044
всегда интерпретируется как восьмеричное значение и означает "$".Такое же поведение. \
с последующей цифрой от 1 до 9, за которой нет дополнительных десятичных цифр.Интерпретируется как обратная ссылка. Например, \9
всегда означает обратную ссылку на 9, даже если девятая захватываемая группа не существует. Если захватываемая группа не существует, парсер регулярных выражений бросает исключение ArgumentException.Если существует захватываемая группа с одной десятичной цифрой, сделайте обратную ссылку на эту цифру. В противном случае значение интерпретируется как литерал. \
с последующей цифрой от 1 до 9, за которой следуют дополнительные десятичные цифры.Цифры интерпретируются как десятичное значение. Если эта захватываемая группа существует, интерпретируйте выражение как обратную ссылку.
В противном случае интерпретируются первые восьмеричные цифры до восьмеричного числа 377, т. е. учитываются только младшие 8 разрядов значения. Оставшиеся цифры интерпретируются как литералы. Например, выражение\3000
, если захватываемая группа 300 существует, интерпретируется как обратная ссылка на 300. В противном случае оно интерпретируется как восьмеричное число 300, за которым следует 0.Выражение интерпретируется как обратная ссылка, для этого как можно больше цифр преобразуется в десятичное значение, которые могут указывать на выделение. Если цифры не могут быть преобразованы, выражение интерпретируется как восьмеричное число с использованием первых восьмеричных разрядов до восьмеричного числа 377. Оставшиеся восьмеричные цифры интерпретируются как литералы.
Сравнение с использованием инвариантной культуры
По умолчанию, когда модуль регулярных выражений выполняет сравнения без учета регистра, правила использования регистра в текущих региональных параметрах используются для определения эквивалентных прописных и строчных символов.
Однако это недопустимо для некоторых типов сравнения, например при сравнении введенных пользователем данных с именами системных ресурсов, таких как пароли, файлы и URL-адреса. В следующем примере показан такой сценарий. Этот код предназначен для блокировки доступа к любым ресурсам, URL-адрес которых начинается с FILE://. Регулярное выражение пытается выполнить сопоставление без учета чувствительности к регистру, используя выражение $FILE://
. Однако, если настройки текущей культуры системы заданы как tr-TR (Turkish-Турция), буква "I" не является эквивалентом буквы "i". В результате вызов метода Regex.IsMatch возвращает false
, и предоставляется доступ к файлу.
CultureInfo defaultCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
string input = "file://c:/Documents.MyReport.doc";
string pattern = "FILE://";
Console.WriteLine($"Culture-sensitive matching ({Thread.CurrentThread.CurrentCulture.Name} culture)...");
if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("URLs that access files are not allowed.");
else
Console.WriteLine($"Access to {input} is allowed.");
Thread.CurrentThread.CurrentCulture = defaultCulture;
// The example displays the following output:
// Culture-sensitive matching (tr-TR culture)...
// Access to file://c:/Documents.MyReport.doc is allowed.
Dim defaultCulture As CultureInfo = Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
Dim input As String = "file://c:/Documents.MyReport.doc"
Dim pattern As String = "$FILE://"
Console.WriteLine("Culture-sensitive matching ({0} culture)...",
Thread.CurrentThread.CurrentCulture.Name)
If Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase) Then
Console.WriteLine("URLs that access files are not allowed.")
Else
Console.WriteLine("Access to {0} is allowed.", input)
End If
Thread.CurrentThread.CurrentCulture = defaultCulture
' The example displays the following output:
' Culture-sensitive matching (tr-TR culture)...
' Access to file://c:/Documents.MyReport.doc is allowed.
Примечание.
Для получения дополнительной информации о сравнении строк с учетом регистра и использовании инвариантной культуры см. Рекомендации по использованию строк.
Вместо использования сравнений в текущей культуре без учета регистра можно указать параметр RegexOptions.CultureInvariant, чтобы игнорировать культурные различия в языке и использовать соглашения инвариантной культуры.
Примечание.
Для сравнения с использованием инвариантной культуры необходимо передать значение RegexOptions.CultureInvariant параметру options
конструктора класса Regex или статического метода сопоставления шаблона. Этот параметр недоступен в интегрированном варианте.
Следующий пример идентичен предыдущему, но в нем статичный метод Regex.IsMatch(String, String, RegexOptions) вызывается с параметрами, содержащими RegexOptions.CultureInvariant. Даже когда текущий язык и региональные настройки установлены на турецкий (Türkiye), механизм регулярных выражений может успешно совпадать с FILE и file и блокировать доступ к файлу.
CultureInfo defaultCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
string input = "file://c:/Documents.MyReport.doc";
string pattern = "FILE://";
Console.WriteLine("Culture-insensitive matching...");
if (Regex.IsMatch(input, pattern,
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
Console.WriteLine("URLs that access files are not allowed.");
else
Console.WriteLine($"Access to {input} is allowed.");
Thread.CurrentThread.CurrentCulture = defaultCulture;
// The example displays the following output:
// Culture-insensitive matching...
// URLs that access files are not allowed.
Dim defaultCulture As CultureInfo = Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
Dim input As String = "file://c:/Documents.MyReport.doc"
Dim pattern As String = "$FILE://"
Console.WriteLine("Culture-insensitive matching...")
If Regex.IsMatch(input, pattern,
RegexOptions.IgnoreCase Or RegexOptions.CultureInvariant) Then
Console.WriteLine("URLs that access files are not allowed.")
Else
Console.WriteLine("Access to {0} is allowed.", input)
End If
Thread.CurrentThread.CurrentCulture = defaultCulture
' The example displays the following output:
' Culture-insensitive matching...
' URLs that access files are not allowed.
Режим без отката
По умолчанию, обработчик регулярных выражений .NET использует бэктрекинг для поиска соответствий шаблону. Подсистема обратного отслеживания — это механизм, который пытается соответствовать одному шаблону, и если это не удается, возвращается и пытается сопоставить альтернативный шаблон и т. д. Механизм обратного отслеживания очень быстр для типичных случаев, но замедляется по мере увеличения числа чередований шаблонов, что может привести к катастрофическому обратному отслеживанию. Этот RegexOptions.NonBacktracking вариант, который был представлен в .NET 7, не использует бэктрекинг и избегает наихудших сценариев. Ее целью является обеспечение стабильного хорошего поведения независимо от искомых входных данных.
Этот RegexOptions.NonBacktracking параметр не поддерживает все возможности, которые поддерживаются другими встроенными механизмами. В частности, параметр нельзя использовать в сочетании с RegexOptions.RightToLeft или RegexOptions.ECMAScript. Он также не допускает следующие конструкции в шаблоне:
- Атомарные группы
- Обратные ссылки
- Группы балансировки
- Условные выражения
- Обходные пути
- Запуск якорей (
\G
)
RegexOptions.NonBacktracking также имеет тонкое различие в отношении исполнения. Если группа захвата находится в цикле, большинство механизмов регулярных выражений (non-.NET) предоставляют только последнее соответствующее значение для этого захвата. Однако обработчик регулярных выражений .NET отслеживает все значения, которые захватываются в цикле, и предоставляет доступ к ним. Этот RegexOptions.NonBacktracking вариант, как и большинство других реализаций регексп, поддерживает только предоставление конечного результата захвата.
Дополнительные сведения об обратном отслеживании см. в разделе Backtracking в регулярных выражениях.