Regex - как сопоставить все, кроме определенного шаблона


171

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


Для этого лучше всего подойдет PCRE: см. Regex Pattern to Match, за исключением случаев, когда ... / кроме случаев . Я удалил findstrтег, так как все ответы здесь недействительны для тега.
Виктор Стрибьев

Ответы:


192

Вы можете использовать прогнозное утверждение:

(?!999)\d{3}

Этот пример соответствует трем цифрам, кроме 999.


Но если у вас нет реализации регулярного выражения с этой функцией (см. Сравнение разновидностей регулярных выражений ), вам, вероятно, придется создавать регулярное выражение с основными функциями самостоятельно.

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

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

Это также соответствует любой последовательности из трех цифр, которой нет 999.


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

10
Это может быть не стандартно, но разве большинство современных языков не поддерживают это? Какой язык не поддерживает прогнозирование в эти дни?
Брайан Оукли

1
Это правда. Но большинство разновидностей регулярных выражений поддерживают эту функцию (см. < Регулярные выражения.info / refflavors.html> ).
Гамбо

1
я думаю, что последнее регулярное выражение также не будет соответствовать 009, 019 ... и т. д.
Себастьян Viereck

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
хм, да я сейчас нашел в одном из своих комментариев к постам. Я видел Regex в названии. В любом случае, если кто-то найдет этот пост при поиске того же самого для регулярного выражения, как я, возможно, это могло бы быть полезным для кого-то :) спасибо за комментарии
Aleks

15

Сопоставьте с шаблоном и используйте основной язык для инвертирования логического результата совпадения. Это будет намного более разборчивым и ремонтопригодным.


1
Тогда я просто получаю (~ A или B) вместо (A и ~ B). Это не решает мою проблему.
не

1
Псевдокод: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {...}
Бен С

Я должен был быть более ясным - части не полностью независимы. Если A соответствует части строки, мы заботимся, соответствует ли ~ B остальной части (но не обязательно всему). Это было для функции командной строки Windows findstr, которая, как я обнаружил, ограничена истинными регулярными выражениями, так что спорный вопрос.
не

8

нет, воскресение этого древнего вопроса, потому что у него было простое решение, которое не было упомянуто. (Нашел свой вопрос во время исследования квеста «Регулярное вознаграждение» .)

Я столкнулся с ситуацией, когда я должен соответствовать шаблону (A и ~ B).

Основное выражение для этого пугающе просто: B|(A)

Вы просто игнорируете общие совпадения и изучаете захваты группы 1, которые будут содержать A.

Пример (со всеми заявлениями об отказе от синтаксического анализа html в регулярных выражениях): A это цифры, B это цифры внутри <a tag

Регулярное выражение: <a.*?<\/a>|(\d+)

Демо (посмотрите на Группу 1 в нижней правой панели)

Ссылка

Как сопоставить шаблон кроме ситуаций s1, s2, s3

Как соответствовать шаблону, если ...


Это звучит слишком хорошо, чтобы быть правдой! К сожалению, это решение не универсально, и оно терпит неудачу в Emacs, даже после замены \dна [[:digit:]]. В первой ссылке упоминается, что она специфична для Perl и PHP: «Существует вариант с использованием синтаксиса, специфичного для Perl и PHP, который выполняет то же самое».
Мигельморин

4

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


2
Если бы я имел дело с реальными регулярными выражениями, то все это было бы спорным. Теперь кажется, что регулярное выражение ссылается на туманное пространство соответствия шаблонов (CSG), которое поддерживает большинство языков. Так как мне нужно сопоставить (A и ~ B), нет способа удалить отрицание и все же сделать все за один шаг.
не

Lookahead, как описано выше, сделал бы это, если бы findstr сделал что-то кроме настоящих регулярных выражений DFA. Все это немного странно, и я не знаю, почему я должен делать этот стиль командной строки (сейчас). Это просто еще один пример того, как мои руки связаны.
не

1
@ notnot: Вы используете findstr из Windows? Тогда вам просто нужно / V. Как: findstr Входной файл | findstr / v B> outputfile.txt Первая соответствует всем строкам с A, вторая соответствует всем строкам без B.
Juliano

Спасибо! Это на самом деле именно то, что мне было нужно. Я не задавал вопрос таким образом, поэтому я все же отвечал Гамбо на более обобщенный ответ.
не

1

шаблон - ре

str.split(/re/g) 

вернет все, кроме шаблона.

Тест здесь


Вы, вероятно, хотите упомянуть, что вам нужно присоединиться снова.
Томдемайт

Аналогичный подход используется replace str.replace(/re/g, ''), тогда нет необходимости возвращаться к ним. также, если вы добавите хороший трейлинг? как 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.
helicle
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.