preg_replace_callback 对相同数字的子模式使用不同的名称

Using different names for subpatterns of the same number with 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 说他们使用相同的 子模式编号 ,这就是我迷路的地方我不确定编号是什么。我熟悉使用 </code>、<code> 等寻址子模式,但在与命名组一起使用时看不到这里的相关性。


目标

万一我使用的技术完全错误,我应该包括我的目标。我最初使用 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]。我不是为每个模式从头开始解析整个字符串,而是尝试在 paragraph/string 的单次扫描中寻找所有模式,相信它会减轻系统负担。研究它让我相信使用 命名捕获组 in a 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."

可以根据需要以包含单词或独立的方括号格式添加更多模式。

在没有完全理解我所做的事情(但现在会研究它)的情况下,我对@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...

希望这也是一种在开销方面将多个正则表达式模式与同一字符串中的回调相匹配的有效方法。

回答关于警告的问题:

PHP Warning: preg_replace_callback(): Compilation failed: different names for subpatterns of the same number are not allowed

您的模式定义了命名匹配组。但是您的模式也使用交替 (|),这意味着模式的整个部分不需要全部匹配。

这意味着,命名模式 link 可以与 match-number 1 一起出现,但 italic 也可以与 match-number 一起出现 1.

由于交替出现,因此匹配项只能相同 "number",因此它们只能具有相同的名称:

@(?|(?<first>one)|(?<first>two))@

将被允许。

@(?|(?<first>one)|(?<second>two))@

抛出此警告。