Regex - як зіставити все, крім конкретного шаблону


171

Як записати регулярний вираз, щоб відповідати будь-якому рядку, який не відповідає конкретному шаблону? Я стикаюся з ситуацією, коли мені доводиться відповідати (A і ~ B).


PCRE було б найкраще для цього: див. Шаблон Regex для відповідності, виключаючи, коли… / За винятком між . Я видалив findstrтег, оскільки всі відповіді тут не вірні для тегу.
Wiktor Stribiżew

Відповіді:


192

Ви можете використовувати твердження наперед:

(?!999)\d{3}

Цей приклад відповідає трьом цифрам, окрім ніж 999.


Але якщо у вас не відбувається регулярної реалізації виразів з цією функцією (див. Порівняння ароматів регулярних виразів ), вам, ймовірно, доведеться самостійно будувати регулярний вираз з основними ознаками.

Сумісний регулярний вираз із базовим синтаксисом буде:

[0-8]\d\d|\d[0-8]\d|\d\d[0-8]

Це також відповідає будь-якій тризначній послідовності, яка не є 999.


1
Вперед - це не стандартний синтаксис регулярного вираження, це розширення Perl, він працюватиме лише в Perl, PCRE (Perl-Compatible RegEx) або інших нестандартних реалізаціях
Juliano

10
Це може бути не стандартним, але чи не підтримує це більшість сучасних мов? Яка мова не підтримує погляд сьогодні?
Брайан Оуклі

1
Це правда. Але більшість ароматів регулярного вираження підтримують цю функцію (див. < Regular-expressions.info/refflavors.html> ).
Gumbo

1
Я думаю, що останній регулярний вираз також не відповідатиме 009, 019 ... тощо
Себастьян Вірек,

1
Стандартний Lex для C не використовує PCRE :-(
pieman72

30

Якщо ви хочете зіставити слово A у рядку, а не відповідати слову B. Наприклад: Якщо у вас є текст:

1. I have a two pets - dog and a cat
2. I have a pet - dog

Якщо ви хочете шукати рядки тексту, у яких є собака для домашньої тварини і НЕ є кішка, ви можете використовувати цей регулярний вираз:

^(?=.*?\bdog\b)((?!cat).)*$

Він знайде лише другий рядок:

2. I have a pet - dog

Він не зміг згадати це у питанні, але ОП фактично використовує команду DOS findstr. Він надає лише крихітний набір можливостей, які ви очікуєте знайти в інструменті регулярних виразів; lookahead серед них немає. (Я щойно додав тег findstr .)
Алан Мур,

2
хм, так, я знайшов зараз в одному з його коментарів до публікацій. Я бачив Реджекс у назві. У будь-якому разі, якщо хтось знайде цю публікацію, коли шукає те саме для регулярного вираження, як я, можливо, це може комусь бути корисним :) дякую за коментарі
Алекс,

15

Зіставтеся з малюнком і використовуйте мову хосту, щоб перевернути бульний результат відповідності. Це буде набагато розбірливішим та ретельним.


1
Тоді я просто закінчую (~ A або B) замість (A і ~ B). Це не вирішує мою проблему.
notnot

1
Псевдо-код: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {...}
Ben S

Я мав би бути більш зрозумілим - п'єси не є повністю незалежними. Якщо A відповідає частині рядка, то нас хвилює, чи ~ B відповідає решті його (але не обов'язково всій справі). Це було для функції findstr командного рядка Windows, яка, як я знайшов, обмежена справжніми регулярними виразами.
notnot

8

ні, воскрешаючи це давнє питання, оскільки воно мало просте рішення, про яке не згадувалося. (Знайшли своє запитання, роблячи кілька досліджень для вишукання великого рівня .)

Я стикаюся з ситуацією, коли мені доводиться відповідати (A і ~ B).

Основний регулярний вираз для цього страхітливий: B|(A)

Ви просто ігноруєте загальні поєдинки та вивчаєте захоплення групи 1, де буде міститись А.

Приклад (з усіма запереченнями щодо розбору html у регулярному виразі): A - це цифри, B - цифри в <a tag

Регекс: <a.*?<\/a>|(\d+)

Демонстрація (подивіться групу 1 у нижній правій області)

Довідково

Як відповідати шаблону, за винятком ситуацій s1, s2, s3

Як відповідати шаблону, якщо ...


Це звучить занадто добре, щоб бути правдою! На жаль, це рішення не є універсальним і він не в Emacs, навіть після заміни \dз [[:digit:]]. Перша посилання згадує, що вона характерна для Perl та PHP: "Існує зміна, використовуючи специфічний для Perl та PHP синтаксис, який здійснює те саме"
miguelmorin

4

Доповнення звичайної мови також є звичайною мовою, але для її побудови ви повинні побудувати DFA для звичайної мови та внести будь-які дійсні зміни стану до помилок. Дивіться це для прикладу. Що сторінка не говорить, це те, що вона перетворена /(ac|bd)/в /(a[^c]?|b[^d]?|[^ab])/. Перетворення з DFA назад у звичайний вираз не є тривіальним. Простіше, якщо ви можете використовувати регулярний вираз без змін і змінити семантику в коді, як це було запропоновано раніше.


2
Якби я мав справу з фактичними виразками, то це все було б суперечливо. Тепер, схоже, Regex посилається на туманний простір CSG-ish (?) Відповідності шаблонів, який підтримує більшість мов. Оскільки мені потрібно зіставити (A і ~ B), немає ніякого способу видалити заперечення і все-таки зробити все це за один крок.
notnot

Lookahead, як описано вище, зробив би це, якби findstr зробив щось, що не відповідає справжнім регексам DFA. Вся справа наче дивна, і я не знаю, чому мені потрібно робити цей командний рядок (пакетний зараз). Це просто ще один приклад зв’язання моїх рук.
notnot

1
@notnot: Ви використовуєте findstr з Windows? Тоді вам просто потрібно / v. Як: findstr A inputfile | findstr / v B> outputfile.txt Перший відповідає всім рядкам з A, другий відповідає всім рядкам, у яких немає B.
Juliano

Дякую! Це насправді саме те, що мені було потрібно. Я не задавав питання таким чином, тому я все-таки дав відповідь Gumbo за більш узагальнену відповідь.
notnot

1

візерунок - повторно

str.split(/re/g) 

поверне все, крім візерунка.

Тестуйте тут


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

Аналогічний підхід застосовується replace str.replace(/re/g, ''), тоді не потрібно повторювати їх. також якщо ви кинете в хороший трейлінг \ s? як str.replace(/\re\s?/g, '')тоді, ви позбудетеся від будь-яких повторюваних пробілів, які б вам довелося замінити щось посеред рядка
jakecraige

0

Моя відповідь тут може також вирішити вашу проблему:

https://stackoverflow.com/a/27967674/543814

  • Замість заміни, ви б використовували Match.
  • Замість групи $1ви б читали групу $2.
  • Група $2була зроблена не захоплення там, чого ви б уникнути.

Приклад:

Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");

Перша група захоплення визначає шаблон, якого ви хочете уникати. Остання група, яка захоплює, фіксує все інше. Просто зачитати цю групу, $2.


0
(B)|(A)

тоді використовуйте те, що захоплює група 2 ...


Йому потрібно захоплювати не B, його мета - не просто ігнорувати всі B-шаблони.
hexicle
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.