У меня возникли проблемы с регулярным выражением в PHP, которое использует потенциально пустую обратную ссылку. Я надеялся, что это будет работать, как описано в http://www.regular-expressions.info/brackets.html:
Если обратная ссылка не использовалась в конкретной попытке сопоставления (например, в первом примере, где вопросительный знак делал первую обратную ссылку необязательной), она просто пуста. Использование пустой обратной ссылки в регулярном выражении совершенно нормально. Его просто заменит ничто.
Однако кажется, что PHP немного отличается... от http://php.net/manual/en/regexp.reference.back-references.php:
Если подшаблон фактически не использовался в конкретном совпадении, то любые обратные ссылки на него всегда терпят неудачу.
В качестве упрощенного примера я хочу сопоставить следующие две вещи с этим регулярным выражением:
- {что-то что-то}
- {что-то:еще} ... {/что-то:еще}
Где «что-то» известно заранее, а «остальное» может быть чем угодно (или ничем).
поэтому я попробовал следующее регулярное выражение («иначе» жестко закодировано для простоты):
preg_match("/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is", $data, $matches)
К сожалению, если (:else)? не совпадает, обратная ссылка \2 не работает. Если я сделаю \2 необязательным (\2?), то я могу сопоставить {что-то} ... {что-то: еще}, что нехорошо.
Столкнулся ли я с ограничением регулярных выражений (пресловутое «вам нужен парсер, а не регулярное выражение») или это поправимо?
Программа испытаний:
<?php
$data = "{something} ... {/something}
{something:else} ... {/something:else}
{something:else} ... {/something}";
// won't match {something} ... {/something}
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/something\\2\}/is", $data, $matches);
print_r($matches);
// change \\2 to \\2? and it matches too much
preg_match_all("/\{(something(:else)?)\}(.*?)\{\/something\\2?\}/is", $data, $matches);
print_r($matches);
?>