Вложенный жадный квантификатор не соответствует

Я заметил странное поведение с регулярным выражением PCRE, которое не могу объяснить. Я бы ожидал код:

preg_match('!^.+?(?:/programs/([^?#]+))?.*?$!',
    'http://example.com/programs/drive', $matches);

чтобы вернуть «диск» как совпадение 1. [^?#]+ и ? после группы без захвата являются жадными, так почему [^?#]+ не имеет приоритета и не соответствует drive? Вместо этого тестирование показало, что .+? в начале соответствует h, а .*? в конце соответствует остальной части URL.

Напротив, код:

preg_match('!^.+?(?:/programs/([^?#]+).*)?$!',
     'http://example.com/programs/drive', $matches);

работает как положено и возвращает drive как совпадение 1.


person user527388    schedule 28.05.2014    source источник
comment
@hwnd Я предполагаю, что только соответствующие URL-адреса не имеют строки запроса или хеша или только компоненты перед этими символами.   -  person Scuzzy    schedule 28.05.2014
comment
@hwnd: Нет, он соответствует нулю или одному разу, насколько это возможно. Который жаден.   -  person Amal Murali    schedule 28.05.2014


Ответы (1)


Вот что происходит. Первый .+? применяется в начале строки перед h в http. Это лениво, поэтому он сдается сразу же, и (?:/programs/([^?#]+).*)? проверяется на соответствие h. Все это выражение является необязательным, поэтому оно также сдается после неудачного совпадения в начале строки. Наконец, применяется .*?$ в конце шаблона, и это выражение может сопоставить все символы в строке для успешного совпадения.

person ridgerunner    schedule 28.05.2014
comment
+1. Вот что я подумал, увидев отладчик regex101, но мой regex-fu не был достаточно силен, чтобы быть действительно уверенным, что это было так. Одно сомнение, однако, почему (?:/programs/([^?#]+).*)? терпит неудачу? Я предполагаю, что это связано с тем, что механизм регулярных выражений, находясь в позиции h, не может найти /programs/ после нее. Или что-то еще? Кажется, это сработает, если я заменю .+? на http://example.com в выражении. - person Amal Murali; 28.05.2014
comment
Молодец, риджраннер! +1 - person zx81; 28.05.2014
comment
@Amal Murali - выражение (?:/programs/([^?#]+).*)? не работает, потому что текст, которому оно соответствует, должен начинаться с косой черты, которой нет в h в начале строки. - person ridgerunner; 28.05.2014