Подтвердить что ты не робот

Как (* SKIP) или (* F) работают над регулярным выражением?

Я изучаю расширенное использование регулярного выражения и заметил, что в нем много сообщений используют (*SKIP) или (*F).

Я задал вопрос, когда идея заключалась в сопоставлении строк, которые не имеют yellow, но имеет blue, только если brown существует после синего. И правильный ответ был:

.*yellow.*(*SKIP)(*F)|^.*\bblue\b(?=.*brown).*$

Я также попытался найти похожие выражения, как показано ниже, но не работал для всех случаев:

^((?!yellow).)*blue(?=.*brown).*$

Я понятия не имел об этих флагах (*SKIP)(*F), так что вопрос в том, как работает этот флаг? Что они делают? И есть ли другие флаги, подобные этим?

Спасибо.

4b9b3361

Ответ 1

Эти два контрольных глагола backtracking реализованы только в Perl, PCRE и pypi regex module.

Идея трюка (*SKIP)(*FAIL) заключается в том, чтобы потреблять символы, которых вы хотите избежать, и это не должно быть частью результата соответствия.

Классический шаблон, который использует этот трюк, выглядит следующим образом:

What_I_want_to_avoid(*SKIP)(*FAIL)|What_I_want_to_match

Механизм regex обрабатывает такую ​​строку:

  • первый токен шаблона проверяется на каждом символе слева направо (по умолчанию большую часть времени, но некоторые механизмы регулярных выражений могут быть настроены на работу справа налево,.net может сделать это, если Я хорошо помню)

  • если первый токен совпадает, тогда механизм regex проверяет следующий токен шаблона со следующими символами (после первого совпадения токенов) и т.д.

  • когда токен терпит неудачу, механизм regex получает символы, совпадающие с последним токеном, и пытается другим способом добиться успеха в шаблоне (если он тоже не работает, механизм регулярных выражений делает то же самое с предыдущий токен и т.д.)

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

Роль (*FAIL) заключается в том, чтобы заставить шаблон терпеть неудачу. Таким образом, все символы, совпадающие слева от (*SKIP), пропускаются, а механизм регулярных выражений продолжает работу после этих символов.

Единственная возможность для шаблона преуспеть в шаблоне примера состоит в том, что первая ветвь завершится до (*SKIP), чтобы разрешить проверку второй ветки.

Здесь вы можете найти другое объяснение .

О Java и других машинах регулярных выражений, которые не имеют этих двух функций

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

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

Использование групп захвата:

способ 1:

What_I_want_to_avoid|(What_I_want_to_match)

Вам нужно только извлечь группу захвата 1 (или проверить, существует ли она), так как это то, что вы ищете. Если вы используете шаблон для выполнения замены, вы можете использовать свойства результата совпадения (смещение, длина, группа захвата), чтобы заменить классические строковые функции. Другой язык, такой как javascript, ruby ​​... позволяет использовать функцию обратного вызова в качестве замены.

способ 2:

((?>To_avoid|Other_things_that_can_be_before_what_i_want)*)(What_I_want)

Это более простой способ для замены, без функции обратного вызова, заменяющая строка должна начинаться только с \1 (или $1)

Использование обращений:

Например, вы хотите найти слово, которое не вложено между двумя другими словами (скажем, S_word и E_word, которые являются разными (см. комментарий Qtax)):

(примеры кросс S_word E_word word E_word и S_word word S_word E_word разрешены в этом примере.)

Глагол управления обратным следом будет:

S_word not_S_word_or_E_word E_word(*SKIP)(*F)|word

Чтобы использовать этот способ, движок регулярного выражения должен в определенной степени допускать зависание переменной длины. С .net или новым модулем regex, никаких проблем, lookbehind может иметь полностью переменную длину. Это возможно и для Java, но размер должен быть ограничен (пример: (?<=.{1,1000})).

эквивалентом Java будет:

word(?:(?!not_S_word_or_E_word E_word)|(?<!S_word not_E_word{0,1000} word))

Обратите внимание, что в некоторых случаях требуется только просмотр. Заметим также, что запуск шаблона с буквенным символом более эффективен, чем запуск с помощью lookbehind, поэтому я поместил его после слова (даже если мне нужно переписать слово еще раз в утверждении.)

Ответ 2

Шаблоны (*SKIP) и (*F) (aka *FAIL) описаны в руководстве Perl: http://perldoc.perl.org/perlre.html p >

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

Java, встроенный в regex engine, не поддерживает эти расширения, и я не знаю того, что делает.

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