Регулярные выражения с обратными ссылками — различия между версиями
Daviondk (обсуждение | вклад) (Правки) |
м (rollbackEdits.php mass rollback) |
||
(не показано 5 промежуточных версий 2 участников) | |||
Строка 2: | Строка 2: | ||
{{Определение | {{Определение | ||
|id=groupdef | |id=groupdef | ||
− | |definition='''Группа''' (англ. ''capture group'') {{---}} часть [[Регулярные языки: два определения и их эквивалентность|регулярного выражения]]. | + | |definition='''Группа''' (англ. ''capture group'') {{---}} часть [[Регулярные языки: два определения и их эквивалентность|регулярного выражения]]. Общепринятое условное обозначение группы {{---}} круглые скобки. |
}} | }} | ||
− | Каждой группе соответствует порядковый номер. Нумерация идёт слева направо: номеру группы соответствует порядковый номер открывающей круглой скобки этой группы в тексте регулярного выражения. | + | Пример: <tex>aba(ca)ba.\,</tex> В данном регулярном выражении представлена одна группа {{---}} <tex>(ca).</tex> |
+ | |||
+ | Каждой группе соответствует порядковый номер. Нумерация идёт слева направо: номеру группы соответствует порядковый номер открывающей круглой скобки этой группы в тексте регулярного выражения (исключая случаи, когда скобки являются частью синтаксической конструкции). | ||
Пример: <tex>(ab(cd))(ef).</tex> Группа <tex>№1</tex> {{---}} <tex>(ab(cd)),\,</tex> группа <tex>№2</tex> {{---}} <tex>(cd),\,</tex> группа <tex>№3</tex> {{---}} <tex>(ef)</tex> | Пример: <tex>(ab(cd))(ef).</tex> Группа <tex>№1</tex> {{---}} <tex>(ab(cd)),\,</tex> группа <tex>№2</tex> {{---}} <tex>(cd),\,</tex> группа <tex>№3</tex> {{---}} <tex>(ef)</tex> | ||
Строка 16: | Строка 18: | ||
Для повторного использования '''слова''' группы используется обозначение <tex>\backslash n,\,</tex> где <tex>n</tex> {{---}} номер группы. | Для повторного использования '''слова''' группы используется обозначение <tex>\backslash n,\,</tex> где <tex>n</tex> {{---}} номер группы. | ||
− | Пример использования: <tex>( | + | Пример использования: <tex>((1\,|\,0)^*)\backslash 1.\,</tex> Данное регулярное выражение будет задавать язык тандемных повторов. Несмотря на то, что он не является [[Регулярные языки: два определения и их эквивалентность|регулярным]], его можно представить с помощью механизма обратных ссылок. |
− | Для повторного использования '''регулярного выражения''' группы используется обозначение <tex>(?n),\,</tex> где <tex>n</tex> {{---}} номер группы. Использование круглых скобок обусловленно тем, что <tex>?</tex> как управляющий символ уже используется. | + | Для повторного использования '''регулярного выражения''' группы используется обозначение <tex>(?n),\,</tex> где <tex>n</tex> {{---}} номер группы. Использование круглых скобок обусловленно тем, что <tex>?,</tex> как управляющий символ, уже используется. В данном случае круглые скобки следует воспринимать как общепринятое '''условное обозначение''' обратной ссылки; запись <tex>(?n)</tex> не задаёт группу. Например, в выражении <tex>(aba)(?1)(caba)(?2)\;</tex> ссылке <tex>(?2)</tex> будет соответствовать <tex>(caba),\,</tex> а не <tex>(?1).</tex> |
− | Обратите внимание, что символы круглых скобок и обратной косой являются управляющими. Чтобы использовать их непосредственно как часть слова, их нужно [https://ru.wikipedia.org/wiki/Экранирование_символов экранировать]. | + | Обратите внимание, что символы круглых скобок и обратной косой черты являются управляющими. Чтобы использовать их непосредственно как часть слова, их нужно [https://ru.wikipedia.org/wiki/Экранирование_символов экранировать]. |
Пример экранирования (в данном случае в качестве символа экранирования используется символ обратной косой черты): <tex>\backslash 1</tex> {{---}} обратная ссылка на первую группу, <tex>\backslash\backslash 1</tex> {{---}} слово, состоящее из символа обратной косой черты и единицы. | Пример экранирования (в данном случае в качестве символа экранирования используется символ обратной косой черты): <tex>\backslash 1</tex> {{---}} обратная ссылка на первую группу, <tex>\backslash\backslash 1</tex> {{---}} слово, состоящее из символа обратной косой черты и единицы. | ||
Строка 30: | Строка 32: | ||
}} | }} | ||
==Примеры== | ==Примеры== | ||
− | # Регулярное выражение <tex>(aba?)c(?1)\,</tex> породит язык <tex>L=\{abcab,abacab,abcaba,abacaba\}.</tex> | + | # Регулярное выражение <tex>(aba?)c(?1)\,</tex> породит язык <tex>L=\{abcab,abacab,abcaba,abacaba\}.\;</tex> Для сравнения, запишем эквивалентное регулярное выражение без использования механизма обратных ссылок: <tex>(aba?)c(aba?).</tex> |
− | + | # <tex>(a^*)\backslash 1.\,</tex> Данное регулярное выражение будет допускать только слова, в которых количество букв <tex>a</tex> чётно. | |
− | # | + | # Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины <tex>n=2\cdot m\,</tex> или <tex>\,n=2\cdot m+1</tex> над алфавитом <tex>\Sigma=\{0,1\}</tex>: |
− | + | #* для чётного <tex>n</tex>: <tex>\;\underbrace{(0\,|\,1)(0\,|\,1)(0\,|\,1)\dotsc(0\,|\,1)}_{m}\,\backslash m\dotsc\backslash 3\backslash 2\backslash 1;</tex> | |
− | # Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины <tex>n=2\cdot m\,</tex> или <tex>\,n=2\cdot m+1</tex>: | + | #* для нечётного <tex>n</tex>: <tex>\;\underbrace{(0\,|\,1)(0\,|\,1)(0\,|\,1)\dotsc(0\,|\,1)}_{m}\,(0\,|\,1)\backslash m\dotsc\backslash 3\backslash 2\backslash 1,\;</tex> |
− | #* для чётного <tex>n</tex>: <tex>\;( | ||
− | #* для нечётного <tex>n</tex>: <tex>\;( | ||
− | |||
# Запишем выражение для языка <tex>L=b^kab^kab^ka,\,k>0.\,</tex> Данный язык не является ни регулярным, ни контекстно-свободным (по [[Лемма о разрастании для КС-грамматик|лемме о разрастании]]), то есть является [[Иерархия Хомского формальных грамматик|контекстно-зависимым]], но также легко представим с помощью обратных ссылок: | # Запишем выражение для языка <tex>L=b^kab^kab^ka,\,k>0.\,</tex> Данный язык не является ни регулярным, ни контекстно-свободным (по [[Лемма о разрастании для КС-грамматик|лемме о разрастании]]), то есть является [[Иерархия Хомского формальных грамматик|контекстно-зависимым]], но также легко представим с помощью обратных ссылок: | ||
#: <tex>L=(bb^*a)\backslash 1\backslash 1</tex>. | #: <tex>L=(bb^*a)\backslash 1\backslash 1</tex>. | ||
Строка 43: | Строка 42: | ||
#: <tex>L=(a(?1)?b).</tex> | #: <tex>L=(a(?1)?b).</tex> | ||
#: Следущий за ссылкой <tex>(?1)</tex> знак вопроса обозначает использование группы <tex>0</tex> или <tex>1</tex> раз, то есть осуществление рекурсивного вызова или его окончание. | #: Следущий за ссылкой <tex>(?1)</tex> знак вопроса обозначает использование группы <tex>0</tex> или <tex>1</tex> раз, то есть осуществление рекурсивного вызова или его окончание. | ||
− | #: <tex>?1</tex> ссылается на первую группу {{---}} <tex>(a(?1)?b)</tex>, что равносильно рекурсивной зависимости: | + | #: <tex>(?1)</tex> ссылается на первую группу {{---}} <tex>(a(?1)?b)</tex>, что равносильно рекурсивной зависимости: |
#:::: <tex>(a(?1)?b)=</tex> | #:::: <tex>(a(?1)?b)=</tex> | ||
#::: <tex>=(a(a(?1)?b)?b)=</tex> | #::: <tex>=(a(a(?1)?b)?b)=</tex> | ||
Строка 62: | Строка 61: | ||
Используя ссылки на регулярные выражения, соответствующие нетерминалам <tex>B</tex> и <tex>C</tex>, можно представить первое правило: | Используя ссылки на регулярные выражения, соответствующие нетерминалам <tex>B</tex> и <tex>C</tex>, можно представить первое правило: | ||
− | <tex>A\rightarrow BC\leftrightarrow A | + | <tex>A\rightarrow BC\leftrightarrow A\rightarrow ((?n_B)\,(?n_C)),\,</tex> где <tex>(?n_B)</tex> и <tex>(?n_C)</tex> соответствуют нетерминалам <tex>B</tex> и <tex>C</tex>; |
Второе и третье правила не требуют использования обратных ссылок: | Второе и третье правила не требуют использования обратных ссылок: | ||
− | <tex>A\rightarrow a\leftrightarrow A | + | <tex>A\rightarrow a\leftrightarrow A\rightarrow (a);\\S\rightarrow\varepsilon\leftrightarrow S\rightarrow ().</tex> |
− | Если какому-то нетерминалу <tex>A</tex> соответствуют несколько регулярных выражений <tex>r_1, r_2, \dotsc, r_n</tex>, заменить их на одно: <tex>A= | + | Если какому-то нетерминалу <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> будет искомым. | + | Регулярное выражение для данной КС-грамматики соответствует нетерминалу <tex>S,\,</tex> однако в нём могут встречаться ссылки на внешние {{---}} отличные от <tex>S</tex> {{---}} группы. Будем обрабатывать такие ссылки, используя метод [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора|левостороннего вывода]]. При обработке очередной ссылки: |
+ | # если эта ссылка встречается впервые, вместо неё подставим соответствующее регулярное выражение и запомним номер его группы в текущем регулярном выражении; | ||
+ | # иначе вместо этой ссылки подставим ссылку на соответствующую группу в текущем регулярном выражении. | ||
+ | |||
+ | |||
+ | После соответствующих замен регулярное выражение для <tex>S</tex> будет искомым. | ||
}} | }} | ||
− | + | ===Пример преобразования=== | |
+ | Рассмотрим следующую КС-грамматику: | ||
− | === | + | <tex>S\rightarrow cA\\S\rightarrow dA\\S\rightarrow cB\\S\rightarrow eB\\A\rightarrow a\\B\rightarrow b</tex> |
− | + | ||
+ | |||
+ | # Приведём её к нормальной форме Хомского: | ||
+ | #: <tex>S\rightarrow CA\\S\rightarrow DA\\S\rightarrow CB\\S\rightarrow EB\\A\rightarrow a\\B\rightarrow b\\C\rightarrow c\\D\rightarrow d\\E\rightarrow e</tex> | ||
+ | # Каждому нетерминалу поставим в соответствие свой номер: | ||
+ | #: <tex>S\leftrightarrow 1, A\leftrightarrow 2, B\leftrightarrow 3, C\leftrightarrow 4, D\leftrightarrow 5, E\leftrightarrow 6</tex> | ||
+ | # Каждое правило представим в виде регулярного выражения с обратными ссылками: | ||
+ | #: <tex>S\rightarrow ((?4)(?2))\\S\rightarrow ((?5)(?2))\\S\rightarrow ((?4)(?3))\\S\rightarrow ((?6)(?3))\\A\rightarrow (a)\\B\rightarrow (b)\\C\rightarrow (c)\\D\rightarrow (d)\\E\rightarrow (e)</tex> | ||
+ | # Объединим регулярные выражения, соответствующие одинаковым нетерминалам: | ||
+ | #: <tex>S\rightarrow (((?4)(?2))\,|\,((?5)(?2))\,|\,((?4)(?3))\,|\,((?6)(?3)))\\A\rightarrow (a)\\B\rightarrow (b)\\C\rightarrow (c)\\D\rightarrow (d)\\E\rightarrow (e)</tex> | ||
+ | # Избавимся от внешних ссылок в регулярном выражении для <tex>S</tex>: | ||
+ | {| class="wikitable" style="display: inline-table; white-space: nowrap; text-align: center;" | ||
+ | |+Пошаговый вывод | ||
+ | ! № || Текущее регулярное выражение | ||
+ | |- | ||
+ | | 1. || <tex>(((\underline{\textbf{?4}})(\underline{?2}))\,|\,((\underline{?5})(\underline{?2}))\,|\,((\underline{?4})(\underline{?3}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 2. || <tex>(((c)(\underline{\textbf{?2}}))\,|\,((\underline{?5})(\underline{?2}))\,|\,((\underline{?4})(\underline{?3}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 3. || <tex>(((c)(a))\,|\,((\underline{\textbf{?5}})(\underline{?2}))\,|\,((\underline{?4})(\underline{?3}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 4. || <tex>(((c)(a))\,|\,((d)(\underline{\textbf{?2}}))\,|\,((\underline{?4})(\underline{?3}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 5. || <tex>(((c)(a))\,|\,((d)(?4))\,|\,((\underline{\textbf{?4}})(\underline{?3}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 6. || <tex>(((c)(a))\,|\,((d)(?4))\,|\,((?3)(\underline{\textbf{?3}}))\,|\,((\underline{?6})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 7. || <tex>(((c)(a))\,|\,((d)(?4))\,|\,((?3)(b))\,|\,((\underline{\textbf{?6}})(\underline{?3})))\,</tex> | ||
+ | |- | ||
+ | | 8. || <tex>(((c)(a))\,|\,((d)(?4))\,|\,((?3)(b))\,|\,((e)(\underline{\textbf{?3}})))\,</tex> | ||
+ | |- | ||
+ | | 9. || <tex>(((c)(a))\,|\,((d)(?4))\,|\,((?3)(b))\,|\,((e)(?8)))\,</tex> | ||
+ | |} | ||
+ | {| class="wikitable" style="display: inline-table; white-space: nowrap; text-align: center;" | ||
+ | |+№ группы в <tex>S</tex> | ||
+ | ! <tex>S</tex> || <tex>A</tex> || <tex>B</tex> || <tex>C</tex> || <tex>D</tex> || <tex>E</tex> | ||
+ | |- | ||
+ | | 1 || || || style="background: #1b5de2; color: white;" | || || | ||
+ | |- | ||
+ | | 1 || style="background: #1b5de2; color: white;" | || || <b>3</b> || || | ||
+ | |- | ||
+ | | 1 || <b>4</b> || || 3 || style="background: #1b5de2; color: white;" | || | ||
+ | |- | ||
+ | | 1 || style="background: #1b5de2; color: white;" | 4 || || 3 || <b>6</b> || | ||
+ | |- | ||
+ | | 1 || 4 || || style="background: #1b5de2; color: white;" | 3 || 6 || | ||
+ | |- | ||
+ | | 1 || 4 || style="background: #1b5de2; color: white;" | || 3 || 6 || | ||
+ | |- | ||
+ | | 1 || 4 || <b>8</b> || 3 || 6 || style="background: #1b5de2; color: white;" | | ||
+ | |- | ||
+ | | 1 || 4 || style="background: #1b5de2; color: white;" | 8 || 3 || 6 || <b>10</b> | ||
+ | |- | ||
+ | | 1 || 4 || 8 || 3 || 6 || 10 | ||
+ | |} | ||
+ | '''Напоминание''': круглые скобки в записи обратной ссылки являются синтаксической конструкцией и не задают группу. | ||
− | |||
− | + | Таким образом, регулярное выражение для данной грамматики будет выглядеть так: <tex>(((c)(a))\,|\,((d)(?4))\,|\,((?3)(b))\,|\,((e)(?8))).</tex> | |
− | + | Рассмотрим другой пример: | |
− | <tex> | + | <tex>S\rightarrow\varepsilon\\S\rightarrow (S)S\\S\rightarrow S(S)</tex> |
− | + | # Приведём её к нормальной форме Хомского: | |
− | # | + | #: <tex>S\rightarrow\varepsilon\\S\rightarrow AS\\S\rightarrow SA\\A\rightarrow OB\\B\rightarrow SC\\O\rightarrow (\\C\rightarrow\; )</tex> |
− | #: <tex>S\ | + | # Каждому нетерминалу поставим в соответствие свой номер: |
+ | #: <tex>S\leftrightarrow 1, A\leftrightarrow 2, B\leftrightarrow 3, O\leftrightarrow 4, C\leftrightarrow 5</tex> | ||
+ | # Каждое правило представим в виде регулярного выражения с обратными ссылками: | ||
+ | #: <tex>S\rightarrow ()\\S\rightarrow ((?2)(?1))\\S\rightarrow ((?1)(?2))\\A\rightarrow ((?4)(?3))\\B\rightarrow ((?1)(?5))\\O\rightarrow (\backslash (\,)\\C\rightarrow (\backslash )\,)</tex> | ||
# Объединим регулярные выражения, соответствующие одинаковым нетерминалам: | # Объединим регулярные выражения, соответствующие одинаковым нетерминалам: | ||
− | #: <tex>S\ | + | #: <tex>S\rightarrow (()\,|\,((?2)(?1))\,|\,((?1)(?2)))\\A\rightarrow ((?4)(?3))\\B\rightarrow ((?1)(?5))\\O\rightarrow (\backslash (\,)\\C\rightarrow (\backslash )\,)</tex> |
− | # | + | # Избавимся от внешних ссылок в регулярном выражении для <tex>S</tex>: |
− | + | {| class="wikitable" style="display: inline-table; white-space: nowrap; text-align: center;" | |
+ | |+Пошаговый вывод | ||
+ | ! № || Текущее регулярное выражение | ||
+ | |- | ||
+ | | 1. || <tex>(()\,|\,((\underline{\textbf{?2}})(?1))\,|\,((?1)(\underline{?2})))</tex> | ||
+ | |- | ||
+ | | 2. || <tex>(()\,|\,(((\underline{\textbf{?4}})(\underline{?3}))(?1))\,|\,((?1)(\underline{?2})))</tex> | ||
+ | |- | ||
+ | | 3. || <tex>(()\,|\,(((\backslash (\,)(\underline{\textbf{?3}}))(?1))\,|\,((?1)(\underline{?2})))</tex> | ||
+ | |- | ||
+ | | 4. || <tex>(()\,|\,(((\backslash (\,)((?1)(\underline{\textbf{?5}})))(?1))\,|\,((?1)(\underline{?2})))</tex> | ||
+ | |- | ||
+ | | 5. || <tex>(()\,|\,(((\backslash (\,)((?1)(\backslash )\,)))(?1))\,|\,((?1)(\underline{\textbf{?2}})))</tex> | ||
+ | |- | ||
+ | | 6. || <tex>(()\,|\,(((\backslash (\,)((?1)(\backslash )\,)))(?1))\,|\,((?1)(?4)))</tex> | ||
+ | |} | ||
+ | {| class="wikitable" style="display: inline-table; white-space: nowrap; text-align: center;" | ||
+ | |+№ группы в <tex>S</tex> | ||
+ | ! <tex>S</tex> || <tex>A</tex> || <tex>B</tex> || <tex>O</tex> || <tex>C</tex> | ||
+ | |- | ||
+ | | 1 || style="background: #1b5de2; color: white;" | || || || | ||
+ | |- | ||
+ | | 1 || <b>4</b> || || style="background: #1b5de2; color: white;" | || | ||
+ | |- | ||
+ | |- | ||
+ | | 1 || 4 || style="background: #1b5de2; color: white;" | || <b>5</b> || | ||
+ | |- | ||
+ | | 1 || 4 || <b>6</b> || 5 || style="background: #1b5de2; color: white;" | | ||
+ | |- | ||
+ | | 1 || style="background: #1b5de2; color: white;" | 4 || 6 || 5 || <b>7</b> | ||
+ | |- | ||
+ | | 1 || 4 || 6 || 5 || 7 | ||
+ | |} | ||
+ | |||
+ | Таким образом, регулярное выражение для данной грамматики будет выглядеть так: <tex>(()\,|\,(((\backslash (\,)((?1)(\backslash )\,)))(?1))\,|\,((?1)(?4))).</tex> | ||
− | |||
==Применение== | ==Применение== | ||
− | С помощью | + | Регулярные выражения с обратными ссылками имеют бо́льшую мощность по сравнению с обычными. С их помощью реализуются как регулярные языки, так и контекстно-свободные грамматики, а также некоторые контекстно-зависимые (например, язык тандемных повторов). |
Регулярные выражения в языках программирования зачастую поддерживают обратные ссылки. На практике их можно использовать, например, для парсинга <tex>html</tex>-выражений (поиск подстрок, содержащихся в определённых тегах). | Регулярные выражения в языках программирования зачастую поддерживают обратные ссылки. На практике их можно использовать, например, для парсинга <tex>html</tex>-выражений (поиск подстрок, содержащихся в определённых тегах). |
Текущая версия на 19:37, 4 сентября 2022
Содержание
Базовые определения
Определение: |
Группа (англ. capture group) — часть регулярного выражения. Общепринятое условное обозначение группы — круглые скобки. |
Пример: В данном регулярном выражении представлена одна группа —
Каждой группе соответствует порядковый номер. Нумерация идёт слева направо: номеру группы соответствует порядковый номер открывающей круглой скобки этой группы в тексте регулярного выражения (исключая случаи, когда скобки являются частью синтаксической конструкции).
Пример:
Группа — группа — группа —
Определение: |
Обратная ссылка (англ. backreference) — механизм повторного использования групп или слов группы. |
Для повторного использования слова группы используется обозначение где — номер группы.
Пример использования: регулярным, его можно представить с помощью механизма обратных ссылок.
Данное регулярное выражение будет задавать язык тандемных повторов. Несмотря на то, что он не являетсяДля повторного использования регулярного выражения группы используется обозначение
где — номер группы. Использование круглых скобок обусловленно тем, что как управляющий символ, уже используется. В данном случае круглые скобки следует воспринимать как общепринятое условное обозначение обратной ссылки; запись не задаёт группу. Например, в выражении ссылке будет соответствовать а не
Обратите внимание, что символы круглых скобок и обратной косой черты являются управляющими. Чтобы использовать их непосредственно как часть слова, их нужно экранировать.
Пример экранирования (в данном случае в качестве символа экранирования используется символ обратной косой черты):
— обратная ссылка на первую группу, — слово, состоящее из символа обратной косой черты и единицы.
Определение: |
Регулярные выражения с обратными ссылками (англ. regex with backreferences) — регулярные выражения, использующие механизм обратных ссылок. |
Примеры
- Регулярное выражение породит язык Для сравнения, запишем эквивалентное регулярное выражение без использования механизма обратных ссылок:
- Данное регулярное выражение будет допускать только слова, в которых количество букв чётно.
- Выведем регулярное выражение для языка, состоящего из палиндромов фиксированной длины
- для чётного :
- для нечётного :
или над алфавитом :
- Запишем выражение для языка лемме о разрастании), то есть является контекстно-зависимым, но также легко представим с помощью обратных ссылок:
- .
Данный язык не является ни регулярным, ни контекстно-свободным (по - Язык
- Следущий за ссылкой знак вопроса обозначает использование группы или раз, то есть осуществление рекурсивного вызова или его окончание.
-
- Очевидно, что все слова из языка удовлетворяют данному регулярному выражению.
можно представить при помощи обратных ссылок:
Теорема о КС-языках
Теорема: |
С помощью механизма обратных ссылок можно представить любой контекстно-свободный язык. |
Доказательство: |
Любую контекстно-свободную грамматику можно привести к нормальной форме Хомского, следовательно, достаточно доказать, что грамматику, заданную в такой форме, можно преобразовать в регулярное выражение с обратными ссылками. Рассмотрим правила, которые могут содержаться в такой грамматике:
Представим каждое из них в виде регулярного выражения с обратными ссылками. Используя ссылки на регулярные выражения, соответствующие нетерминалам и , можно представить первое правило:где и соответствуют нетерминалам и ; Второе и третье правила не требуют использования обратных ссылок:
Если какому-то нетерминалу соответствуют несколько регулярных выражений , заменить их на одно: (очевидно, что оно также будет соответствовать этому нетерминалу).Регулярное выражение для данной КС-грамматики соответствует нетерминалу левостороннего вывода. При обработке очередной ссылки: однако в нём могут встречаться ссылки на внешние — отличные от — группы. Будем обрабатывать такие ссылки, используя метод
|
Пример преобразования
Рассмотрим следующую КС-грамматику:
- Приведём её к нормальной форме Хомского:
- Каждому нетерминалу поставим в соответствие свой номер:
- Каждое правило представим в виде регулярного выражения с обратными ссылками:
- Объединим регулярные выражения, соответствующие одинаковым нетерминалам:
- Избавимся от внешних ссылок в регулярном выражении для :
№ | Текущее регулярное выражение |
---|---|
1. | |
2. | |
3. | |
4. | |
5. | |
6. | |
7. | |
8. | |
9. |
1 | |||||
1 | 3 | ||||
1 | 4 | 3 | |||
1 | 4 | 3 | 6 | ||
1 | 4 | 3 | 6 | ||
1 | 4 | 3 | 6 | ||
1 | 4 | 8 | 3 | 6 | |
1 | 4 | 8 | 3 | 6 | 10 |
1 | 4 | 8 | 3 | 6 | 10 |
Напоминание: круглые скобки в записи обратной ссылки являются синтаксической конструкцией и не задают группу.
Таким образом, регулярное выражение для данной грамматики будет выглядеть так:
Рассмотрим другой пример:
- Приведём её к нормальной форме Хомского:
- Каждому нетерминалу поставим в соответствие свой номер:
- Каждое правило представим в виде регулярного выражения с обратными ссылками:
- Объединим регулярные выражения, соответствующие одинаковым нетерминалам:
- Избавимся от внешних ссылок в регулярном выражении для :
№ | Текущее регулярное выражение |
---|---|
1. | |
2. | |
3. | |
4. | |
5. | |
6. |
1 | ||||
1 | 4 | |||
1 | 4 | 5 | ||
1 | 4 | 6 | 5 | |
1 | 4 | 6 | 5 | 7 |
1 | 4 | 6 | 5 | 7 |
Таким образом, регулярное выражение для данной грамматики будет выглядеть так:
Применение
Регулярные выражения с обратными ссылками имеют бо́льшую мощность по сравнению с обычными. С их помощью реализуются как регулярные языки, так и контекстно-свободные грамматики, а также некоторые контекстно-зависимые (например, язык тандемных повторов).
Регулярные выражения в языках программирования зачастую поддерживают обратные ссылки. На практике их можно использовать, например, для парсинга
-выражений (поиск подстрок, содержащихся в определённых тегах).См. также
- Регулярные языки: два определения и их эквивалентность
- Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора
- Нормальная форма Хомского
- Иерархия Хомского формальных грамматик