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

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

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

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

.NET определяет отдельные элементы языка для ссылки на нумерованные и именованные захватываемые группы. Дополнительные сведения о группах записи см. в статье Конструкции группирования.

Нумерованные обратные ссылки

Нумерованная обратная ссылка использует следующий синтаксис:

где число — это порядковое положение захватываемой группы в регулярном выражении. Например, \4 соответствует содержимому четвертой захватываемой группы. Если параметр число не определен в шаблоне регулярного выражения, возникает ошибка синтаксического анализа, и обработчик регулярных выражений создает исключение ArgumentException. Например, регулярное выражение \b(\w+)\s\1 является допустимым, поскольку (\w+) — это первая и единственная захватываемая группа в выражении. С другой стороны, выражение \b(\w+)\s\2 недопустимо и создает исключение аргумента, так как захватываемая группа с номером \2 отсутствует. Кроме того, если число определяет захватываемую группу с определенным порядковым номером, но захватываемой группе назначено числовое имя, отличное от ее порядкового номера, то анализатор регулярных выражений также создает исключение ArgumentException.

Следует отметить неоднозначность такой записи, которая может означать как восьмеричные escape-коды (например, \16 ), так и \ число для обратных ссылок. Эта неопределенность разрешается следующим образом:

Выражения с \1 по \9 всегда интерпретируются как обратные ссылки, а не как восьмеричные коды.

Если первая цифра многоразрядного выражения — 8 или 9 (например, \80 или \91 ), выражение интерпретируется как литерал.

Выражения от \10 и более считаются обратными ссылками, если имеется обратная ссылка, соответствующая этому номеру. В противном случае они интерпретируются как восьмеричные коды.

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

Если неоднозначность представляет проблему, можно использовать однозначное представление \k< name > , которое невозможно спутать с восьмеричными кодами символов. Аналогичным образом шестнадцатеричные коды, например \xdd , однозначны, и их нельзя спутать с обратными ссылками.

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

Элемент Описание: (\w) Совпадение со словообразующим символом и его назначение первой захватываемой группе. \1 Совпадение со следующим символом, значение которого совпадает с первой захватываемой группой.

Именованные обратные ссылки

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

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

В приведенном ниже примере в строке выделяются двойные словообразующие символы. Здесь определяется регулярное выражение, (?<char>\w)\k<char> , которое состоит из следующих элементов.

Элемент Описание: (?<char>\w) Сопоставляется с буквенным символом и назначает его группе записи с именем char . \k<char> Сопоставляется со следующим символом, значение которого совпадает со значением группы записи char .

Именованные числовые обратные ссылки

В именованной обратной ссылке с \k имя также может быть строковым представлением числа. Например, далее используется регулярное выражение (?<2>\w)\k<2> для поиска в строке двойных словообразующих символов. В этом случае в примере определяется захватываемая группа, которая явно названа "2", и обратная ссылка, соответственно названная "2".

Если имя является строковым представлением числа и не существует захватываемой группы с таким именем, то \k< имя > совпадает со значением обратной ссылки \ номер, где номер — порядковый номер записи. В следующем примере существует одна захватываемая группа с именем char . Конструкция обратной ссылки ссылается на нее как \k<1> . Как видно из результата выполнения примера, вызов Regex.IsMatch завершается успешно, поскольку char является первой группой записи.

Однако, если имя является строковым представлением числа и захватываемой группе на этой позиции явно назначено числовое имя, обработчик регулярных выражений не сможет идентифицировать захватываемую группу по ее порядковому номеру. Вместо этого он создаст исключение ArgumentException. Единственная захватываемая группа в следующем примере имеет имя "2". Поскольку конструкция \k используется для определения обратных ссылок с именем "1", обработчик регулярных выражений не может идентифицировать первую группу записи и вызывает исключение.

С чем сопоставляются обратные ссылки

Обратная ссылка относится к самому недавнему определению группы (самому ближнему слева определению при обработке слева направо). Если из группы создается несколько шаблонов для поиска, обратная ссылка относится к самому последнему шаблону.

В примере ниже показан шаблон регулярного выражения (?<1>a)(?<1>\1b)* , который переопределяет именованную группу \1. В следующей таблице описывается каждый шаблон регулярного выражения.

Шаблон Описание: (?<1>a) Сопоставляется с символом "a" и назначает его значение группе записи с именем 1 . (?<1>\1b)* Сопоставляется с нулем или одним вхождением группы с именем 1 рядом с символом "b" и назначает полученное значение группе записи с именем 1 .

При сравнении регулярного выражения с входной строкой ("aababb") обработчик регулярных выражений выполняет указанные далее операции.

Начинается с первого символа и успешно сопоставляет "a" с выражением (?<1>a) . Теперь значение группы 1 будет равно "a".

Перемещается ко второму символу и успешно сопоставляет строку "ab" с выражением \1b или "ab". Затем результат "ab" присваивается \1 .

Переходит к четвертому символу. Выражение (?<1>\1b)* должно выдать ноль или больше совпадений, поэтому он успешно сопоставляет строку "abb" с выражением \1b . Затем результат "abb" присваивается \1 .

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

Если для группы не было найдено ни одной подстроки, то обратная ссылка на эту группу не определена и не работает. Это продемонстрировано в шаблоне регулярного выражения \b(\p)(\d)?(\p)\b , который определяется следующим образом:

Шаблон Описание: \b Сопоставление начинается на границе слова. (\p) Совпадение с двумя прописными буквами. Это первая группа записи. (\d)? Совпадение с нулевым или единичным вхождением двух десятичных цифр. Это вторая группа записи. (\p) Совпадение с двумя прописными буквами. Это третья группа записи. \b Сопоставление заканчивается на границе слова.

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

📎📎📎📎📎📎📎📎📎📎