Регулярное выражение для операции "И НЕ" - PullRequest
24 голосов
/ 26 сентября 2011

Я ищу общую конструкцию регулярного выражения, чтобы соответствовать всему в шаблоне x, ИСКЛЮЧИТЬ совпадения с шаблоном y. Это трудно объяснить как полностью, так и кратко ... формальное определение см. Материальная неявность .

Например, сопоставить любой символ слова (\w), КРОМЕ «p». Обратите внимание, что я вычитаю небольшой набор (буква «р») из большего набора (все символы слова). Я не могу просто сказать [^p], потому что это не учитывает больший ограничивающий набор только символов слова. Конечно, для этого небольшого примера я мог бы вручную реконструировать что-то вроде [a-oq-zA-OQ-Z0-9_], что было бы больно, но выполнимо. Но я ищу более общую конструкцию, чтобы по крайней мере большой положительный набор мог быть более сложным выражением. Как и в случае совпадения ((?<=(so|me|^))big(com?pl{1,3}ex([pA]t{2}ern), за исключением случаев, когда оно начинается с «My».

Редактировать : Я понимаю, что это был плохой пример, так как исключение вещей в начале или в конце - это ситуация, когда работают отрицательные прогнозные выражения и прогнозные выражения. (Богемный, я все же дал вам голос за иллюстрацию). Итак ... как насчет исключения совпадений, которые содержат "My" где-то посередине? ... Я все еще действительно ищу общую конструкцию, подобную регулярному выражению, эквивалентному следующему псевдо-sql

select [captures] from [input]
where (
    input MATCHES [pattern1]
    AND NOT capture MATCHES [pattern2]
)

Если есть ответ «его не существует, и вот почему ...», я бы тоже хотел это знать.

Редактировать 2 : Если бы я хотел определить свою собственную функцию, чтобы сделать это, это было бы что-то вроде (вот версия C # LINQ):

public static Match[] RegexMNI(string input, 
                               string positivePattern, 
                               string negativePattern) {
    return (from Match m in Regex.Matches(input, positivePattern)
            where !Regex.IsMatch(m.Value, negativePattern)
            select m).ToArray();
}

Я ВСЕГДА просто задаюсь вопросом, есть ли нативная конструкция регулярного выражения, которая могла бы сделать это.

Ответы [ 4 ]

19 голосов
/ 26 сентября 2011

Это будет соответствовать любому символу, который является словом и не a p:

((?=[^p])\w)

Чтобы решить ваш пример, используйте отрицательный взгляд-перед "My" в любом месте ввода, то есть (?!.*My):

^(?!.*My)((?<=(so|me|^))big(com?pl{1,3}ex([pA]t{2}ern)

Обратите внимание на привязку к началу ввода ^, которая необходима для его работы.

15 голосов
/ 26 сентября 2011

Интересно, почему люди пытаются делать сложные вещи в больших монолитных регулярных выражениях?

Почему вы не можете просто разбить проблему на части, а затем сделать действительно простые регулярные выражения для сопоставления с ними по отдельности? В этом случае сначала соответствует \w, а затем [^p], если первое совпадение прошло успешно. Perl (и другие языки) позволяет создавать действительно сложные на вид регулярные выражения, которые позволяют вам делать именно то, что вам нужно, в одном большом blobby-регулярном выражении (или, как это может быть хорошо, с коротким и быстрым крипто-регулярным выражением) , но ради того, кому нужно читать (и поддерживать!) код после того, как вы ушли, вам необходимо полностью документировать его. Лучше, чтобы было проще понять с самого начала.

Извините, разглагольствовал.

5 голосов
/ 26 сентября 2011

После ваших изменений, он по-прежнему отрицательный взгляд, но с дополнительным квантификатором.

Если вы хотите убедиться, что вся строка не содержит «My», то вы можете сделать это

(?!.*My)^.*$

См. Здесь здесь, в Regexr

Это будет соответствовать любой последовательности символов (с .* в конце), а (?!.*My).* в начале потерпит неудачу, когдагде-нибудь в строке есть «Мой».

Если вы хотите сопоставить что-либо, что не совсем «Мой», тогда используйте якоря

(?!^My$).*
1 голос
/ 13 мая 2015

Итак, просмотрев следующие темы в RegEx: просмотр, просмотр, размещение и оператор AND, рекурсия, подпрограммы, условные выражения, привязки и группы, я пришел к выводу, что решения не существует это удовлетворяет тому, что вы просите.

Причина, по которой lookahead не работает, заключается в том, что он терпит неудачу в этом относительно простом случае:

Три слова без Моего включены как одно.

Regex:

^ (?!. * My. *) (\ B \ w + \ b \ s \ b \ w + \ b \ s \ b \ w + \ b)

Матчи:

включен как один

Первые три слова не совпадают, потому что Мое происходит после них. Если «Мое» находится в конце всей строки, вы никогда не найдете ничего подходящего, потому что каждый запрос будет неудачным, потому что они все это увидят.

Проблема, как представляется, заключается в том, что, хотя lookahead имеет неявную привязку относительно того, где он начинает свое сопоставление, нет способа завершить, где lookahead завершает свой поиск с помощью привязки, основанной на результате другой части RegEx. Это означает, что вам действительно нужно продублировать все RegEx в негативном поле зрения, чтобы вручную создать нужный якорь.

Это разочарование и боль. «Решением» является использование языка сценариев для выполнения двух регулярных выражений. Один поверх другого. Я удивлен, что такого рода функциональность не лучше встроена в движки регулярных выражений.

...