Perl регулярное выражение, как отрицать часть

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

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)

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

Изменить: например, 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 ответ

Решение

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

/(?!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 есть шанс найти совпадение в любом месте строки.

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

НТН

Другие вопросы по тегам