Подтвердить что ты не робот

Регулярное выражение противоположно

Можно ли написать регулярное выражение, которое возвращает обратный результат? Регулярные выражения обычно включают в себя - поиск матчей. Я хочу иметь возможность преобразовать регулярное выражение в его противоположность - утверждая, что совпадений нет. Это возможно? Если да, то как?

http://zijab.blogspot.com/2008/09/finding-opposite-of-regular-expression.html утверждает, что вы должны скопировать ваше регулярное выражение с помощью

/^((?!^ MYREGEX ).)*$/

но это, похоже, не работает. Если у меня есть регулярное выражение

/[a|b]./

строка "abc" возвращает false как с моим регулярным выражением, так и с обратным, предложенным zijab,

/^((?!^[a|b].).)*$/

. Можно ли написать регулярное выражение, или я неправильно думаю?

4b9b3361

Ответ 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.

Ответ 5

В perl вы можете противодействовать с помощью $string !~ /regex/;.

Ответ 6

С помощью grep вы можете использовать --invert-match или -v.

Ответ 7

Java Regexps имеют интересный способ сделать это (можно протестировать здесь), где вы можете создать жадное дополнительное совпадение для нужной строки, а затем сопоставить данные после него. Если жадное совпадение терпит неудачу, оно необязательно, так что это не имеет значения, если он преуспевает, ему нужны дополнительные данные для соответствия второму выражению и поэтому не удается.

Он выглядит контр-интуитивным, но работает.

Например, (foo)?+.+ соответствует bar, foox и xfoo, но не соответствует foo (или пустой строке).

Возможно, это возможно и на других диалектах, но не может заставить его работать самостоятельно (они, похоже, больше желают отступить, если второе совпадение не получится?)