使用preg_replace_callback

时间:2018-03-27 13:08:30

标签: php regex 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 个答案:

答案 0 :(得分:1)

如果没有完全理解我所做的事情(但现在会调查),我会对@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...

希望它在开销方面也是一种有效的方法,可以在同一个字符串中匹配多个正则表达式模式和回调。

答案 1 :(得分:1)

回答有关警告的问题:

  

PHP警告:preg_replace_callback():编译失败:不允许使用相同编号的子模式的不同名称

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

这意味着,命名模式link可以与匹配编号1一起显示,但italic也可以与匹配编号1一起显示。

由于存在替换,因此匹配只能是#34;数字&#34;,因此它们只允许具有相同的名称:

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

将被允许。

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

抛出此警告。