Использование разных имен для подшаблонов одного и того же номера с 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...

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

Другие вопросы по тегам