#perl #regex-negation #regex-lookarounds
#perl #регулярное выражение-отрицание #поиск регулярных выражений
Вопрос:
Я пытаюсь создать однострочный скрипт, который печатает, когда github
не отстает golang
.
Например, java is a language used in github
должно совпадать, но golang is a language used in github
не должно совпадать.
Я пробовал выражение /(?<!golang).*github/
, но оно не работает.
echo "golang is a language used in github" |
perl -nle'print /(?<!golang).*github/ ? "match" : "no match"'
Это печатает match
вместо no match
.
Как я могу это сделать, используя «отрицательный просмотр» в Perl?
(С использованием Perl v5.28.1)
Комментарии:
1. В вашем примере шаблон совпадает с позицией 0. Позиция 0 не предшествует непосредственно
golang
, и это начало строки, которая соответствует.*github
2. Нужно ли ему совпадать
"java is a language used in github, but golang is not"
(где github предшествует golang)?
Ответ №1:
Ваше выражение соответствует всем строкам со словом « github
» в них. Давайте посмотрим, почему:
/(?<!golang).*github/
будет совпадать до тех пор, пока Perl может настроить .*
сопоставление достаточного количества символов, чтобы не столкнуться с ситуацией, когда ему непосредственно предшествует golang
. Регулярные выражения, будучи жадными, .*
будут соответствовать столько, сколько смогут, при этом остальная часть шаблона будет совпадать.
Так что, если ваша строка
golang is a language used in github
Регулярное выражение может совпадать, присваивая строку разным частям:
(?<!golang)
совпадения в начале строки.*
получает «golang is a language used in
«github
получает «github
«
Потенциально дорогостоящий способ добиться того, чего вы хотели, это:
/^(?:(?!golang).)*github/
Он работает, следя за тем, чтобы ни один из символов, предшествующих « github
«, не начинал последовательность « golang
«.
Итак
echo "java is a language used in github" | perl -ne 'print q!Not golang: !, /^(?:(?!golang).)*github/ ? q!true! : q!false!'
будет распечатываться Not golang: true
, пока
echo "golang is a language used in github" | perl -ne 'print q!Not golang: !, /^(?:(?!golang).)*github/ ? q!true! : q!false!'
будет распечатан Not golang: false
.
Другой (менее запутанный) способ — выполнить два последовательных теста:
/^(.*)github/ and $1 !~ /golang/
Если вы выполняете десятки или сотни тысяч строк, может быть, протестируйте оба способа, чтобы найти, какой из них быстрее?
Ответ №2:
улучшение Bohemian,
/^(?!.*golang.*github).*github/
Ответ №3:
Просто используйте отрицательный взгляд вперед, привязанный к началу:
^(?!.*golang).*github
Комментарии:
1. Это будет неправильно не соответствовать
github golang
.