Регулярные выражения с обратными ссылками — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Правки)
(Правки)
Строка 1: Строка 1:
 +
==Базовые определения==
 
{{Определение
 
{{Определение
|id=maindef
+
|id=groupdef
|definition='''Регулярные выражения с обратными ссылками''' (англ. ''regex with backreferences'') {{---}} одна из разновидностей регулярных выражений, дающая возможность использовать в них слова, принадлежащие некоторой группе.
+
|definition='''Группа''' (англ. ''capture group'') {{---}} часть [[Регулярные языки: два определения и их эквивалентность|регулярного выражения]]. Группа заключается в круглые скобки.
 
}}
 
}}
<tex>(aba)c\backslash 1</tex> {{---}} пример такого регулярного выражения.
 
  
Выражение, заключённое в скобки, называется ''группой'' (англ. ''capture group''). Скобки захватывают текст, сопоставленный регулярным выражением внутри нумерованной группы, который может быть повторно использован с помощью обратной ссылки с указанием номера группы.
+
Каждой группе соответствует порядковый номер. Нумерация идёт слева направо: номеру группы соответствует порядковый номер открывающей круглой скобки этой группы в тексте регулярного выражения.
  
«<tex>\backslash</tex>» – символ обратной ссылки (англ. ''backreference''), который действует на первую группу. Обратная ссылка <tex>\backslash 1</tex> показывает, что после группы <tex>1</tex> {{---}} <tex>(aba)</tex> {{---}} и символа <tex>c</tex> должен быть описан тот же текст, что содержится в ней.
+
Пример: <tex>(ab(cd))(ef).</tex> Группа №1 {{---}} <tex>(ab(cd)),\,</tex> группа №2 {{---}} <tex>(cd),\,</tex> группа №3 {{---}} <tex>(ef)</tex>
  
Порядок нумерации групп: сначала внешняя, потом вложенные (в порядке [[Обход в глубину, цвета вершин|обхода в глубину]]).
+
{{Определение
==Примеры==
+
|id=referencedef
* Выразим язык тандемных повторов над алфавитом <tex>\Sigma=\{0,1\},</tex> используя механизм обратных ссылок:
+
|definition='''Обратная ссылка''' (англ. ''backreference'') {{---}} механизм повторного использования групп или [[Основные определения, связанные со строками|слов]] группы.
 +
}}
  
:<tex>L=((0|1)^∗)\backslash 1</tex>
+
Для повторного использования '''слова''' группы используется обозначение <tex>\backslash n,\,</tex> где <tex>n</tex> {{---}} номер группы.
  
:Данный язык не является [[Регулярные языки: два определения и их эквивалентность|регулярным]], однако его можно представить с помощью регулярных выражений с использованием обратных ссылок.
+
Пример использования: <tex>(a^*)\backslash 1.\,</tex> Данное регулярное выражение будет допускать только слова, в которых количество букв <tex>a</tex> чётно.
* Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины <tex>n=2\cdot m\,</tex> или <tex>\,n=2\cdot m+1</tex>:
 
# для чётного <tex>n</tex>: <tex>\;(.)(.)(.)...(.)\backslash m...\backslash 3\backslash 2\backslash 1;</tex>
 
# для нечётного <tex>n</tex>: <tex>\;(.)(.)(.)...(.).\backslash m...\backslash 3\backslash 2\backslash 1,\;</tex>
 
  
:где «<tex>.</tex>» – любой одиночный символ.
+
Для повторного использования '''регулярного выражения''' группы используется обозначение <tex>(?n),\,</tex> где <tex>n</tex> {{---}} номер группы. Использование круглых скобок обусловленно тем, что <tex>?</tex> как управляющий символ уже используется.
  
