Ошибка не очевидна, но вполне обычна: «общий» шаблон сопоставления жадных точек сопровождается рядом необязательных подшаблонов (шаблонов, которые могут соответствовать пустой строке).
Шаблон \..*\/.*\/([^\/?]*)\/?$
соответствует следующему: \..*
соответствует .
, а затем любые 0+ символов, как можно больше, затем начинается обратное отслеживание для \/
, чтобы соответствовать /
, то естьсамый правый /
в строке (последний), затем .*\/
снова сопоставляет любые 0+ символов как можно больше, а затем заставляет двигатель вернуться назад еще больше и вынуждает его отказаться от ранее найденного /
и выполнить повторное сопоставление/
, который стоит перед другим правым /
в строке.Затем, наконец, наступает ([^\/?]*)\/?$
, но предыдущий .*\/
уже сопоставлен в URL с /
в конце, а индекс регулярного выражения находится в конце строки.Таким образом, поскольку ([^\/?]*)
может соответствовать 0+ символов, отличных от ?
, а /
и \/?
могут соответствовать 0 /
символов, они оба соответствуют пустым строкам в конце строки, и $
вызывает егодень, и механизм регулярных выражений возвращает действительное совпадение с пустым значением в группе 1.
Чтобы избавиться от жадных точек, используйте
'~([^\/?]+)\/?$~'
См. демонстрационную версию regex
Подробности
([^\/?]+)
- Группа захвата 1: один или несколько символов, отличных от ?
и /
\/?
- 1 или 0 /
символов $
- в конце строки.