Как (*SKIP) или (*F) работают с регулярными выражениями?
Я изучаю расширенное использование регулярных выражений и заметил, что многие посты используют (*SKIP)
или же (*F)
в этом.
Я отправил вопрос, где идея состояла в том, чтобы соответствовать линиям, которые не имеют yellow
но имеет blue
только если brown
существует после синего И правильный ответ был:
.*yellow.*(*SKIP)(*F)|^.*\bblue\b(?=.*brown).*$
Я также попробовал выражения поиска, как показано ниже, но не работал для всех случаев:
^((?!yellow).)*blue(?=.*brown).*$
Я понятия не имел об этом (*SKIP)(*F)
флаги, так что вопрос, как эти флаги работают? Что они делают? И есть ли другие флаги, подобные этим?
Благодарю.
2 ответа
Эти два глагола управления возвратом реализованы только в Perl, PCRE и модуле pypi regex.
Идея (*SKIP)(*FAIL)
хитрость состоит в том, чтобы потреблять символы, которых вы хотите избежать, и которые не должны быть частью результата матча.
Классический шаблон, который использует этот трюк выглядит так:
What_I_want_to_avoid(*SKIP)(*FAIL)|What_I_want_to_match
Движок регулярных выражений обрабатывает строку следующим образом:
первый токен шаблона проверяется на каждом символе слева направо (по умолчанию большую часть времени, но некоторые движки регулярных выражений могут работать справа налево, .net может сделать это, если я хорошо помню)
если первый токен совпадает, то механизм регулярных выражений проверяет следующий токен шаблона со следующими символами (после первого совпадения токена) и т. д.
когда токен выходит из строя, механизм регулярных выражений возвращает символы, сопоставленные последнему токену, и пытается найти другой способ, чтобы преуспеть в паттерне (если он тоже не работает, механизм регулярных выражений делает то же самое с предыдущим токеном и т. д.)
Когда двигатель регулярного выражения встречает (*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
)
Использование lookarounds:
Например, вы хотите найти слово, которое не вставлено между двумя другими словами (скажем, 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 или новым модулем регулярных выражений, нет проблем, взгляды могут иметь полностью переменную длину. Это возможно и с Java, но размер должен быть ограничен (пример: (?<=.{1,1000})
)
Эквивалент Java будет:
word(?:(?!not_S_word_or_E_word E_word)|(?<!S_word not_E_word{0,1000} word))
Обратите внимание, что в некоторых случаях необходим только прогноз. Заметьте также, что запуск шаблона с буквенным символом более эффективен, чем запуск с просмотра сзади, поэтому я поставил его после слова (даже если мне нужно переписать слово еще раз в утверждении).
(*SKIP)
а также (*F)
(ака *FAIL
) шаблоны описаны в руководстве по Perl: http://perldoc.perl.org/perlre.html
Однако они доступны только в Perl и во разновидностях регулярных выражений, имитирующих Perl (например, библиотека PCRE, используемая PHP).
Встроенный в Java движок регулярных выражений не поддерживает эти расширения, и я не знаю ни одного из них.
Мой общий совет в Java - сохранять ваши регулярные выражения простыми и использовать другие методы манипуляции со строками, чтобы достичь того, что не может быть четко сделано с помощью короткого регулярного выражения.