Как составить сложное регулярное выражение?

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

Сразу договоримся что / это разделитель и в случайные символы не входит.

Как бы обьяснить попроще....

Есть вот такая строка:
book/<name>|[a-z]|i/<:p>|[0-9]{2,3}|i/<:id>/<!:q>|^[a-z]+$|i


Она проверяет url из браузерной строки на соответствие:

<name> - имя переменной в которую попадет часть url
<:p> - имя необязательного параметра
<!:q> - имя обязательного параметра

В чем отличие переменной от параметра?
В ссылке переменная это просто что то что между //
А параметр это кода написано так /p/значение/

В общем я нанял программиста и он написал для меня этот роутер, но толку оказалось 0.
Так как он не правильно работает и сколько я не пытался его поправить, ничего не вышло.

Решил написать грамотно с 0 и самостоятельно.

Но для начала хочу понять как в регулярных выражениях учесть не обязательный параметр.

В регулярных выражениях есть алиасы, и как раз они мне подходят.
book/(?P<name>[a-z])

Как составить регулярное выражение вида:

book/любые символы/p/любое число/id/любые символы/q/любое число


При этом p/любое число может как быть в строке так и не быть, а может быть в таком виде p//

И еще /p/любое число/ и /id/любые символы/ и /q/любое число/ могут идти в любом порядке, например так

book/любые символы/q/любое число/id/любые символы/p/любое число


:)
жесть
  • Вопрос задан
  • 2893 просмотра
Пригласить эксперта
Ответы на вопрос 2
viktorvsk
@viktorvsk
Да, жесть.
https://github.com/NoahBuscher/Macaw
symfony.com/doc/current/components/routing/introdu...

P.S. не до конца вник в то, что вы хотите реализовать. Возможно, это можно (и нужно) сделать по-другому. Но если нет, то может быть, что "очевидных" возможностей существующих роутеров не хватит. Не знаком особо с php, но в rails routing есть много разных фишек, в частности, constraints, с помощью которых можно сделать вообще что угодно. Думаю, что-то похожее должно быть и в php
Ответ написан
Комментировать
FilimoniC
@FilimoniC
$symMatch = '(?:/p/(?<Pvar>\d+|)|/id/(?<IDvar>[^/]+)|/q/(?<Qvar>\d+))'
$regm = "^book/(?<Xvar>[^/]+)$($symMatch)$($symMatch)$($symMatch)(?:/|)`$"


То есть суммарно
^book/(?<Xvar>[^/]+)(?:/p/(?<Pvar>\d+|)|/id/(?<IDvar>[^/]+)|/q/(?<Qvar>\d+))(?:/p/(?<Pvar>\d+|)|/id/(?<IDvar>[^/]+)|/q/(?<Qvar>\d+))(?:/p/(?<Pvar>\d+|)|/id/(?<IDvar>[^/]+)|/q/(?<Qvar>\d+))(?:/|)$


Более кошерно, конечно, поиграть с LookAhead и LookBehind, но тут, увы, я не помогу.
* Не матчит book/BOOK_ID_Q_noP/id/Aa12345/q/12345/p так как после P нет слешей
* Некорректно матчит, если в строке, например, два и более одинаковых тега (P\Q\id), и не хватает одного (и более) тега. Тут LookAhead\LookBehind в помощь

Проходит по строкам
book/BOOK_P_ID_Q/p/12345/id/Aa12345/q/67890
book/BOOK_Q_ID_P/q/67890/id/Aa12345/q/12345
book/BOOK_ID_P_Q/id/Zz12345/p/12345/q/12345
book/BOOK_noP_ID_Q/p//id/Aa12345/q/12345
book/BOOK_ID_Q_noP/id/Aa12345/q/12345/p//

> $Matches

Name                           Value                                                                                                                                                          
----                           -----                                                                                                                                                          
Qvar                           67890                                                                                                                                                          
Pvar                           12345                                                                                                                                                          
IDvar                          Aa12345                                                                                                                                                        
Xvar                           BOOK_P_ID_Q                                                                                                                                                    
0                              book/BOOK_P_ID_Q/p/12345/id/Aa12345/q/67890

PS> PowerShell-синтаксис RegExp (именованые выделения как (?<SelectionName>) ; без выделения - (?:)

UPD:
А вот вариант с LookBehind-ами. Избавит от "двойных" тегов.
$symMatch = '(?:(?<!.*/p/.*)/p/(?<Pvar>\d+|)|(?<!.*/id/.*)/id/(?<IDvar>[^/]+)|(?<!.*/q/.*)/q/(?<Qvar>\d+))'
$regm = "^book/(?<Xvar>[^/]+)$($symMatch)$($symMatch)$($symMatch)(?:/|)`$"


^book/(?<Xvar>[^/]+)(?:(?<!.*/p/.*)/p/(?<Pvar>\d+|)|(?<!.*/id/.*)/id/(?<IDvar>[^/]+)|(?<!.*/q/.*)/q/(?<Qvar>\d+))(?:(?<!.*/p/.*)/p/(?<Pvar>\d+|)|(?<!.*/id/.*)/id/(?<IDvar>[^/]+)|(?<!.*/q/.*)/q/(?<Qvar>\d+))(?:(?<!.*/p/.*)/p/(?<Pvar>\d+|)|(?<!.*/id/.*)/id/(?<IDvar>[^/]+)|(?<!.*/q/.*)/q/(?<Qvar>\d+))(?:/|)$

* LookBehind (?<= .... ); LookBehindNot (?<! ..... )
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы