Perl регулярное выражение, как отрицать часть - PullRequest
3 голосов
/ 02 февраля 2012

Я должен разделить

D= d1| d2|...|dn

и

F=f1|f2|...|fn

в данный момент я проверяю эти два регулярных выражения с помощью оператора if, который выглядит следующим образом:

if (($text_to_search =~ $D) && ($text_to_search !~ $F))

Как я могу отрицать F? Можно ли использовать отрицательный обходной путь для всего дизъюнкта или для каждого отдельного дизъюнкта F?

Я должен выглядеть так:

regexp = (d1)| (d2) | (d3)  ... (dn) | NOT (f1) | NOT (f2) | ... | Not (fn)

Скобки необходимы для отрицания шаблона, а не только первого одиночного символа, не так ли?

Edit: например, D: a|b|c|d и F: 1|2|3

теперь поведение должно быть таким:

input: "abc" --> accepted
input: "a" --> accepted
input: "abc1" --> Not accepted
input: "2" --> NOT accepted
input: "a2bc1" --> Not accepted
(input: "xyz999" --> does not match - shouldn't be accepted)

F-дизъюнкт должен быть похож на «когда видно, что во входной последовательности не совпадают»

1 Ответ

2 голосов
/ 02 февраля 2012

Да, вы можете использовать негативную перспективу.Используя ваши обозначения, мы можем построить форму такого комбинированного регулярного выражения:

/(?!F)D/

Хотя есть нюансы.Давайте рассмотрим простой пример.

my $patternD = '^(\d\d\d\d | \w\w)$';
my $patternF = 'AA | 12';

Как видите, patternD соответствует строкам, состоящим из 4 цифр или двухсимвольных символов.PatternF соответствует либо AA, либо 12.Таким образом, следующий фрагмент выводит то, что мы ожидаем.

my $str = '1121';
print "patternD matches\n" if $str =~ /$patternD/x; # patternD matches
print "patternF matches\n" if $str =~ /$patternF/x; # patternF matches

Теперь давайте создадим объединенное регулярное выражение, используя наивный подход.

my $combined = "(?!($patternF))$patternD";
print "Combined regex matches\n" if $str =~ /$combined/x; # Combined regex matches?!

Упс, у нас ложный положительный результат!(помните, наше объединенное регулярное выражение должно совпадать тогда и только тогда, когда регулярное выражение D соответствует, а F нет, но это не так).Почему это?Ответ прост.Мы создали наше объединенное регулярное выражение так, что если D совпадает в некоторой позиции, то F может совпадать только из той же позиции.В этом случае D совпадает в начале $str (альтернатива \d\d\d\d), где ни AA, ни 12 не могут совпадать.Решение простое, хотя.Мы должны дать F некоторую гибкость, добавив .* перед ним.Окончательный результат:

 my $combined = "(?!.*($patternF))$patternD";

Независимо от того, где D совпадает, у F есть шанс найти совпадение в любом месте строки.

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

HTH

...