* Запишем выражение для языка <tex>L=b^kab^kab^ka</tex>. Данный язык не является ни регулярным, ни контекстно-свободным (по [[Лемма о разрастании для КС-грамматик|лемме о разрастании]]), но также легко представим с помощью обратных ссылок:
 
  
:<tex>L=(b\{b\}^*a)\backslash 1\backslash 1</tex>.
+
Обратите внимание, что символы круглых скобок и обратной косой являются управляющими. Чтобы использовать их непосредственно как часть слова, их нужно [https://ru.wikipedia.org/wiki/Экранирование_символов экранировать].  
  
:Группа <tex>1</tex> {{---}} <tex>(b\{b\}^∗a)</tex> {{---}} представляет из себя регулярное выражение для языка <tex>L=b^ka,k>0\,</tex>, последующие за ней обратные ссылки используются для многократного использования ''текста'' группы. Поэтому после «<tex>b^ka</tex>» обязан присутствовать текст «<tex>b^kab^ka</tex>».
+
Пример экранирования (в данном случае в качестве символа экранирования используется символ обратной косой черты): <tex>\backslash 1</tex> {{---}} обратная ссылка на первую группу, <tex>\backslash\backslash 1</tex> {{---}} слово, состоящее из символа обратной косой черты и единицы.
 
 
* Язык <tex>L=a^nb^n,\,n>0\,</tex> можно представить при помощи обратных ссылок:
 
 
 
:<tex>L=(a(?1)?b),</tex>
 
 
 
:где «<tex>?1</tex>» – ссылка, осуществляющая рекурсивный вызов первой группы. Следущий за ссылкой знак вопроса обозначает использование группы <tex>0</tex> или <tex>1</tex> раз, то есть осуществление рекурсивного вызова или его окончание.
 
 
 
:<tex>?1</tex> ссылается на первую группу {{---}} <tex>(a(?1)?b)</tex>, что равносильно рекурсивной зависимости:       
 
::::<tex>(a(?1)?b)=</tex>
 
:::<tex>=(a(a(?1)?b)?b)=</tex>
 
::<tex>=(a(a(a(?1)?b)?b)?b)=</tex>
 
:<tex>=(a(a(a(a(?1)?b)?b)?b)?b)=\cdots</tex>
 
 
 
:Очевидно, что все слова из языка <tex>L</tex> удовлетворяют данному регулярному выражению.
 
  
 +
{{Определение
 +
|id=maindef
 +
|definition='''Регулярные выражения с обратными ссылками''' (англ. ''regex with backreferences'') {{---}} регулярные выражения, использующие механизм обратных ссылок.
 +
}}
 +
==Примеры==
 +
# Регулярное выражение <tex>(aba?)c(?1)\,</tex> породит язык <tex>L=\{abcab,abacab,abcaba,abacaba\}.</tex>
 +
# Выразим язык тандемных повторов над алфавитом <tex>\Sigma=\{0,1\},</tex> используя механизм обратных ссылок:
 +
#: <tex>L=((0|1)^∗)\backslash 1.</tex>
 +
#: Данный язык не является [[Регулярные языки: два определения и их эквивалентность|регулярным]], однако его можно представить с помощью регулярных выражений с использованием обратных ссылок.
 +
# Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины <tex>n=2\cdot m\,</tex> или <tex>\,n=2\cdot m+1</tex>:
 +
#* для чётного <tex>n</tex>: <tex>\;(a_1)(a_2)(a_3)\dotsc(a_m)\backslash m\dotsc\backslash 3\backslash 2\backslash 1;</tex>
 +
#* для нечётного <tex>n</tex>: <tex>\;(a_1)(a_2)(a_3)\dotsc(a_m)a_{m+1}\backslash m\dotsc\backslash 3\backslash 2\backslash 1,\;</tex>
 +
#: где <tex>a_i</tex> – любой одиночный символ.
 +
# Запишем выражение для языка <tex>L=b^kab^kab^ka,\,k>0.\,</tex> Данный язык не является ни регулярным, ни контекстно-свободным (по [[Лемма о разрастании для КС-грамматик|лемме о разрастании]]), то есть является [[Иерархия Хомского формальных грамматик|контекстно-зависимым]], но также легко представим с помощью обратных ссылок:
 +
#: <tex>L=(bb^*a)\backslash 1\backslash 1</tex>.
 +
# Язык <tex>L=a^nb^n,\,n>0\,</tex> можно представить при помощи обратных ссылок:
 +
#: <tex>L=(a(?1)?b).</tex>
 +
#: Следущий за ссылкой <tex>(?1)</tex> знак вопроса обозначает использование группы <tex>0</tex> или <tex>1</tex> раз, то есть осуществление рекурсивного вызова или его окончание.
 +
#: <tex>?1</tex> ссылается на первую группу {{---}} <tex>(a(?1)?b)</tex>, что равносильно рекурсивной зависимости:       
 +
#:::: <tex>(a(?1)?b)=</tex>
 +
#::: <tex>=(a(a(?1)?b)?b)=</tex>
 +
#:: <tex>=(a(a(a(?1)?b)?b)?b)=</tex>
 +
#: <tex>=(a(a(a(a(?1)?b)?b)?b)?b)=\dotsc</tex>
 +
#: Очевидно, что все слова из языка <tex>L</tex> удовлетворяют данному регулярному выражению.
 
==Теорема о КС-языках==
 
==Теорема о КС-языках==
 
{{Теорема
 
{{Теорема
Строка 47: Строка 54:
 
|statement=С помощью механизма обратных ссылок можно представить любой [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора|контекстно-свободный язык]].
 
|statement=С помощью механизма обратных ссылок можно представить любой [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора|контекстно-свободный язык]].
 
|proof=
 
|proof=
Любую контекстно-свободную грамматику можно привести к [[Нормальная форма Хомского|нормальной форме Хомского]], следовательно, достаточно доказать, что грамматику, заданную в нормальной форме, можно преобразовать в регулярное выражение с обратными ссылками. Рассмотрим правила, которые могут содержаться в такой грамматике:
+
Любую контекстно-свободную грамматику можно привести к [[Нормальная форма Хомского|нормальной форме Хомского]], следовательно, достаточно доказать, что грамматику, заданную в такой форме, можно преобразовать в регулярное выражение с обратными ссылками. Рассмотрим правила, которые могут содержаться в такой грамматике:
  
<tex>A\rightarrow BC</tex>
+
<tex>A\rightarrow BC\\A\rightarrow a\\S\rightarrow\varepsilon</tex>
  
<tex>A\rightarrow a</tex>
+
Представим каждое из них в виде регулярного выражения с обратными ссылками.
 
 
<tex>S\rightarrow\varepsilon</tex>
 
 
 
Представим каждое из них в виде регулярного выражения с обратными ссылками.  
 
  
 
Используя ссылки на регулярные выражения, соответствующие нетерминалам <tex>B</tex> и <tex>C</tex>, можно представить первое правило:
 
Используя ссылки на регулярные выражения, соответствующие нетерминалам <tex>B</tex> и <tex>C</tex>, можно представить первое правило:
Строка 63: Строка 66:
 
Второе и третье правила не требуют использования обратных ссылок:
 
Второе и третье правила не требуют использования обратных ссылок:
  
<tex>A\rightarrow a\leftrightarrow A=a;</tex>
+
<tex>A\rightarrow a\leftrightarrow A=a;\\S\rightarrow\varepsilon\leftrightarrow S=\varepsilon.</tex>
  
<tex>S\rightarrow\varepsilon\leftrightarrow S=\varepsilon.</tex>
+
Если какому-то нетерминалу <tex>A</tex> соответствуют несколько регулярных выражений <tex>r_1, r_2, \dotsc, r_n</tex>, заменить их на одно: <tex>A=((r_1)|(r_2)|\dotsc|(r_n))\,</tex> (очевидно, что оно также будет соответствовать этому нетерминалу).
  
Таким образом, регулярные выражения с обратными ссылками имеют бо́льшую мощность по сравнению с обычными. С их помощью реализуются как регулярные языки, так и контекстно-свободные грамматики, а также некоторые [[Иерархия Хомского формальных грамматик|контекстно-зависимые]].
+
Регулярное выражение для <tex>S</tex> будет искомым.
 
}}
 
}}
 +
 +
