[Moscow.pm] perlre & backtracking

Сергей Мартынов sergey на martynov.info
Вт Сен 30 10:29:47 PDT 2008


> Требуется помощь.
> Делаю регексп, который выбирает N символов, причём HTML entitie должно
> считаться за 1 символ.
>
> print 'оx' =~ /(?>&#[0-9]+;|\S){3}/;
> мачиться успешно, хотя "символа" всего 2.
>
> Подскажите, где я неправ?

Происходит так:

1. регексп применяется к началу строки:
1.1. &#[0-9]+; схватывает entity
1.2. &#[0-9]+; не подходит для x, поэтому \S хватает x
1.3. строка кончилась, для третьего применения скобок места нет -
значит регексп не сматчился

2. регексп-машина продолжает искать матч - сдвигается на один символ
(матчим строку #1086;x)
2.1. &#[0-9]+; не подходит для #, поэтому \S хватает #
2.2. ... дальше понятно

То есть дело в том, что (?>) конечно не бэктрекится, но сам регексп
ищет матч, сдвигаясь по всей строке


Чтобы добиться желаемого результата, надо запретить ему сдвигаться -
как-то привязать начало регекспа. Например, если мы всегда матчим
целую строку - можно привязать к началу строки:

/^(?>&#\d+;|\S){3}/

Если ищем длинные "слова" в тексте - привязываем к "границе слова" -
пробелу или началу строки:

/(^|(?<=\s))(?>&#\d+;|\S){3}/


-- 
С уважением, Сергей Мартынов.


Подробная информация о списке рассылки Moscow-pm