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

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

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

b
ab
1

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

a
ba

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

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

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

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

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

8 ответов

Решение

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

.*(?<!a)$

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

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

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

.*(?<!ab)$

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

Использовать не (^) условное обозначение:

.*[^a]$

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

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

.*[^a][^b]$

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

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

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

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

.*[^a]$

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

Попробуй это

/.*[^a]$/

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

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

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

.*[^a]$

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

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

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

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

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

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

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

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

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

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

Вопрос старый, но я не смог найти лучшего решения, которое я разместил здесь. Найдите все 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

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

Если вы используете 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

Другие вопросы по тегам