Регулярные выражения с обратными ссылками имеют бо́льшую мощность по сравнению с обычными. С их помощью реализуются как регулярные языки, так и контекстно-свободные грамматики, а также некоторые контекстно-зависимые (см. пример 4).
  
 
===Примеры преобразования===
 
===Примеры преобразования===
Строка 75: Строка 80:
 
<tex>S\rightarrow A\\A\rightarrow\varepsilon\\A\rightarrow BA\\B\rightarrow b\\B\rightarrow c</tex>
 
<tex>S\rightarrow A\\A\rightarrow\varepsilon\\A\rightarrow BA\\B\rightarrow b\\B\rightarrow c</tex>
  
Очевидно, что эквивалентным будет выражение <tex>(((b\,|\,c)\,(?1)?)?).</tex>
+
Эквивалентным будет выражение <tex>(((b\,|\,c)\,(?1)?)?).</tex>
  
 
Другой пример:
 
Другой пример:

Версия 22:18, 27 мая 2018

Базовые определения

Определение:
Группа (англ. capture group) — часть регулярного выражения. Группа заключается в круглые скобки.


Каждой группе соответствует порядковый номер. Нумерация идёт слева направо: номеру группы соответствует порядковый номер открывающей круглой скобки этой группы в тексте регулярного выражения.

