Регулярные выражения и отрицание целой группы персонажей

Я пытаюсь что-то, что, по моему мнению, должно быть достаточно очевидным для меня, но это не так. Я пытаюсь сопоставить строку, которая НЕ содержит определенную последовательность символов. Я пробовал использовать [^ab], [^(ab)] и т.д. Для соответствия строкам, не содержащим "a" или "b", или только "a" или "b", но не соответствует "ab". Примеры, которые я дал, не будут соответствовать "ab" it true, но они также не будут соответствовать "a" , и мне они нужны. Есть ли простой способ сделать это?

Ответ 1

Используйте отрицательный просмотр:

^(?!.*ab).*$

ОБНОВЛЕНИЕ. В комментариях ниже я заявил, что этот подход медленнее, чем тот, который приведен в Питере.. С тех пор я провел несколько тестов и обнаружил, что это действительно немного быстрее. Однако причина предпочитать эту технику над другой - это не скорость, а простота.

Другой метод, описанный здесь как умеренный алчный токен, подходит для более сложных проблем, таких как сопоставление текста с разделителями, в котором разделители состоят из несколько символов (например, HTML, как Luke прокомментировал ниже). Для проблемы, описанной в вопросе, она переполняется.

Для всех, кто интересуется, я тестировал большой фрагмент текста Lorem Ipsum, подсчитывая количество строк, которые не содержат слова "quo". Это регулярные выражения, которые я использовал:

(?m)^(?!.*\bquo\b).+$

(?m)^(?:(?!\bquo\b).)+$

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

Ответ 2

Использование класса символов, такого как [^ab], будет соответствовать одиночному символу, который не входит в набор символов. (С ^ является отрицательной частью).

Чтобы соответствовать строке, которая не содержит многосимвольной последовательности ab, вы хотите использовать отрицательный просмотр:

^(?:(?!ab).)+$


И вышеприведенное выражение, которое вызывается в режиме комментариев регулярных выражений:

(?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

Ответ 3

Да его называют негативным взглядом. Это происходит так: (?!regex here). Таким образом, abc(?!def) будет соответствовать abc не, а затем def. Таким образом, он будет соответствовать abce, abc, abck и т.д.

Аналогично, есть положительный результат - (?=regex here). Таким образом, abc(?=def) будет соответствовать abc, а затем def.

Есть также отрицательные и положительные lookbehind - (?<!regex here) и (?<=regex here) соответственно

Следует отметить, что отрицательный lookahead имеет нулевую ширину. То есть, это не считается тем, что занимает какое-то пространство.

Таким образом, может показаться, что a(?=b)c будет соответствовать "abc", но это не будет. Он будет соответствовать "a", а затем положительному взгляду с "b", но он не будет двигаться вперед в строку. Затем он попытается сопоставить "c" с "b", который не будет работать. Точно так же ^a(?=b)b$ будет соответствовать "ab", а не "abb", потому что обратные стороны имеют нулевую ширину (в большинстве реализаций регулярных выражений).

Дополнительная информация о этой странице

Ответ 4

Самый простой способ - полностью вывести отрицание из регулярного выражения:

if (!userName.matches("^([Ss]ys)?admin$")) { ... }

Ответ 5

Использование регулярного выражения, как вы описали, является простым способом (насколько мне известно). Если вам нужен диапазон, вы можете использовать [^ a-f].

Ответ 6

abc (?! def) не будет соответствовать abc по def. Таким образом, он будет соответствовать abce, abc, abck и т.д., что, если я не хочу, чтобы ни xyz не будет abc (?! (def) (xyz))???

У меня был тот же вопрос и нашел решение:

abc(?:(?!def))(?:(?!xyz))

Эти несчетные группы объединяются с помощью "И", поэтому это должно сделать трюк. Надеюсь, что это поможет.

Ответ 7

Регулярное выражение [^ (ab)] будет соответствовать, например, "ab ab ab ab", но не "ab", потому что оно будет соответствовать строке "a" или "b".

Какой язык/сценарий у вас есть? Вы можете вычесть результаты из исходного набора и просто совместить ab?

Если вы используете GNU grep и используете синтаксический анализ, используйте флаг "-v", чтобы инвертировать ваши результаты, возвращая все несоответствия. Другие инструменты регулярных выражений также имеют функцию return nonmatch.

Если я правильно понимаю, вы хотите все, кроме тех элементов, которые содержат "ab" где угодно.

Ответ 8

В этом случае я могу просто просто избегать регулярных выражений и идти с чем-то вроде:

if (StringToTest.IndexOf("ab") < 0)
  //do stuff

Вероятно, это также будет намного быстрее (быстрый тест vs regexes выше показал, что этот метод занимает около 25% времени в методе regex). В общем, если я знаю точную строку, которую я ищу, я обнаружил, что регулярные выражения являются излишними. Поскольку вы знаете, что не хотите "ab", просто проверить, содержит ли строка эту строку, не используя регулярное выражение.

Ответ 9

Просто найдите "ab" в строке, затем отрицайте результат:

!/ab/.test("bamboo"); // true
!/ab/.test("baobab"); // false

Кажется, это проще и должно быть быстрее.