Авторитетным справочником по прагматическим вопросам, стоящим за внедрением движков регулярных выражений, является серия из трех сообщений в блоге Расса Кокса . Как описано здесь, поскольку обратные ссылки делают ваш язык нерегулярным, они реализуются с использованием обратного отслеживания .
Взгляд в прошлое и взгляд назад, как и многие функции механизмов сопоставления с регулярным выражением, не совсем вписываются в парадигму принятия решения о том, является ли строка членом языка или нет. Вместо регулярных выражений мы обычно ищем подстроки в большей строке. «Соответствия» - это подстроки, которые являются членами языка, а возвращаемое значение - это начальная и конечная точки подстроки в большей строке.
Точка предвзятости и взглядов задних сторон заключается не столько в том, чтобы представить возможность сопоставления с нерегулярными языками, но скорее в том, чтобы настроить, где механизм сообщает о начальной и конечной точках сопоставленной подстроки.
Я полагаюсь на описание на http://www.regular-expressions.info/lookaround.html . Механизмы регулярных выражений, которые поддерживают эту функцию (Perl, TCL, Python, Ruby, ...), похоже, все основаны на возврате (т. Е. Они поддерживают гораздо больший набор языков, чем обычные языки). Похоже, они реализуют эту функцию как относительно «простое» расширение обратного отслеживания, вместо того, чтобы пытаться создать реальные конечные автоматы для выполнения задачи.
Позитивный Lookahead
Синтаксис для положительного взгляда - (?=
регулярное выражение)
. Так, например, q(?=u)
совпадает q
только в том случае, если за ним следует u
, но не совпадает с u
. Я предполагаю, что они реализуют это с изменением на откат назад. Создайте FSM для выражения перед положительным прогнозом. Когда это совпадение, запомните, где оно закончилось, и запустите новый FSM, представляющий выражение в положительном прогнозе. Если это соответствует, то у вас есть «совпадение», но совпадение «заканчивается» как раз перед позицией, где началось положительное совпадение.
Единственная часть этого, которая была бы сложной без обратного отслеживания, заключается в том, что вам нужно запомнить точку на входе, с которой начинается упреждение, и переместить ленту ввода обратно в это положение после того, как вы закончите с совпадением.
Негативный Lookahead
Синтаксис для отрицательного просмотра - (?!
регулярное выражение)
. Так, например, q(?!u)
совпадения, q
только если за ним не следует u
. Это может быть либо q
другой символ, либо символ «за» q
в самом конце строки. Я полагаю, что это реализуется путем создания NFA для выражения lookahead, которое выполняется только в том случае, если NFA не соответствует следующей строке.
Если вы хотите сделать это, не полагаясь на возврат, вы можете отрицать NFA для выражения прогнозирования, а затем относиться к нему так же, как к позитивному прогнозированию.
Позитивный взгляд сзади
(?<=
)
(?=q)u
u
q
q
nnn
Вы могли бы реализовать это без возврата назад, взяв пересечение «string, заканчивающегося регулярным выражением », с любой частью регулярного выражения, которая предшествует оператору lookbehind. Это будет сложно, потому что регулярное выражение lookbehind, возможно, должно оглянуться назад, чем текущее начало ввода.
Отрицательный взгляд сзади
Синтаксис для отрицательного взгляда сзади - (?<!
регулярное выражение)
. Так, например, (?<!q)u
совпадает u
, но только если ему не предшествует q
. Так что это будет соответствовать u
in umbrella
и u
in doubt
, но не u
in quick
. Опять же, это, кажется, делается путем вычисления длины регулярного выражения , резервного копирования такого количества символов, проверки на соответствие регулярному выражению , но теперь провал всего совпадения, если совпадает просмотр назад.
Вы могли бы реализовать это без отступления, приняв отрицание регулярного выражения, а затем сделав то же самое, что и для позитивного взгляда.