Пример: [math](ab(cd))(ef).[/math] Группа №1 — [math](ab(cd)),\,[/math] группа №2 — [math](cd),\,[/math] группа №3 — [math](ef)[/math]


Определение:
Обратная ссылка (англ. backreference) — механизм повторного использования групп или слов группы.


Для повторного использования слова группы используется обозначение [math]\backslash n,\,[/math] где [math]n[/math] — номер группы.

Пример использования: [math](a^*)\backslash 1.\,[/math] Данное регулярное выражение будет допускать только слова, в которых количество букв [math]a[/math] чётно.

Для повторного использования регулярного выражения группы используется обозначение [math](?n),\,[/math] где [math]n[/math] — номер группы. Использование круглых скобок обусловленно тем, что [math]?[/math] как управляющий символ уже используется.


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

Пример экранирования (в данном случае в качестве символа экранирования используется символ обратной косой черты): [math]\backslash 1[/math] — обратная ссылка на первую группу, [math]\backslash\backslash 1[/math] — слово, состоящее из символа обратной косой черты и единицы.


Определение:
Регулярные выражения с обратными ссылками (англ. regex with backreferences) — регулярные выражения, использующие механизм обратных ссылок.

Примеры

  1. Регулярное выражение [math](aba?)c(?1)\,[/math] породит язык [math]L=\{abcab,abacab,abcaba,abacaba\}.[/math]
  2. Выразим язык тандемных повторов над алфавитом [math]\Sigma=\{0,1\},[/math] используя механизм обратных ссылок:
    [math]L=((0|1)^∗)\backslash 1.[/math]
    Данный язык не является регулярным, однако его можно представить с помощью регулярных выражений с использованием обратных ссылок.
  3. Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины [math]n=2\cdot m\,[/math] или [math]\,n=2\cdot m+1[/math]:
    • для чётного [math]n[/math]: [math]\;(a_1)(a_2)(a_3)\dotsc(a_m)\backslash m\dotsc\backslash 3\backslash 2\backslash 1;[/math]
    • для нечётного [math]n[/math]: [math]\;(a_1)(a_2)(a_3)\dotsc(a_m)a_{m+1}\backslash m\dotsc\backslash 3\backslash 2\backslash 1,\;[/math]
    где [math]a_i[/math] – любой одиночный символ.
  4. Запишем выражение для языка [math]L=b^kab^kab^ka,\,k\gt 0.\,[/math] Данный язык не является ни регулярным, ни контекстно-свободным (по лемме о разрастании), то есть является контекстно-зависимым, но также легко представим с помощью обратных ссылок:
    [math]L=(bb^*a)\backslash 1\backslash 1[/math].
  5. Язык [math]L=a^nb^n,\,n\gt 0\,[/math] можно представить при помощи обратных ссылок:
    [math]L=(a(?1)?b).[/math]
    Следущий за ссылкой [math](?1)[/math] знак вопроса обозначает использование группы [math]0[/math] или [math]1[/math] раз, то есть осуществление рекурсивного вызова или его окончание.
    [math]?1[/math] ссылается на первую группу — [math](a(?1)?b)[/math], что равносильно рекурсивной зависимости:
    [math](a(?1)?b)=[/math]
    [math]=(a(a(?1)?b)?b)=[/math]
    [math]=(a(a(a(?1)?b)?b)?b)=[/math]
    [math]=(a(a(a(a(?1)?b)?b)?b)?b)=\dotsc[/math]
    Очевидно, что все слова из языка [math]L[/math] удовлетворяют данному регулярному выражению.

