2015-06-18 2 views
0

В этом примере:Lookahead не работает в «не следует» регулярное выражение

jump (foo) (db); 
jump (foo); 
call(bar)(db); 

я должен соответствовать только вторую строку, содержащее уникальную jump|call|rts|rti, но не следует с (db).

/ 
(?:jump|call|rts|rti)\s* 
\(\w+\)\s* 
(?!\(db\)) # Not followed with (db) 
/xi 

https://regex101.com/r/fS2gA0/1

Где моя ошибка?

ответ

1

После того, как движок регулярных выражений соответствует последним пробельные \s* опережения является (из-за наличия (db)).

Так что же происходит после? Обратный отсчет двигателя регулярного выражения (он пытается найти другой способ добиться успеха в шаблоне). Он возвращает последние пробелы, и теперь вместо новой позиции не следует (db), а пробелом (и результат выглядит успешно).

Способ предотвращения этого является использование притяжательных кванторов, что вынуждает движок регулярных выражений, чтобы не возвращаться назад: так \s*+

demo

Вы можете ясно видеть поведение с regex101 отладчиком.

1

Ваш онлайн-тестировщик показывает, что он соответствует jump (foo), а не jump (foo). jump (foo) не следует (db). За ним следует (db), но у вашего регулярного выражения нет проблем с этим. Да, у вас есть \s* в вашем регулярном выражении, но это все еще позволяет совпадение, которое не включает пробелы.

Для решения этой проблемы вы можете перемещать (или копировать) код \s* в свой негативный прогноз.

1

Добавить точку с запятой в конце концов, здесь Perl-скрипт, который делает работу:

my $re = qr~ 
(?:jump|call|rts|rti)\s* 
\(\w+\)\s* 
(?!\(db\)) # Not followed with (db) 
; # <-- here 
~xi; 

while(<DATA>) { 
    chomp; 
    say /$re/ ? "OK: $_" : "KO: $_"; 
} 

__DATA__ 
jump (foo) (db); 
jump (foo); 
call(bar)(db); 

Выход:

KO: jump (foo) (db); 
OK: jump (foo); 
KO: call(bar)(db); 
0
\(\w+\)\s* 

может быть изменен на:

\(\w+\)\s 

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

Смежные вопросы