Регулярное выражение PCRE ведет себя по-разному при перемещении в подпрограмму

Используя PCRE v8.42, я пытаюсь абстрагировать регулярное выражение в именованную подпрограмму, но когда оно находится в подпрограмме, оно, кажется, ведет себя по-другому.

Это выводит 10/:

echo '10/' | pcregrep '(?:0?[1-9]|1[0-2])\/' 

Это ничего не выводит:

echo '10/' | pcregrep '(?(DEFINE)(?<MONTHNUM>(?:0?[1-9]|1[0-2])))(?&MONTHNUM)\/'

Разве эти два регулярных выражения не эквивалентны?


person Connor Clark    schedule 29.12.2020    source источник
comment
Правильно, вам нужно (?<MONTHNUM>(?:1[0-2]|0?[1-9]))   -  person Wiktor Stribiżew    schedule 29.12.2020


Ответы (1)


В версиях PCRE2 до 10.30 все вызовы подпрограмм всегда обрабатывается как атомарные группы. Ваше регулярное выражение (?(DEFINE)(?<MONTHNUM>(?:0?[1-9]|1[0-2])))(?&MONTHNUM)\/ на самом деле равно (?>0?[1-9]|1[0-2])\/. См. эту демонстрацию регулярного выражения, где 10/ не соответствует ожидаемому.

Совпадения нет, потому что 0?[1-9] соответствует 1 в 10/, а поскольку возврат не разрешен, вторая альтернатива не была проверена (введена), и все совпадение не удалось, поскольку после 1 нет /.

Вы должны убедиться, что более длинная альтернатива идет первой:

(?(DEFINE)(?<MONTHNUM>(?:1[0-2]|0?[1-9])))(?&MONTHNUM)/

См. демонстрацию регулярного выражения. Обратите внимание, что в шаблоне pcregrep вам не нужно экранировать /.

В качестве альтернативы вы можете использовать PCRE2 v10.30 или новее.

person Wiktor Stribiżew    schedule 29.12.2020