如何将数组中带有模式的 preg_replace 转换为 preg_replace_callback?

How to convert preg_replace with pattern in array into preg_replace_callback?

我正在尝试将我的网站从 PHP 5.4 迁移到 HHVM。我了解到 preg_replace /e 是 E_DEPRECATED 所以我尝试尽可能地转换所有出现的地方。我纠正了很多部分,但无法转换数组 中具有 模式的部分。以下是其中一个案例:

if(strpos($msglower, '[/img]') !== FALSE) {
    $message = preg_replace(array(
        "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/ies",
        "/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/ies"
    ), $allowimgcode ? array(
        "bbcodeurl('\1', '<img src=\"%s\" border=\"0\" onclick=\"zoom(this, this.src)\" onload=\"attachimg(this, \'load\')\" alt=\"\" />')",
        "bbcodeurl('\3', '<img width=\"\1\" height=\"\2\" src=\"%s\" border=\"0\" alt=\"\" />')"
    ) : array(
        "bbcodeurl('\1', '<a href=\"%s\" target=\"_blank\">%s</a>')",
        "bbcodeurl('\3', '<a href=\"%s\" target=\"_blank\">%s</a>')"
    ), $message);
}

我知道我应该使用匿名函数来转换,但我不确定 function($matchese){return XXXXXXXXXXXX;} 应该放在哪里,因为模式数组中有多个 preg_replace /e。我试图放在 REPLACEMENT 字符串的开头或每个数组元素之前。 fail.I 都被困在这两天了。谁能帮我解决这个问题?

我试图按照你的建议进行修改,在每个 return 数组中添加匿名函数块,但它会在该位置给我空内容:

if(strpos($msglower, '[/img]') !== FALSE) {
        $message = preg_replace_callback(array(
                "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
                "/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is"
        ), $allowimgcode ? function($v) {return array(
                "bbcodeurl('$v[1]', '<img src=\"%s\" border=\"0\" onclick=\"zoom(this, this.src)\" onload=\"attachimg(this, \'load\')\" alt=\"\" />')",
                "bbcodeurl('$v[3]', '<img width=\"$v[1]\" height=\"$v[2]\" src=\"%s\" border=\"0\" alt=\"\" />')"
        );} : function($v) {return array(
                "bbcodeurl('$v[1]', '<a href=\"%s\" target=\"_blank\">%s</a>')",
                "bbcodeurl('$v[3]', '<a href=\"%s\" target=\"_blank\">%s</a>')"
        );}, $message);
}

这实际上是我之前的尝试之一。好像不行。

根据axiac的提示,替换部分必须是字符串,不能是数组,我试了一下,好像可以:

if(strpos($msglower, '[/img]') !== FALSE) { $message = preg_replace_callback("/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is", $allowimgcode ? function($v) {return bbcodeurl($v[1], '<img src="%s" border="0" onclick="zoom(this, this.src)" onload="attachimg(this, \'load\')" alt="" />');} : function($v) {return bbcodeurl($v[1], '<a href="%s" target="_blank">%s</a>');}, $message); $message = preg_replace_callback("/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is", $allowimgcode ? function($v) {return bbcodeurl($v[3], "<img width=\"$v[1]\" height=\"$v[2]\" src=\"%s\" border=\"0\" alt=\"\" />");} : function($v) {return bbcodeurl($v[3], '<a href="%s" target="_blank">%s</a>');}, $message); }

非常感谢大家!

每场比赛使用相同的回调,因此您只能提供一个这样的回调 -

if(strpos($msglower, '[/img]') !== FALSE) {
    $message = preg_replace_callback(array(
        "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
        "/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is"
    ), $allowimgcode ? function ($matchese) {return "XXXX";} : 
          function($matchese) { return "XXXXX";}
    , $message);
}

(我会留给你充实替换功能)

您可以检查您获得的匹配项以确定您拥有两个匹配项中的哪一个(或者您可以将其拆分为两个单独的 preg_replace_callback 调用)。这个问题的答案有一些关于如何更容易找出你的匹配项的想法 - preg_replace_callback with array pattern and replacement

调用preg_replace_callback() with an array of search strings is possible only when there is a single replacement for them (when the parameter $replacement of the call to preg_replace()你要替换的是字符串,不是数组)。这是因为提供给回调的参数不包含任何关于哪个搜索字符串产生匹配调用回调的信息。

因为您的替换取决于搜索字符串,所以我建议您使用对 preg_replace_callback() 的新调用来进行每次替换。这样,您需要为每组 search/replacement 字符串编写单独的函数。

回调函数接收匹配数组作为参数(preg_match() 作为其第三个参数接收时填充的相同数组)。使用 use 语言构造(如文档页面上关于 anonymous functions 的第三个示例中所述,让回调了解变量 $allowimgcode:

的值
$message = preg_replace_callback(
    "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
    function (array $matches) use ($allowimgcode) {
        if ($allowimgmode) {
            return bbcode($matches[1], '<img src="%s" border="0" onclick="zoom(this, this.src)" onload="attachimg(this, \'load\')" alt="" />');
        } else {
            return bbcode($matches[1], '<a href="%s" target="_blank">%s</a>');
        }
    }
    $message,
);

如果有很多 search/replacement 对,那么您可以将搜索与替换函数一起组织到一个列表中(并为每个场景使用单独的回调)。这样代码更清晰:

// The search strings and their alternate replacements
$replacements = array(
    array(
        // The search regex
        'search' => "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
        // The callback when $allowimgcode is TRUE
        'images' => function (array $matches) {
            return bbcode($matches[1], '<img src="%s" border="0" onclick="zoom(this, this.src)" onload="attachimg(this, \'load\')" alt="" />');
        },
        // The callback when $allowimgcode is FALSE
        'noimgs' => function (array $matches) {
            return bbcode($matches[1], '<a href="%s" target="_blank">%s</a>');
        },
    ),
    array(
        'search' => "/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
        'images' => function (array $matches) {
            return bbcode($matches[3], '<img width="'.$matches[1].'" height="'.$matches[2].'" src="%s" border="0" alt="" />');
        },
        'noimgs' => function (array $matches) {
            return bbcode($matches[3], '<a href="%s" target="_blank">%s</a>');
        },
    ),
);

然后循环一个接一个地替换:

foreach ($replacements as $set) {
    $message = preg_replace_callback(
        $set['search'],
        // select the correct replacement callback depending on $allowimgcode
        $allowimgcode ? $set['images'] : $set['noimgs'], 
        $message
    );
}

嗨,David 和 JE SUIS CHARLIE,

我试图按照您的建议进行修改,在每个 return 数组中添加匿名函数块,但它会在该位置给我空内容:

if(strpos($msglower, '[/img]') !== FALSE) {
        $message = preg_replace_callback(array(
                "/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is",
                "/\[img=(\d{1,4})[x|\,](\d{1,4})\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is"
        ), $allowimgcode ? function($v) {return array(
                "bbcodeurl('$v[1]', '<img src=\"%s\" border=\"0\" onclick=\"zoom(this, this.src)\" onload=\"attachimg(this, \'load\')\" alt=\"\" />')",
                "bbcodeurl('$v[3]', '<img width=\"$v[1]\" height=\"$v[2]\" src=\"%s\" border=\"0\" alt=\"\" />')"
        );} : function($v) {return array(
                "bbcodeurl('$v[1]', '<a href=\"%s\" target=\"_blank\">%s</a>')",
                "bbcodeurl('$v[3]', '<a href=\"%s\" target=\"_blank\">%s</a>')"
        );}, $message);
}

这其实是我之前的尝试之一。好像不行。