Regex для рядка, що не закінчується заданим суфіксом


190

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

Це відповідає

b
ab
1

Це не відповідає

a
ba

Я знаю, що регулярний вираз повинен закінчуватися, $щоб позначити кінець, хоча я не знаю, що повинно передувати це.

Редагувати : оригінальне запитання, мабуть, не є законним прикладом для моєї справи. Отже: як обробити більше одного персонажа? Скажіть, що не закінчується ab?

Я зміг виправити це за допомогою цієї теми :

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

Незважаючи на те, що недолік цього полягає в тому, що він не відповідає рядку з одного символу.


5
Це не дублікат зв'язаного питання - відповідність лише кінця вимагає іншого синтаксису, ніж збігання будь-якого місця в рядку. Подивіться тут верхню відповідь.
jaustin

Я згоден, це не дублікат зв'язаного питання. Цікаво, як ми можемо зняти вищевказані «позначки»?
Алан Кабрера

Немає такого посилання, яке я бачу.
Алан Кабрера

Відповіді:


252

Ви не даєте нам мови, але якщо ваша підтримка аромату регулярного виду заступається за твердженням , це те, що вам потрібно:

.*(?<!a)$

(?<!a)- це заперечений вигляд за твердженням, яке гарантує, що перед закінченням рядка (або рядка з mмодифікатором) не буде символу "a".

Дивіться це тут на Regexr

Ви також можете легко розширити це за допомогою інших символів, оскільки ця перевірка рядка і не є класом символів.

.*(?<!ab)$

Це відповідало б тому, що не закінчується на "ab", дивіться це на Regexr


1
Я не знаю RegexPAL, але регулярні вирази є різними на всіх мовах, а заперечення тверджень - це вдосконалена функція, яка підтримується не всіма.
стема

7
regexpal - тестер regex, заснований на JavaScript, і javascript не підтримує погляд за твердженнями, яке сумно
HamZa

Lookbehinds не підтримуються в regexr (javascript)
Stealth Rabbi

1
Відсутність поглядів в JS змушує мене плакати. Якщо ви працюєте на сервері, хоча ви, ймовірно, можете використовувати модуль PCRE на NPM або подібний, щоб використовувати їх безпосередньо (це набір прив’язок, тому я не думаю, що ви можете використовувати його на передній частині)
Ейрік Біркеланд,

Більше типів пошуку / твердження за твердженнями: 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 дає наступний результат:

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


1
Це цікаво, будь-яка ідея, чому це працює, а чому ^.*(?![.]tmp$)ні?
Łukasz Zaroda

4
Ваша рання .*вже відповідає цілому рядку, тому решта виключення більше не працює.
П'ятьО

Для моїх цілей це спрацювало, а інші відповіді не відповіли. Дякую!
Девід Моріц

8
.*[^a]$

Регекс вище буде відповідати рядкам, на яких не закінчується a.


Я продовжив своє запитання, оскільки початковий приклад, здавалося, не повністю відповідав моєму випадку. Ви можете це вирішити?
Менно

5

Спробуйте це

/.*[^a]$/

[]Позначає клас символів, і ^інвертує символьний клас , щоб відповідати все але a.


1

Питання старе, але я не зміг знайти кращого рішення, який я розміщую тут. Знайдіть усі USB-накопичувачі, але не перераховуючи розділи , тим самим видаляючи "частину [0-9]" з результатів. У кінцевому підсумку я робив два грепи, останній заперечує результат:

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.