Регулярные выражения и отрицание целой группы символов [дубликат]
этот вопрос уже есть ответ здесь:
- регулярное выражение для соответствия строке, которая не содержит слова? 27 ответов
Я пытаюсь что-то, что я чувствую, должно быть довольно очевидно для меня, но это не так. Я пытаюсь сопоставить строку, которая не содержит определенной последовательности символов. Я пробовал используя [^ab]
, [^(ab)]
, etc. чтобы соответствовать строки, содержащие 'А или Б, или только А или только б или 'бу' но не матч на 'АБ'. Примеры, которые я привел, не будут соответствовать "ab", это правда, но они также не будут соответствовать " a " в одиночку, и мне это нужно. Есть ли простой способ сделать это?
9 ответов
используйте отрицательный lookahead:
^(?!.*ab).*$
UPDATE: в комментариях ниже я заявил, что этот подход медленнее, чем тот, который приведен в Петровская. С тех пор я провел несколько тестов и обнаружил, что это действительно немного быстрее. Однако причина предпочесть эту технику другой - не скорость, а простота.
другая техника, описанная здесь как закаленный жадный токен, предназначен для более сложных проблемы, такие как сопоставление текста с разделителями, где разделители состоят из нескольких символов (например, HTML, как прокомментировал Люк ниже). Для проблемы, описанной в вопросе, это перебор.
для всех, кто заинтересован, я тестировал с большим куском текста Lorem Ipsum, подсчитывая количество строк, которые не содержат слова "quo". Это регексы, которые я использовал:
(?m)^(?!.*\bquo\b).+$
(?m)^(?:(?!\bquo\b).)+$
ищу ли я совпадения во всем тексте или разбиваю его на строки и сопоставьте их индивидуально, закрепленный lookahead последовательно превосходит плавающий.
использовать класс символов, таких как [^ab]
будет соответствовать один символ, что не входит в набор символов. (С ^
будучи отрицающей частью).
чтобы соответствовать строке, которая не содержит многозначную последовательность ab
, вы хотите использовать отрицательный просмотр вперед:
^(?:(?!ab).)+$
И приведенное выше выражение, отключенное в режиме комментариев regex:
(?x) # enable regex comment mode
^ # match start of line/string
(?: # begin non-capturing group
(?! # begin negative lookahead
ab # literal text sequence ab
) # end negative lookahead
. # any single character
) # end non-capturing group
+ # repeat previous match one or more times
$ # match end of line/string
да его называют отрицательным взглядом. Вот как это звучит ... --0-->. Так что abc(?!def)
будет соответствовать abc не затем def. Таким образом, он будет соответствовать abce, abc, abck и т. д.
аналогично есть положительный lookahead -(?=regex here)
. Так что abc(?=def)
будет соответствовать abc, а затем def.
есть также отрицательный и положительный lookbehind -(?<!regex here)
и (?<=regex here)
соответственно
следует отметить, что отрицательный lookahead равен нулевой ширине. То есть, это не считайте, что заняли любое пространство.
так это может выглядеть как a(?=b)c
будет соответствовать "abc", но это не будет. Он будет соответствовать "a", затем положительный lookahead с "b", но он не будет двигаться вперед в строку. Затем он попытается сопоставить " c " с "b", который не будет работать. Аналогично ^a(?=b)b$
будет соответствовать "ab", а не "abb", потому что lookarounds имеют нулевую ширину (в большинстве реализаций регулярных выражений).
подробнее о этой страница
использование регулярного выражения, как вы описали, является простым способом (насколько мне известно). Если вам нужен диапазон, вы можете использовать [^a-f].
самый простой способ-полностью вытащить отрицание из регулярного выражения:
if (!userName.matches("^([Ss]ys)?admin$")) { ... }
abc(?!def) будет соответствовать abc не следует на деф. Так что это будет соответствовать abce, abc, abck, etc. что, если я не хочу ни def и xyz не будет abc(?!(def) (xyz)) ???
у меня был тот же вопрос и нашел решение:
abc(?:(?!def))(?:(?!xyz))
эти не подсчитывающие группы объединены "и", поэтому это должно сделать трюк. Надеюсь, это поможет.
регулярное выражение [^(ab)] будет соответствовать, например, "ab ab ab ab", но не "ab", потому что оно будет соответствовать строке " a " или "b".
какой язык / сценарий у вас есть? Можете ли вы вычесть результаты из исходного набора и просто сопоставить ab?
Если вы используете GNU grep и анализируете входные данные, используйте флаг '-v' для инвертирования результатов, возвращая все несоответствия. Другие инструменты регулярных выражений также имеют функцию "return nonmatch".
Если я правильно понял, вы хотите все, кроме тех элементов, которые содержат " ab " в любом месте.
в этом случае я мог бы просто избежать регулярных выражений и пойти с что-то вроде:
if (StringToTest.IndexOf("ab") < 0)
//do stuff
Это, вероятно, также будет намного быстрее (быстрый тест против регулярных выражений выше показал, что этот метод занимает около 25% времени метода регулярных выражений). В общем, если я знаю точную строку, которую я ищу, я нашел, что regexes излишни. Поскольку вы знаете, что не хотите "ab", просто проверить, содержит ли строка эту строку, без использования регулярное выражение.
просто найдите " ab " в строке, затем отрицайте результат:
!/ab/.test("bamboo"); // true
!/ab/.test("baobab"); // false
это кажется проще и должно быть быстрее.