Использование разных имен для подшаблонов одного и того же номера с preg_replace_callback
Мне трудно разобраться, что именно пронумеровано в моем regex
подмаски. Мне дают PHP
предупреждение:
PHP Warning: preg_replace_callback(): Compilation failed: different names for subpatterns of the same number are not allowed
При попытке сделать следующее:
$input = "A string that contains [link-ssec-34] and a [i]word[/i] here";
$matchLink = "\[link-ssec-(0?[1-9]|[1-9][0-9]|100)\]";
$matchItalic = "\[i](.+)\[\/i]";
$output = preg_replace_callback(
"/(?|(?<link>$matchLink)|(?<italic>$matchItalic))/",
function($m) {
if(isset($m['link'])){
$matchedLink = substr($m['link'][0], 1, -1);
//error_log('m is: ' . $matchedLink);
$linkIDExplode = explode("-",$matchedLink);
$linkHTML = createSubSectionLink($linkIDExplode[2]);
return $linkHTML;
} else if(isset($m['italic'])){
// TO DO
}
},
$input);
Если я удаляю именованные группы захвата, вот так:
"/(?|(?:$matchLink)|(?:$matchItalic))/"
Предупреждений нет, и я получаю совпадения в порядке, но не могу нацелить их условно в своей функции. Я полагаю, что следую правильной процедуре присвоения имен группам захвата, но PHP говорит, что они используют один и тот же номер подшаблона, из-за которого я теряюсь, так как не уверен, что нумеруется. Я знаком с адресацией подшаблонов с помощью $1
, $2
и т. д., но не вижу здесь соответствия при использовании с именованными группами.
Цель
Если я использую совершенно неправильную технику, я должен указать свою цель. Я изначально использовал preg_replace_callback()
заменить помеченные строки, которые соответствуют шаблону, следующим образом:
$output = preg_replace_callback(
"/\[link-ssec-(0?[1-9]|[1-9][0-9]|100)\]/",
function($m) {
$matchedLink = substr($m[0], 1, -1);
$linkIDExplode = explode("-",$matchedLink);
$linkHTML = createSubSectionLink($linkIDExplode[2]);
return $linkHTML;
},
$input);
Требование выросло до необходимости сопоставлять несколько тегов в одном и том же абзаце (Мой оригинальный пример включал следующий [i]word[/i]
, Вместо того, чтобы анализировать всю строку с нуля для каждого шаблона, я пытаюсь найти все шаблоны в одном цикле абзаца / строки, полагая, что это будет менее обременительным для системы. Изучение этого привело меня к убеждению, что использование именованных групп захвата в branch reset
был лучшим средством для нацеливания на совпадения с условными выражениями. Возможно, я иду по неправильному пути с этим, но был бы признателен, чтобы быть направленным на лучший метод.
Желаемый результат
$input = "A string that contains [link-ssec-34] and a [i]word[/i] here";
$output = "A string that contains <a href='linkfromdb.php'>Link from Database</a> and a <span class='italic'>word</span> here."
С возможностью добавления дополнительных шаблонов по мере необходимости в формате квадратных скобок, включающих слово или самодостаточных.
2 ответа
Чтобы ответить на ваш вопрос о предупреждении:
Предупреждение PHP: preg_replace_callback(): Ошибка компиляции: запрещены разные имена для подшаблонов с одинаковым номером
Ваш шаблон определяет именованные группы совпадений. Но ваш шаблон использует чередования (|
), а это означает, что целая часть шаблона не должна совпадать со всеми.
Это означает, что названный образец link
может появиться с номером совпадения 1
, но italic
также может появиться с совпадением номер 1.
Поскольку есть чередование ОБА, совпадения могут быть только с одним и тем же "номером", поэтому им разрешено иметь только одно ИМЯ:
@(?|(?<first>one)|(?<first>two))@
будет разрешено
@(?|(?<first>one)|(?<second>two))@
бросает это предупреждение.
Без полного понимания того, что я сделал (но сейчас рассмотрим это), я сделал несколько проб и ошибок в комментарии @bobblebubble и получил следующее, чтобы получить желаемый результат. Теперь я могу использовать условные операторы, предназначенные для именованных групп захвата, чтобы решить, какое действие предпринять с совпадениями.
Я изменил regex
к следующему:
$matchLink = "\[link-ssec-(0?[1-9]|[1-9][0-9]|100)\]"; // matches [link-ssec-N]
$matchItalic = "\[i](.+)\[\/i]"; // matches [i]word[/i]
$output = preg_replace_callback(
"/(?<link>$matchLink)|(?<italic>$matchItalic)/",
function($m) { etc...
Надеюсь, это также эффективный способ, с точки зрения накладных расходов, сопоставления нескольких шаблонов регулярных выражений с обратными вызовами в одной и той же строке.