В PCRE2 или любом другом механизме регулярных выражений, поддерживающем прямые обратные ссылки, можно изменить группу захвата, которая соответствовала на предыдущей итерации цикла, на не участвующую группу захвата (также известную как неустановленная группа захвата или не захваченная группа ), в результате чего условные выражения, проверяющие соответствие этой группы их условию «ложь», а не условию «истина»?
Например, возьмем следующее регулярное выражение PCRE:
^(?:(z)?(?(1)aa|a)){2}
Когда передается строка zaazaa
, она соответствует всей строке, как требуется. Но когда кормят zaaaa
, я бы хотел, чтобы он совпадал с zaaa
; вместо этого он соответствует zaaaa
, всей строке. (Это только для иллюстрации. Конечно, этот пример может быть обработан с помощью ^(?:zaa|a){2}
, но это не относится к делу. Практическое использование стирания группы захвата обычно происходит в циклах, которые чаще всего выполняют намного больше двух итераций.)
Альтернативный способ сделать это, который также не работает должным образом:
^(?:(?:z()|())(?:\1aa|\2a)){2}
Обратите внимание, что оба они работают по желанию, когда цикл "развернут", потому что им больше не нужно стирать уже сделанный захват:
^(?:(z)?(?(1)aa|a))(?:(z)?(?(2)aa|a))
^(?:(?:z()|())(?:\1aa|\2a))(?:(?:z()|())(?:\3aa|\4a))
Таким образом, вместо того, чтобы использовать простейшую условную форму, нужно использовать более сложную форму, которая работает только в этом примере, потому что "истинное" совпадение z
не пусто:
^(?:(z?)(?(?!.*$\1)aa|a)){2}
Или просто используя эмулируемое условие:
^(?:(z?)(?:(?!.*$\1)aa|(?=.*$\1)a)){2}
Я просмотрел всю документацию, которую смог найти, и, похоже, даже нет упоминания или явного описания этого поведения (то, что перехваты, сделанные в цикле, сохраняются в течение итераций этого цикла, даже когда они не могут быть перехвачены ).
Это отличается от того, что я интуитивно ожидал. Я бы реализовал это так: оценка группы захвата с 0 повторениями приведет к ее удалению / отмене (поэтому это может произойти с любой группой захвата с квантификатором *
, ?
или {0,N}
), но пропуская ее из-за наличие параллельной альтернативы в той же группе, в которой он получил перехват во время предыдущей итерации, не удалит его. Таким образом, это регулярное выражение будет по-прежнему соответствовать словам, если они содержат хотя бы один из каждого гласного :
\b(?:a()|e()|i()|o()|u()|\w)++\1\2\3\4\5\b
Но пропуск группы захвата из-за ее нахождения в неоцененной альтернативе группы, которая оценивается с ненулевыми повторениями, вложенной в группу, в которой группа захвата приняла значение во время предыдущей итерации будет стереть / сбросить его, чтобы это регулярное выражение могло захватывать или стирать группу \1
на каждой итерации цикла:
^(?:(?=a|(b)).(?(1)_))*$
и будет соответствовать строкам, таким как aaab_ab_b_aaaab_ab_aab_b_b_aaa
. Тем не менее, обратные ссылки на самом деле реализованы в существующих движках, это соответствует aaaaab_a_b_a_a_b_b_a_b_b_b_
.
Я хотел бы знать ответ на этот вопрос не только потому, что он был бы полезен при построении регулярных выражений, но и потому, что я написал свой собственный механизм регулярных выражений , в настоящее время совместимый с ECMAScript с некоторыми дополнительными расширениями (включая молекулярный взгляд (?*)
, то есть неатомный взгляд, который, насколько я знаю, не имеет никакой другой движок), и я хотел бы продолжить добавление функций из других движков, включая прямые / вложенные обратные ссылки. Я не только хочу, чтобы моя реализация обратных обратных ссылок была совместима с существующими реализациями, но если не способ удаления групп захвата в других движках, я, вероятно, создам способ сделать это в моем движок, который не конфликтует с другими существующими функциями регулярных выражений.
Чтобы быть ясным: ответ, утверждающий, что это невозможно в каких-либо основных двигателях, будет приемлемым, если он подкреплен адекватными исследованиями и / или цитированием источников. Ответ о том, что это возможно , было бы гораздо проще сформулировать, поскольку для этого потребовался бы только один пример.
Некоторая информация о том, что такое не участвующая группа захвата:
http://blog.stevenlevithan.com/archives/npcg-javascript - это статья, которая первоначально познакомила меня с идеей.
https://www.regular -expressions.info / backref2.html - первый раздел этой страницы дает краткое объяснение.
В регулярных выражениях ECMAScript / Javascript обратные ссылки на NPCG всегда совпадают (сопоставление нулевой длины). Практически во всех других разновидностях регулярных выражений они ничего не соответствуют.