Посмотрите за регулярными выражениями в однострочном perl

#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 .