Я знаю, что можно сопоставить слово, а затем отменить совпадения, используя другие инструменты (например grep -v
). Однако возможно ли сопоставить строки, которые не содержат определенного слова, например hede
, с использованием регулярного выражения?
Входные данные:
hoho
hihi
haha
hede
Код:
grep "<Regex for 'doesn't contain hede'>" input
Желаемый результат:
hoho
hihi
haha
regex
regex-negation
knaser
источник
источник
([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*
:? Идея проста. Продолжайте сопоставление, пока не увидите начало нежелательной строки, затем сопоставляйте только в N-1 случаях, когда строка не завершена (где N - длина строки). Эти случаи N-1: «h, сопровождаемый не-е», «он следует, не-d», и «hed, сопровождаемый не-e». Если вам удалось пропустить эти случаи N-1, вы успешно не сопоставили нежелательную строку, поэтому вы можете начать поиск[^h]*
снова^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$
это происходит, когда экземплярам "hede" предшествуют частичные экземпляры "hede", такие как "hhede".Ответы:
Понятие, что регулярное выражение не поддерживает обратное сопоставление, не совсем верно. Вы можете имитировать это поведение, используя негативные осмотры:
Приведенное выше регулярное выражение будет соответствовать любой строке или строке без разрыва строки, не содержащей (под) строку 'hede'. Как уже упоминалось, это не то , что регулярное выражение «хорошо» в (или должны делать), но все же, это возможно.
И если вам нужно сопоставить символы разрыва строки, используйте модификатор DOT-ALL (трейлинг
s
в следующем шаблоне):или используйте его в строке:
(где
/.../
разделители регулярных выражений, т. е. не являются частью шаблона)Если модификатор DOT-ALL недоступен, вы можете имитировать то же поведение с классом символов
[\s\S]
:объяснение
Строка - это просто список
n
символов. До и после каждого символа есть пустая строка. Таким образом, списокn
символов будет иметьn+1
пустые строки. Рассмотрим строку"ABhedeCD"
:где
e
это пустые строки. Регулярное выражение(?!hede).
смотрит вперед, чтобы увидеть, нет ли подстроки,"hede"
которая будет видна, и если это так (то есть что-то еще видно), то.
(точка) будет соответствовать любому символу, кроме разрыва строки. Осмотры также называются утверждениями нулевой ширины, потому что они не потребляют никаких символов. Они только утверждают / подтверждают что-то.Итак, в моем примере каждая пустая строка сначала проверяется, чтобы увидеть, нет ли
"hede"
впереди, прежде чем символ будет использован.
(точка). Регулярное выражение(?!hede).
будет делать это только один раз, так что он обернут в группе, и повторяться ноль или более раз:((?!hede).)*
. Наконец, начало и конец ввода привязываются, чтобы убедиться, что весь вход используется:^((?!hede).)*$
Как вы можете видеть, вход
"ABhedeCD"
будет не потому , что наe3
регулярное выражение(?!hede)
не удается (там находится"hede"
впереди!).источник
grep
, которые упоминает OP) с поддержкой регулярных выражений имеют функции, которые делают их нерегулярными в теоретическом смысле.^\(\(hede\)\@!.\)*$
Обратите внимание, что решение не начинается с «хеде» :
обычно гораздо эффективнее, чем решение , не содержащее «хеде» :
Первый проверяет «hede» только в первой позиции входной строки, а не в каждой позиции.
источник
(.*)(?<!hede)$
. Версия @Nyerguds тоже подойдет, но полностью упускает момент производительности, о котором говорится в ответе.^((?!hede).)*$
? Разве это не более эффективно для использования^(?!.*hede).*$
? Он делает то же самое, но в несколько шаговЕсли вы просто используете его для grep, вы можете использовать
grep -v hede
для получения всех строк, которые не содержат хеде.ЭТА О, перечитывая вопрос,
grep -v
вы, вероятно, подразумевали «инструменты».источник
grep -v -e hede -e hihi -e ...
grep -v "hede\|hihi"
:)grep -vf pattern_file file
egrep
илиgrep -Ev "hede|hihi|etc"
чтобы избежать неловкого побега.Ответ:
Объяснение:
^
начало строки,(
группировка и захват в \ 1 (0 или более раз (соответствует максимально возможному количеству)),(?!
посмотрите вперед, если нет,hede
твоя строка,)
конец упреждения,.
любой символ, кроме \ n,)*
конец \ 1 (Примечание: поскольку вы используете квантификатор для этого перехвата, только последнее ПОСЛЕДНЕЕ повторение захваченного шаблона будет сохранено в \ 1)$
перед необязательным \ n, и конец строкиисточник
^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$
'Приведенные ответы прекрасно, просто академический балл:
Регулярные выражения в смысле теоретических компьютерных наук НЕ МОГУТ делать это так. Для них это должно было выглядеть примерно так:
Это только соответствует ПОЛНОМУ. Делать это для под-матчей было бы еще более неловко.
источник
(hede|Hihi)
»? (Это может быть вопрос для CS.)Если вы хотите, чтобы тест регулярного выражения завершился неудачей, только если вся строка совпадает, будет работать следующее:
Например, если вы хотите разрешить все значения, кроме «foo» (то есть «foofoo», «barfoo» и «foobar» пройдут, но «foo» завершится ошибкой), используйте:
^(?!foo$).*
Конечно, если вы проверяете точное равенство, лучшим общим решением в этом случае является проверка на равенство строк, т.е.
Вы даже можете поместить отрицание вне теста, если вам нужны какие-либо функции регулярных выражений (здесь, нечувствительность к регистру и согласование диапазона):
Однако решение regex в верхней части этого ответа может быть полезным в ситуациях, когда требуется положительный тест regex (возможно, через API).
источник
" hede "
?\s
директива соответствует одному пробелу^(?!\s*hede\s*$).*
FWIW, поскольку регулярные языки (или рациональные языки) закрыты при дополнении, всегда можно найти регулярное выражение (также называемое рациональное выражение), которое отрицает другое выражение. Но не многие инструменты реализуют это.
Vcsn поддерживает этот оператор (который обозначает
{c}
postfix).Вы сначала определить тип ваших выражений: этикетки письмо (
lal_char
) , чтобы выбрать из ,a
чтобыz
, например (определение алфавита при работе с комплементарности, конечно, очень важно), и «значение» вычисляется для каждого слова просто Boolean :true
слово принятоfalse
, отклонено.В Python:
затем вы вводите выражение:
преобразовать это выражение в автомат:
наконец, преобразовать этот автомат обратно в простое выражение.
где
+
обычно обозначается|
,\e
обозначает пустое слово и[^]
обычно пишется.
(любой символ). Итак, немного переписав()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*
.Вы можете увидеть этот пример здесь и попробовать Vcsn онлайн там .
источник
|
не будут играть хорошо.'^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'
,Вот хорошее объяснение того, почему не легко отрицать произвольное регулярное выражение. Я должен согласиться с другими ответами, хотя: если это что-то кроме гипотетического вопроса, то регулярное выражение здесь не правильный выбор.
источник
С отрицательным взглядом, регулярное выражение может соответствовать чему-то, не содержащему определенного шаблона. На это отвечает и объясняет Барт Киерс. Отличное объяснение!
Тем не менее, с ответом Барта Киерса, предварительная часть будет проверять от 1 до 4 символов вперед при сопоставлении с любым отдельным символом. Мы можем избежать этого и позволить предзаголовочной части проверить весь текст, убедиться, что нет «хеде», и тогда нормальная часть (. *) Может съесть весь текст за один раз.
Вот улучшенное регулярное выражение:
Обратите внимание, что (*?) Ленивый квантификатор в части с отрицательным прогнозом не является обязательным, вы можете вместо этого использовать (*) жадный квантификатор, в зависимости от ваших данных: если 'hede' присутствует и в первой половине текста, ленивый квантификатор может быть быстрее; в противном случае жадный квантификатор будет быстрее. Однако, если «hede» не присутствует, оба будут равны медленно.
Вот демонстрационный код .
Для получения дополнительной информации о Lookahead, пожалуйста, прочитайте большую статью: Освоение Lookahead и Lookbehind .
Кроме того, ознакомьтесь с RegexGen.js , генератором регулярных выражений JavaScript, который помогает создавать сложные регулярные выражения. С помощью RegexGen.js вы можете создать регулярное выражение более читабельным способом:
источник
^(?!.*(str1|str2)).*$
^(?!.*?(?:str1|str2)).*$
зависимости от ваших данных. Добавил,?:
так как нам не нужно захватывать его.Ориентиры
Я решил оценить некоторые из представленных опций и сравнить их производительность, а также использовать некоторые новые функции. Сравнительный анализ на .NET Regex Engine: http://regexhero.net/tester/
Контрольный текст:
Первые 7 строк не должны совпадать, поскольку они содержат искомое выражение, а нижние 7 строк должны совпадать!
Результаты:
Результатами являются итерации в секунду в качестве медианы 3 прогонов - большее число = лучшее
Поскольку .NET не поддерживает глаголы действий (* FAIL и т. Д.), Я не смог протестировать решения P1 и P2.
Резюме:
Я пытался протестировать большинство предложенных решений, возможна некоторая оптимизация для определенных слов. Например, если первые две буквы строки поиска не совпадают, ответ 03 можно расширить до
^(?>[^R]+|R+(?!egex Hero))*$
небольшого прироста производительности.Но в целом наиболее читаемым и быстродействующим решением, по-видимому, является 05 с использованием условного оператора или 04 с положительным квантификатором. Я думаю, что Perl-решения должны быть еще быстрее и более легко читаемыми.
источник
^(?!.*hede)
тоже. /// Кроме того, вероятно, лучше ранжировать выражения для совпадающего и несовпадающего корпусов по отдельности, потому что это обычно тот случай, когда большинство совпадений строк или большинство строк этого не делают.Не регулярное выражение, но я нашел логичным и полезным использовать последовательные greps с pipe для устранения шума.
например. искать файл конфигурации apache без всех комментариев-
а также
Логика последовательных grep'ов есть (не комментарий) и (соответствует dir)
источник
grep -v
good_stuff #comment_stuff
при этом вы избегаете проверять прогноз на каждой позиции:
эквивалентно (для .net):
Старый ответ:
источник
/^[^h]*(?:h+(?!ede)[^h]*)*$/
Вышеупомянутое
(?:(?!hede).)*
замечательно, потому что это может быть закреплено.Но в этом случае будет достаточно:
Это упрощение готово к добавлению предложений «И»:
источник
Вот как я это сделаю:
Точнее и эффективнее других ответов. Он реализует метод эффективности «развернутой петли» Фридла и требует гораздо меньшего возврата.
источник
Если вы хотите сопоставить символ, чтобы отрицать слово, подобное отрицанию класса символов:
Например, строка:
Не используйте:
Использование:
Обратите внимание, что
"(?!bbb)."
это не взгляд назад и не взгляд вперед, это выглядит как ток, например:источник
(?!
). Префикс положительного предпросмотра был бы, в(?=
то время как соответствующие префиксы предпросмотра были бы(?<!
и(?<=
соответственно. Взгляд в будущее означает, что вы читаете следующие символы (следовательно, «впереди»), не потребляя их. Взгляд назад означает, что вы проверяете символы, которые уже были использованы.На мой взгляд, более читаемый вариант верхнего ответа:
По сути, «совпадать в начале строки тогда и только тогда, когда в ней нет слова« хеде »», поэтому требование почти напрямую переводится в регулярное выражение.
Конечно, возможно наличие нескольких требований отказа:
Детали: Якорь ^ гарантирует, что механизм регулярных выражений не повторяет совпадение в каждом месте строки, что соответствует каждой строке.
Якорь ^ в начале предназначен для обозначения начала строки. Инструмент grep сопоставляет каждую строку по одной за раз, в тех случаях, когда вы работаете с многострочной строкой, вы можете использовать флаг "m":
или
источник
ОП не указывал или Tagпост, чтобы указать контекст (язык программирования, редактор, инструмент), в котором будет использоваться Regex.
Для меня, иногда мне нужно сделать это при редактировании файла с помощью
Textpad
.Textpad
поддерживает некоторые Regex, но не поддерживает lookahead или lookbehind, поэтому требуется несколько шагов.Если я хочу сохранить все строки, которые НЕ содержат строку
hede
, я бы сделал это так:Теперь у вас есть оригинальный текст со всеми строками, содержащими
hede
удаленную строку .Если я хочу сделать что-то еще только для строк, которые НЕ содержат строку
hede
, я бы сделал это так:источник
Поскольку никто другой не дал прямого ответа на заданный вопрос , я сделаю это.
Ответ в том, что с POSIX
grep
невозможно буквально удовлетворить этот запрос:Причина в том, что POSIX
grep
требуется только для работы с базовыми регулярными выражениями , которые просто недостаточно мощны для выполнения этой задачи (они не способны анализировать обычные языки из-за отсутствия чередования и скобок).Тем не менее, GNU
grep
реализует расширения, которые позволяют это. В частности,\|
оператор Чередование в реализации проекта GNU в Бре, а\(
и\)
являются круглые скобки. Если ваш механизм регулярных выражений поддерживает чередование, выражения с отрицательными скобками, круглые скобки и звездочку Клини и может привязывать начало и конец строки, это все, что вам нужно для этого подхода. Тем не менее, обратите внимание, что отрицательные множества[^ ... ]
очень удобны в дополнение к тем, потому что в противном случае вам нужно заменить их выражением формы, в(a|b|c| ... )
котором перечислены все символы, которых нет в наборе, что является чрезвычайно утомительным и чрезмерно длинным, особенно если весь набор символов Unicode.С GNU
grep
ответом будет что-то вроде:(найдено с Grail и некоторыми дополнительными оптимизациями, сделанными вручную).
Вы также можете использовать инструмент, который реализует расширенные регулярные выражения , например
egrep
, чтобы избавиться от обратной косой черты:Вот скрипт для его проверки (обратите внимание, что он генерирует файл
testinput.txt
в текущем каталоге):В моей системе это печатает:
как и ожидалось.
Для тех, кто интересуется деталями, используется метод преобразования регулярного выражения, соответствующего слову, в конечный автомат, затем инвертирование автомата путем изменения каждого состояния принятия в непринятие и наоборот, а затем преобразование полученного FA обратно в регулярное выражение.
Наконец, как все уже заметили, если ваш движок регулярных выражений поддерживает отрицательный прогноз, это значительно упрощает задачу. Например, с помощью GNU grep:
Обновление: я недавно нашел превосходную библиотеку FormalTheory Кендалла Хопкинса , написанную на PHP, которая обеспечивает функциональность, аналогичную Grail. Используя его и написанный мной упрощатель, я смог написать онлайн-генератор отрицательных регулярных выражений с учетом входной фразы (в настоящее время поддерживаются только буквенно-цифровые и пробельные символы): http://www.formauri.es/personal/ pgimeno / разное / неигровые-регулярное выражение /
Для
hede
этого выводит:что эквивалентно вышеизложенному.
источник
С момента появления ruby-2.4.1 мы можем использовать новый оператор Absent в регулярных выражениях Ruby.
из официального документа
Таким образом, в вашем случае
^(?~hede)$
делает работу за васисточник
Через глагол PCRE
(*SKIP)(*F)
Это полностью пропустит строку, которая содержит точную строку
hede
и соответствует всем оставшимся строкам.DEMO
Исполнение частей:
Давайте рассмотрим приведенное выше регулярное выражение, разбив его на две части.
Часть перед
|
символом. Часть не должна совпадать .Часть после
|
символа. Часть должна соответствовать .ЧАСТЬ 1
Движок Regex начнет выполнение с первой части.
Объяснение:
^
Утверждает, что мы на старте.hede
Соответствует строкеhede
$
Утверждает, что мы находимся в конце строки.Таким образом, строка, содержащая строку
hede
, будет сопоставлена. Как только механизм регулярных выражений видит следующий(*SKIP)(*F)
( Примечание: вы можете написать(*F)
как(*FAIL)
) глагол, он пропускает и делает совпадение неудачным.|
Вызывается изменение или логический оператор ИЛИ, добавленный рядом с глаголом PCRE, который соответствует всем границам, существующим между каждым и каждым символом во всех строках, за исключением того, что строка содержит точную строкуhede
. Смотрите демо здесь . То есть он пытается сопоставить символы из оставшейся строки. Теперь регулярное выражение во второй части будет выполнено.ЧАСТЬ 2
Объяснение:
^
Утверждает, что мы на старте. то есть он соответствует всем началам строки, кроме той, что вhede
строке. Смотрите демо здесь ..*
В многострочном режиме.
будет соответствовать любому символу, кроме символов новой строки или возврата каретки. И*
будет повторять предыдущий символ ноль или более раз. Так.*
будет соответствовать всей линии. Смотрите демо здесь .Эй, почему ты добавил. * Вместо. +?
Потому что
.*
будет соответствовать пустой строке, но.+
не будет соответствовать пустой. Мы хотим сопоставить все строки, за исключением тогоhede
, что возможна также пустая строка на входе. поэтому вы должны использовать.*
вместо.+
..+
будет повторять предыдущий символ один или несколько раз. Смотрите.*
совпадения пустой строкой здесь .$
Привязка конца строки здесь не нужна.источник
Это может быть более приемлемым для двух регулярных выражений в вашем коде, один для первого сопоставления, а затем, если он совпадает, запустите второе регулярное выражение, чтобы проверить наличие выбросов, которые вы хотите заблокировать, например,
^.*(hede).*
затем иметь соответствующую логику в своем коде.Хорошо, я признаю, что это не совсем ответ на опубликованный вопрос, и он также может использовать немного больше обработки, чем одно регулярное выражение. Но для разработчиков, которые пришли сюда в поисках быстрого экстренного решения для случайного случая, это решение не следует упускать из виду.
источник
Другой вариант заключается в том, чтобы добавить положительный прогноз и проверить, есть ли
hehe
где-нибудь в строке ввода, то мы бы отрицали это, используя выражение, подобное:с границами слова.
Выражение объяснено на верхней правой панели regex101.com , если вы хотите изучить / упростить / изменить его, и по этой ссылке вы можете посмотреть, как оно будет соответствовать некоторым образцам входных данных, если хотите.
RegEx Circuit
jex.im визуализирует регулярные выражения:
источник
Язык TXR поддерживает отрицание регулярных выражений.
Более сложный пример: сопоставить все строки, которые начинаются с
a
и заканчиваютсяz
, но не содержат подстрокиhede
:Отрицание регулярных выражений не особенно полезно само по себе, но когда у вас также есть пересечение, вещи становятся интересными, поскольку у вас есть полный набор операций с булевыми множествами: вы можете выразить «множество, которое соответствует этому, за исключением вещей, которые соответствуют этому».
источник
Функция ниже поможет вам получить желаемый результат
источник
^ ((?! hede).) * $ - элегантное решение, за исключением того, что оно использует символы, поэтому вы не сможете комбинировать его с другими критериями. Например, скажем, вы хотели проверить отсутствие «хеде» и наличие «хаха». Это решение будет работать, потому что оно не будет потреблять символы:
^ (?!. \ bhede \ b) (? =. \ bhaha \ b)
источник
Как использовать контрольные глаголы PCRE для соответствия строке, не содержащей слова
Вот метод, который я раньше не видел:
Как это работает
Сначала он пытается найти «хеде» где-то в очереди. В случае успеха на этом этапе
(*COMMIT)
двигатель сообщает не только не возвращаться в случае сбоя, но и не предпринимает попыток дальнейшего сопоставления в этом случае. Затем мы пытаемся сопоставить что-то, что не может совпадать (в этом случае^
).Если строка не содержит «hede», тогда вторая альтернатива, пустой подшаблон, успешно соответствует строке темы.
Этот метод не более эффективен, чем негативный взгляд, но я решил, что просто добавлю его здесь на случай, если кто-то найдет его изящным и найдет применение для других, более интересных приложений.
источник
Более простое решение - использовать оператор not !
Ваше заявление if должно соответствовать «содержит», а не соответствовать «исключает».
Я считаю, что дизайнеры RegEx ожидали использования не операторов.
источник
Возможно, вы найдете это в Google, пытаясь написать регулярное выражение, которое может соответствовать сегментам строки (в отличие от целых строк), которые не содержат подстроки. Уделите мне немного времени, чтобы понять, поэтому я поделюсь:
Учитывая строку:
<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>
Я хочу соответствовать
<span>
теги, которые не содержат подстроку «плохо»./<span(?:(?!bad).)*?>
будет соответствовать<span class=\"good\">
и<span class=\"ugly\">
.Обратите внимание, что есть два набора (слоя) скобок:
Демо в Ruby:
источник
С помощью ConyEdit вы можете использовать командную строку,
cc.gl !/hede/
чтобы получить строки, которые не содержат совпадения с регулярным выражением, или использовать командную строкуcc.dl /hede/
для удаления строк, которые содержат сопоставление с регулярным выражением. У них одинаковый результат.источник
Я хотел бы добавить еще один пример, если вы пытаетесь сопоставить всю строку, которая содержит строку X , но также не содержит строку Y .
Например, допустим, мы хотим проверить, содержит ли наш URL / строка « вкусные угощения », если он также нигде не содержит « шоколад ».
Этот шаблон регулярного выражения будет работать (работает и в JavaScript)
(глобальные, многострочные флаги в примере)
Интерактивный пример: https://regexr.com/53gv4
Матчи
(Эти URL содержат «вкусные угощения», а также не содержат «шоколад»)
Не совпадает
(Эти URL-адреса содержат где-то «шоколад» - поэтому они не будут совпадать, даже если они содержат «вкусные угощения»)
источник