Регулярное выражение противоположно
Можно ли написать регулярное выражение, которое возвращает обратный результат? Регулярные выражения обычно включают в себя - поиск матчей. Я хочу иметь возможность преобразовать регулярное выражение в его противоположность - утверждая, что совпадений нет. Это возможно? Если да, то как?
http://zijab.blogspot.com/2008/09/finding-opposite-of-regular-expression.html утверждает, что вы должны скопировать ваше регулярное выражение с помощью
/^((?!^ MYREGEX ).)*$/
но это, похоже, не работает. Если у меня есть регулярное выражение
/[a|b]./
строка "abc" возвращает false как с моим регулярным выражением, так и с обратным, предложенным zijab,
/^((?!^[a|b].).)*$/
. Можно ли написать регулярное выражение, или я неправильно думаю?
Ответы
Ответ 1
Причина, по которой ваше инвертированное регулярное выражение не работает, происходит из-за "^
" внутри отрицательного вида:
/^((?!^[ab].).)*$/
^ # WRONG
Может быть, он отличается от vim, но в любом регулярном выражении, с которым я знаком, карет соответствует началу строки (или началу строки в многострочном режиме). Но я думаю, что это была опечатка в блоге.
Вам также необходимо учитывать семантику используемого инструмента регулярного выражения. Например, в Perl это верно:
"abc" =~ /[ab]./
Но в Java это не так:
"abc".matches("[ab].")
Это потому, что регулярное выражение, переданное методу matches()
, неявно закреплено на обоих концах (т.е. /^[ab].$/
).
Взяв более распространенную семантику Perl, /[ab]./
означает, что целевая строка содержит последовательность, состоящую из "a" или "b", за которой следует, по меньшей мере, один символ (нестрочный разделитель). Другими словами, в ЛЮБОЙ точке условие TRUE. Обратное к этому утверждению: в КАЖДОЙ точке условие FALSE. Это означает, что перед тем, как вы будете потреблять каждый символ, вы выполняете отрицательный просмотр, чтобы подтвердить, что символ не является началом соответствующей последовательности:
(?![ab].).
И вам нужно изучить каждый символ, поэтому регулярное выражение должно быть привязано с обоих концов:
/^(?:(?![ab].).)*$/
Это общая идея, но я не думаю, что можно инвертировать каждое регулярное выражение, а не когда исходные регулярные выражения могут включать в себя положительные и отрицательные образы, неохотные и притяжательные кванторы, а кто-знает-что.
Ответ 2
Не могли бы вы просто проверить, нет ли совпадений? Я не знаю, какой язык вы используете, но как насчет этого псевдокода?
if (!'Some String'.match(someRegularExpression))
// do something...
Если вы можете изменить только регулярное выражение, то тот, который вы получили из вашей ссылки, должен работать:
/^((?!REGULAR_EXPRESSION_HERE).)*$/
Ответ 3
Вы можете инвертировать набор символов, написав ^
в начале ([^…]
). Таким образом, противоположное выражение [ab]
(соответствует либо a
, либо b
) равно [^ab]
(не соответствует ни a
, ни b
).
Но чем сложнее ваше выражение, тем сложнее дополнительное выражение. Пример:
Вы хотите совместить литерал foo
. Выражение, которое соответствует любому другому, кроме строки, содержащей foo
, должно соответствовать либо
- любая строка, длина которой меньше
foo
(^.{0,2}$
), или
- любая длинная строка из трех символов, а не
foo
(^([^f]..|f[^o].|fo[^o])$
), или
- любая строка, не содержащая
foo
.
Все это может сработать:
^[^fo]*(f+($|[^o]|o($|[^fo]*)))*$
Но обратите внимание: это относится только к foo
.
Ответ 4
Вы также можете сделать это (в python) с помощью re.split
и расщепления на основе вашего регулярного выражения, возвращая тем самым все части, которые не соответствуют регулярному выражению как найти обратное выражение регулярного выражения
Ответ 5
В perl вы можете противодействовать с помощью $string !~ /regex/;
.
Ответ 6
С помощью grep вы можете использовать --invert-match
или -v
.
Ответ 7
Java Regexps имеют интересный способ сделать это (можно протестировать здесь), где вы можете создать жадное дополнительное совпадение для нужной строки, а затем сопоставить данные после него. Если жадное совпадение терпит неудачу, оно необязательно, так что это не имеет значения, если он преуспевает, ему нужны дополнительные данные для соответствия второму выражению и поэтому не удается.
Он выглядит контр-интуитивным, но работает.
Например, (foo)?+.+
соответствует bar
, foox
и xfoo
, но не соответствует foo
(или пустой строке).
Возможно, это возможно и на других диалектах, но не может заставить его работать самостоятельно (они, похоже, больше желают отступить, если второе совпадение не получится?)