Теорема о КС-языках

Теорема:
С помощью механизма обратных ссылок можно представить любой контекстно-свободный язык.
Доказательство:
[math]\triangleright[/math]

Любую контекстно-свободную грамматику можно привести к нормальной форме Хомского, следовательно, достаточно доказать, что грамматику, заданную в такой форме, можно преобразовать в регулярное выражение с обратными ссылками. Рассмотрим правила, которые могут содержаться в такой грамматике:

[math]A\rightarrow BC\\A\rightarrow a\\S\rightarrow\varepsilon[/math]

Представим каждое из них в виде регулярного выражения с обратными ссылками.

Используя ссылки на регулярные выражения, соответствующие нетерминалам [math]B[/math] и [math]C[/math], можно представить первое правило:

[math]A\rightarrow BC\leftrightarrow A=((?1)\,(?2)),\,[/math] где [math]1[/math] и [math]2[/math] соответствуют нетерминалам [math]B[/math] и [math]C[/math];

Второе и третье правила не требуют использования обратных ссылок:

[math]A\rightarrow a\leftrightarrow A=a;\\S\rightarrow\varepsilon\leftrightarrow S=\varepsilon.[/math]

Если какому-то нетерминалу [math]A[/math] соответствуют несколько регулярных выражений [math]r_1, r_2, \dotsc, r_n[/math], заменить их на одно: [math]A=((r_1)|(r_2)|\dotsc|(r_n))\,[/math] (очевидно, что оно также будет соответствовать этому нетерминалу).

Регулярное выражение для [math]S[/math] будет искомым.
[math]\triangleleft[/math]

Регулярные выражения с обратными ссылками имеют бо́льшую мощность по сравнению с обычными. С их помощью реализуются как регулярные языки, так и контекстно-свободные грамматики, а также некоторые контекстно-зависимые (см. пример 4).

Примеры преобразования

Рассмотрим следующую КС-грамматику:

[math]S\rightarrow A\\A\rightarrow\varepsilon\\A\rightarrow BA\\B\rightarrow b\\B\rightarrow c[/math]

Эквивалентным будет выражение [math](((b\,|\,c)\,(?1)?)?).[/math]

Другой пример:

[math]S\rightarrow AB\\S\rightarrow\varepsilon\\A\rightarrow SS\\B\rightarrow CD\\C\rightarrow c\\D\rightarrow d[/math]

Регулярное выражение для этой грамматики будет выглядеть так: [math]((?1?1cd)\,|\,\varepsilon).[/math]

Применение

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

Регулярные выражения в языках программирования зачастую поддерживают обратные ссылки. На практике их можно использовать, например, для парсинга [math]html[/math]-выражений (поиск подстрок, содержащихся в определённых тегах).

См. также

Источники информации