PHP preg_match() соответствует не всем подшаблонам

#php #regex #match #preg-match

#php #регулярное выражение #соответствует #preg-match

Вопрос:

У меня есть preg_match (), который соответствует шаблону, но не получает ожидаемых совпадений (в третьем параметре).

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

 $pattern = "~^amp;multiamp;[^amp;] (amp;(?:(p-(?<sad>[1-9]d*)|page-(?<sad>[1-9]d*))))?amp;[^amp;] (amp;(?:(p-(?<gogosi>[1-9]d*)|page-(?<gogosi>[1-9]d*))))?amp;?$~J";

$string = "amp;multiamp;mickaelamp;p-23amp;georgeamp;page-34";

preg_match($pattern, $string, $matches);
  

Это то, что содержит $matches:

 Array
(
    [0] => amp;multiamp;mickaelamp;p-23amp;georgeamp;page-34
    [1] => amp;p-23
    [2] => p-23
    [sad] => 
    [3] => 23
    [4] => 
    [5] => amp;page-34
    [6] => page-34
    [gogosi] => 34
    [7] => 
    [8] => 34
)
  

Проблема в том, что [sad] должно иметь значение 23.
Если я не включу в $string вторую страницу (page-34), ’cause является необязательным […]

 $string = "amp;multiamp;mickaelamp;p-23amp;george";
  

[…] У меня есть хорошие $ совпадения, потому что мой [sad] получил его значение:

 Array
(
    [0] => amp;multiamp;mickaelamp;p-23amp;george
    [1] => amp;p-23
    [2] => p-23
    [sad] => 23
    [3] => 23
)
  

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

Что сделать, чтобы все подшаблоны имели свое значение?

Примечание: Такие слова, как (‘p’, ‘страница’), являются только примерами. Там могут быть любые слова.

Примечание: Приведенные выше данные являются всего лишь примером. Не предлагайте мне обходных решений, но что-нибудь хорошее для любых входных данных.

Ответ №1:

Вы можете использовать группу сброса ветки, (?|...|...) :

 '~^amp;multiamp;[^amp;] (amp;((?|p-(?<sad>[1-9]d*)|page-(?<sad>[1-9]d*))))?amp;[^amp;] (amp;((?|p-(?<gogosi>[1-9]d*)|page-(?<gogosi>[1-9]d*))))?amp;?$~J'
  

Смотрите демонстрацию регулярных выражений.

Смотрите демонстрацию PHP:

 $pattern = "~^amp;multiamp;[^amp;] (amp;((?|p-(?<sad>[1-9]d*)|page-(?<sad>[1-9]d*))))?amp;[^amp;] (amp;((?|p-(?<gogosi>[1-9]d*)|page-(?<gogosi>[1-9]d*))))?amp;?$~J";
$string = "amp;multiamp;mickaelamp;p-23amp;georgeamp;page-34";
if (preg_match($pattern, $string, $matches)) {
    print_r($matches);
}
  

Вывод:

 Array
(
    [0] => amp;multiamp;mickaelamp;p-23amp;georgeamp;page-34
    [1] => amp;p-23
    [2] => p-23
    [sad] => 23
    [3] => 23
    [4] => amp;page-34
    [5] => page-34
    [gogosi] => 34
    [6] => 34
)
  

Комментарии:

1. Спасибо за ваш ответ. Но такие слова, как (‘p’, ‘page’), являются только примерами. Там могут быть любые слова. Помогло бы мне найти решение для любых имен подшаблонов или входных данных. Большое спасибо.

2. @ValentinTanasescu Теперь смотрите другой ответ.

3. Большое вам спасибо. Могу ли я также спросить вас, почему четвертый параметр PREG_UNMATCHED_AS_NULL не включает в $matches несопоставимые подшаблоны с нулевым значением, как должно быть?

4. Почему они никогда не включаются, даже если так написано в документации?

5. @ValentinTanasescu Извините, я, возможно, перепутал точное поведение. Похоже, что это новая константа и, возможно, она содержит ошибки.