Как отрицать конкретное слово в регулярных выражениях? - PullRequest
549 голосов
/ 06 августа 2009

Я знаю, что могу отрицать группу символов, как в [^bar], но мне нужно регулярное выражение, где отрицание применяется к конкретному слову - так что в моем примере, как мне отрицать фактическое "bar", а не "any chars in bar"?

Ответы [ 11 ]

606 голосов
/ 06 августа 2009

Отличный способ сделать это - использовать негативный взгляд :

^(?!.*bar).*$

Негативная конструкция - это пара круглых скобок, за открывающей скобкой следует знак вопроса и восклицательный знак Внутри lookahead [есть любой шаблон регулярных выражений].

59 голосов
/ 06 августа 2009

Если производительность не имеет первостепенного значения, зачастую проще пропустить результаты через второй проход, пропуская те, которые соответствуют словам, которые вы хотите опровергнуть.

Регулярные выражения обычно означают, что вы в любом случае выполняете сценарии или выполняете какие-то неэффективные задачи, поэтому найдите решение, которое легко прочитать, легко понять и легко обслуживать.

44 голосов
/ 06 августа 2009

Следующее регулярное выражение будет делать то, что вы хотите (при условии, что поддерживаются отрицательные lookbehind и lookaheads), правильно сопоставляя вещи; единственная проблема заключается в том, что он соответствует отдельным символам (т. е. каждое совпадение является одним символом, а не всеми символами между двумя последовательными "столбцами"), что может привести к высоким издержкам при работе с очень длинными строками.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]
42 голосов
/ 06 августа 2009

Вы можете использовать негативный прогноз или прогноз :

^(?!.*?bar).*
^(.(?<!bar))*?$

Или используйте только основы:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$

Все они соответствуют чему-либо, что не содержит bar.

30 голосов
/ 11 сентября 2010

Я наткнулся на эту ветку форума, пытаясь определить регулярное выражение для следующего утверждения на английском языке:

Для заданной входной строки соответствует все , если эта входная строка в точности не является 'bar'; например, я хочу сопоставить «барьер» и «дисбар», а также «foo».

Вот регулярное выражение, которое я придумал

^(bar.+|(?!bar).*)$

Мой английский перевод регулярного выражения: «соответствует строке, если она начинается с« bar »и содержит хотя бы еще один символ, или если строка не начинается с« bar ».

28 голосов
/ 13 сентября 2016

Решение:

^(?!.*STRING1|.*STRING2|.*STRING3).*$

хххххх ОК

xxxSTRING1xxx KO (является ли это желательным)

xxxSTRING2xxx KO (является ли это желательным)

xxxSTRING3xxx KO (является ли это желательным)

9 голосов
/ 04 января 2016

Принятый ответ хорош, но на самом деле это обходной путь для отсутствия простого оператора отрицания подвыражения в регулярных выражениях Вот почему grep --invert-match выходит. Таким образом, в * nixes вы можете достичь желаемого результата, используя каналы и второе регулярное выражение.

grep 'something I want' | grep --invert-match 'but not these ones'

Все еще обходной путь, но, возможно, легче запомнить.

3 голосов
/ 06 декабря 2017

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

@ ChrisVanOpstal поделился этим руководством по регулярным выражениям , которое является отличным ресурсом для изучения регулярных выражений.

Однако, было действительно много времени, чтобы прочитать.

Я сделал шпаргалку для удобства мнемоники.

Эта ссылка основана на скобках [], () и {}, ведущих за каждым классом, и мне легко вспомнить.

Regex = {
 'single_character': ['[]', '.', {'negate':'^'}],
 'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
 'repetition'      : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
 'anchor'          : ['^', '\b', '$'],
 'non_printable'   : ['\n', '\t', '\r', '\f', '\v'],
 'shorthand'       : ['\d', '\w', '\s'],
 }
1 голос
/ 06 ноября 2015

У меня был список имен файлов, и я хотел исключить определенные имена с таким поведением (Ruby):

files = [
  'mydir/states.rb',      # don't match these
  'countries.rb',
  'mydir/states_bkp.rb',  # match these
  'mydir/city_states.rb' 
]
excluded = ['states', 'countries']

# set my_rgx here

result = WankyAPI.filter(files, my_rgx)  # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']

Вот мое решение:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|')
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/

Мои предположения для этого приложения:

  • Строка, которая должна быть исключена, находится в начале ввода или сразу после косой черты.
  • Разрешенные строки заканчиваются на .rb.
  • Разрешенные имена файлов не имеют символа . перед .rb.
1 голос
/ 07 августа 2009

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

Используйте эквивалентный метод split() на выбранном вами языке в строке со словом отрицания в качестве аргумента для того, на что делиться. Пример использования Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']

Приятно делать это таким образом, по крайней мере, в Python (я не помню, была ли бы функциональность такой же, скажем, в Visual Basic или Java), - это то, что он позволяет вам косвенно знать, когда "bar" был повторен в строке из-за того, что пустые строки между «барами» включены в список результатов (хотя пустая строка в начале обусловлена ​​наличием «бара» в начале строки). Если вы этого не хотите, вы можете просто удалить пустые строки из списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...