Ответ 1
Прежде чем прочесть этот ответ, вы должны быть знакомы с механизмом возврата, атомных групп и притяжательных квантификаторов. Вы можете найти информацию об этих понятиях и функциях в книге Friedl и следуя этим ссылкам: www.regular-expressions.info, www.rexegg.com
Все тесты были выполнены с глобальным поиском (с функцией preg_match_all()
).
(* СБОЙ)
baabo caaco daado
caac(*FAIL)|aa.|caaco|co
[0] => aab
[1] => caaco
[2] => aad
(*FAIL)
вызывают точно такое же поведение, как "плохой символ" в шаблоне. Если вы замените его на "R", вы получите точно такой же результат: caacR|aa.|caaco|co
. Чтобы быть более общим, вы действительно можете заменить (*FAIL)
на "всегда неудачный подшаблон", например: (?!)
, (?=a(?<!a))
...
a (first from "baabo")
: Без удивления, первый результат найден вторым вариантом. (aab
)
c (first)
: механизм regex встречает первый "c" и пытается использовать первый вариант и находит: caac
, но подшаблон принудительно завершается с ошибкой. Затем механизм регулярных выражений (всегда с первого "c" ) пытается выполнить вторую альтернативу, третий вариант завершается успешно. (caaco
)
a (first from "daado")
: третий результат найден вторым вариантом. (aad
)
(* SKIP)
baabo caaco daado
caa(*SKIP)c(*FAIL)|aa.|caaco|co
[0] => aab
[1] => co
[2] => aad
Этот глагол определяет точку, за которой движению регулярных выражений не разрешается отступать, когда подшаблон позже завершится. Последствия, все символы, найденные ранее с помощью подшаблона, расходуются раз и навсегда и не могут использоваться для другой части шаблона (альтернатива).
a (first from "baabo")
: первый результат найден вторым вариантом. (aab
)
c (first)
: двигатель regex находит caac
, как в первом случае, затем не работает (причина (*FAIL)
verb), возвращается к второму "c" , но ему не разрешено возвращаться к символам, которые ранее ( "caa" ) перед глаголом (*SKIP)
. c (second)
: Теперь, механизм регулярных выражений всегда старается использовать первую альтернативу, но в этой новой позиции и терпит неудачу, так как после этого происходит "o", а не "a" , а затем возвращается к этому второму "c" . Обратите внимание, что в этом случае эти символы не расходуются, как раньше, потому что подшаблон не сработал до достижения глагола (*SKIP)
.
Вторая альтернатива протестирована и терпит неудачу (не начинается с "c" ). Третий вариант тоже не подходит, потому что следующий символ - "o", а не "a" .
Четвертый вариант преуспевает и дает второй результат. (co
)
a (first from "daado")
: третий результат найден вторым вариантом. (aad
)
(* PRUNE)
baabo caaco daado
caa(*PRUNE)c(*FAIL)|aa.|caaco|co
[0] => aab
[1] => aac
[2] => aad
Этот глагол отличается от (*SKIP)
, потому что он не запрещает использовать все предыдущие совпадающие символы, но пропускает первый согласованный символ подшаблоном (или запрещает запуск подшаблона), если подшаблон позже завершится.
a (first from "baabo")
: первый результат найден вторым вариантом. (aab
)
c (first)
: двигатель регулярных выражений найдет caac
, как в первом случае, затем завершится с ошибкой, но теперь возвращается к первому "a" из "caaco", так как первый "c" пропущен. a (first from "caaco")
: первая альтернатива испробована и терпит неудачу, вторая преуспевает и дает второй результат. (aac
)
a (first from "daado")
: третий результат найден вторым вариантом. (aad
)