如何将数组中带有模式的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。我试图放在替换字符串的开头或每个数组元素之前。两者都失败了。我被困了两天了。任何人都可以帮我解决这个问题吗?

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

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); }

非常感谢大家!

仅当搜索字符串只有一个替换时(当要替换的preg_replace()的调用的参数$replacement是字符串而不是数组时(,才可以使用搜索字符串数组调用preg_replace_callback()。这是因为提供给回调的参数不包含有关哪个搜索字符串生成了调用回调的匹配项的任何信息。

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

回调函数接收匹配数组作为参数(接收时由 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,
);

如果有许多搜索/替换对,则可以将搜索与替换函数一起组织到一个列表中(并为每个方案使用单独的回调(。代码这样更干净:

// 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
    );
}

每个匹配项使用相同的回调,因此您只能像这样提供一个回调 -

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数组模式和替换

嗨,

大卫和杰苏伊斯查理,

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

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);
}

这实际上是我以前的尝试之一。似乎行不通。