Регулярное выражение для строки, не заканчивающейся данным суффиксом


190

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

Это соответствует

b
ab
1

Это не совпадает

a
ba

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

Изменить : Оригинальный вопрос, кажется, не является законным примером для моего случая. Итак: как обрабатывать более одного персонажа? Скажи что-нибудь не заканчивается ab?

Я смог это исправить, используя эту тему :

.*(?:(?!ab).).$

Хотя недостатком этого является то, что он не соответствует строке из одного символа.


5
Это не дубликат связанного вопроса - сопоставление только с концом требует другого синтаксиса, чем сопоставление в любом месте строки. Просто посмотрите на верхний ответ здесь.
Джастин

Я согласен, это не дубликат связанного вопроса. Интересно, как можно убрать вышеуказанные «отметки»?
Алан Кабрера

Там нет такой ссылки, которую я вижу.
Алан Кабрера

Ответы:


252

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

.*(?<!a)$

(?<!a)является отрицательным утверждением, которое гарантирует, что до конца строки (или строки с mмодификатором) не будет символа «a».

Смотрите это здесь на Regexr

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

.*(?<!ab)$

Это будет соответствовать всему, что не заканчивается на "ab", посмотрите это на Regexr


1
Я не знаю RegexPAL, но регулярные выражения различны во всех языках, и утверждения, представленные ниже, являются расширенной функцией, которая поддерживается не всеми.
Stema

7
regexpal - это тестер регулярных выражений на основе javascript, а javascript не поддерживает утверждения, которые печальны, что печально
HamZa

Взгляды не поддерживаются в регулярных выражениях (javascript)
Stealth Rabbi

1
Отсутствие взглядов в JS заставляет меня плакать. Если вы работаете на стороне сервера, то, возможно, вы можете использовать модуль PCRE в NPM или аналогичном, чтобы использовать их напрямую (это набор привязок, поэтому я не думаю, что вы можете использовать его как интерфейс)
Eirik Birkeland

Другие типов упреждающих / утверждений: просмотр назад stackoverflow.com/q/2973436/12484
Джон Шнайдер

76

Используйте символ not ( ^):

.*[^a]$

Если поставить ^символ в начале скобок, это означает «все, кроме вещей в скобках». $это просто якорь до конца.

Для нескольких символов просто поместите их все в их собственный набор символов:

.*[^a][^b]$

1
+1, с оговоркой, что это не совпадает с пустой строкой (которая может или не может быть, как предполагалось), поэтому значение скорее "любой символ, который не в скобках".
Фред Фу

3
@ 0A0D: строка, содержащая пробел, не является пустой строкой.
Фред Фу

7
@ 0A0D На самом деле, это не подлежит обсуждению, это факт
tckmn

8
@ Doorknob: это не соответствует aeили cb.
Фред Фу

1
Нет, это также не позволило бы "acb".
Менно

49

Для поиска файлов, не заканчивающихся на «.tmp», мы используем следующее регулярное выражение:

^(?!.*[.]tmp$).*$

Протестировано с Regex Tester дает следующий результат:

введите описание изображения здесь


1
Это интересно, есть идеи, почему это работает, а почему ^.*(?![.]tmp$)нет?
Лукаш Зарода

4
Ваше раннее .*уже соответствует всей строке, поэтому оставшееся исключение больше не работает.
пятнадцать

Для моих целей это сработало, а другие ответы - нет. Спасибо!
Дэвид Мориц

8
.*[^a]$

приведенное выше регулярное выражение будет соответствовать строкам, которые не заканчиваются на a.


Я расширил свой вопрос, так как исходный пример не полностью соответствовал моему случаю. Вы можете решить это?
Менно

5

Попробуй это

/.*[^a]$/

[]Обозначает класс символов, и ^инвертирует символьный класс , чтобы соответствовать все но a.


1

Вопрос старый, но я не смог найти лучшего решения, которое я разместил здесь. Найдите все USB-накопители, но не перечислите разделы , удалив, таким образом, «part [0-9]» из результатов. Я сделал два grep, последний сводит на нет результат:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

Это приводит к моей системе:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Если бы я только хотел разделы, которые я мог бы сделать:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

Где я получаю:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

И когда я делаю:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Я получил:

/dev/sdb

1

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

Если мы посмотрим на широко предложенное регулярное выражение для этого вопроса:

.*[^a]$

Мы обнаружим, что это почти работает. Он не принимает пустую строку, что может быть немного неудобно. Тем не менее, это незначительная проблема при работе только с одним персонажем. Однако, если мы хотим исключить всю строку, например, «abc», то:

.*[^a][^b][^c]$

не буду делать Например, он не примет переменную.

Хотя есть простое решение этой проблемы. Мы можем просто сказать:

.{,2}$|.*[^a][^b][^c]$

или более обобщенная версия:

.{,n-1}$|.*[^firstchar][^secondchar]$ где п длина строки , которую вы хотите запретить (для abcего 3), и firstchar, secondchar... есть первый, второй ... степени п символов вашей строки (для abcнего будет a, то b, тогда c).

Это вытекает из простого наблюдения, что строка, которая короче, чем текст, который мы не запрещаем, не может содержать этот текст по определению. Таким образом, мы можем либо принять все, что короче («ab» не «abc»), либо что-нибудь достаточно длинное, чтобы мы могли это принять, но без окончания.

Вот пример поиска, который удалит все файлы, которые не являются .jpg:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$не соответствуетccc
psalaets

0

Все, что соответствует чему-то, заканчивающемуся на --- .*a$Итак, когда вы соответствуете регулярному выражению, отмените условие или, в качестве альтернативы, вы также можете сделать, .*[^a]$где [^a]означает все, чтоnot a


0

Если вы используете grepили sedсинтаксис будет немного другим. Обратите внимание, что последовательный [^a][^b]метод здесь не работает:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW, я нахожу те же результаты в Regex101 , который я думаю, это синтаксис JavaScript.

Плохо: https://regex101.com/r/MJGAmX/2
Хорошо: https://regex101.com/r/LzrIBu/2

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.