preg_match для соответствия необязательной строке, но не для соответствия всей строке

Возьмем, к примеру, следующее соответствие регулярному выражению.

preg_match('!^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)(/page-[0-9]+)?$!', 'publisher/news/1/2010-march:03-23/test_title/1/page-1', $matches); 
print_r($matches);

Он производит следующее:

Array
(
    [0] => publisher/news/1/2010-march:03-23/test_title/1/page-1
    [1] => news
    [2] => 1
    [3] => 2010
    [4] => march
    [5] => 03
    [6] => 23
    [7] => test_title
    [8] => 1
    [9] => /page-1
)

Однако, поскольку последнее совпадение является необязательным, оно также может работать со следующим соответствием «издатель/новости/1/2010-март:03-23/test_title/1». Моя проблема в том, что я хочу иметь возможность сопоставлять (/page-[0-9]+), если он существует, но сопоставлять только номер страницы, поэтому "publisher/news/1/2010-march:03-23/test_title/ 1/page-1" будет соответствовать так:

Array
(
    [0] => publisher/news/1/2010-march:03-23/test_title/1/page-1
    [1] => news
    [2] => 1
    [3] => 2010
    [4] => march
    [5] => 03
    [6] => 23
    [7] => test_title
    [8] => 1
    [9] => 1
)

Я пробовал следующее регулярное выражение

'!^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)/?p?a?g?e?-?([0-9]+)?$!'

Это работает, однако он также будет соответствовать "publisher/news/1/2010-march:03-23/test_title/1/1". У меня нет идеи провести матч, но он не вернулся в матчах? Возможно ли это в одном регулярном выражении?


person buggedcom    schedule 25.03.2010    source источник


Ответы (3)


Абсолютно не соответствовать publisher/news/1/2010-march:03-23/test_title/1/whatever

!^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)(?:/page-([0-9]+))?$!

Чтобы по-прежнему соответствовать publisher/news/1/2010-march:03-23/test_title/1/whatever, но игнорировать /whatever:

!^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)(?:(?:/page-([0-9]+))|/.*)?$!
person Matt Blaine    schedule 25.03.2010
comment
Это билет. Спасибо. Означает ли ?: совпадение, только если оно существует? - person buggedcom; 25.03.2010
comment
?: делает скобки незахватывающими. Итак, в массиве в вашем примере 0 - это вся строка, совпадающая с вашим шаблоном. 1-9 — это захваты, все, что вы завернули в () в своем паттерне. (?:) группирует /page и [0-9]+ вместе, но не захватывает их. - person Matt Blaine; 25.03.2010
comment
Мое объяснение в моем предыдущем комментарии не самое лучшее, я уверен, что вы можете найти лучшее. Не беспокойтесь об этом, я рад, что смог помочь. - person Matt Blaine; 25.03.2010
comment
Дох! После всего этого я понял, что при обратном отображении этих URL-адресов обратно из частей param в URL-адрес невозможно сделать правильно, если только не добавить всю строку /page-string к значению param, что не сработает, если регулярное выражение param было изменено с помощью пользователь. - person buggedcom; 25.03.2010

может так:

'!^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)(/page-([0-9]+))?$!'
person Mathieu    schedule 25.03.2010
comment
Нет, потому что тогда это будет соответствовать /page-1 и 1. Я хочу, чтобы он соответствовал только 1. Он используется в автоматической системе маршрутизации URL-адресов, и совпадения регулярных выражений заменяются через заполнители, поэтому любые возвращаемые совпадения должны соответствовать количество заполнителей. - person buggedcom; 25.03.2010

Это регулярное выражение, которое вы ищете:

^publisher/([A-Za-z0-9\-\_]+)/([0-9]+)/([0-9]{4})-(january|february|march|april|may|june|july|august|september|october|november|december):([0-9]{1,2})-([0-9]{1,2})/([A-Za-z0-9\-\_]+)/([0-9]+)/(?:page-(\d+))?

Вы можете проверить это в rexexbuddy. Если «страница-1» не установлена, переменная 9 останется пустой, иначе она будет установлена.

person RJD22    schedule 25.03.2010
comment
Спасибо, но Мэтт побил тебя тоже ответом. Действительно ли есть какое-то преимущество (\d+) над ([0-9]+)? - person buggedcom; 25.03.2010
comment
Я не уверен, есть ли какая-то разница в производительности. \d предназначен для цифр, а [0-9] — это просто диапазон, как вы можете использовать и [a-z]. - person RJD22; 25.03.2010