【问题标题】:nested regex replacements (tag wrapping)嵌套的正则表达式替换(标签包装)
【发布时间】:2011-08-27 20:33:25
【问题描述】:

我需要用一堆正则表达式进行多个(嵌套)文本替换(例如,用标签 SPAN 包装所有找到的字符串以突出显示),但是......请参阅代码:

<?php

// Sample workaround code:
$html = "hello world";

$regex_array = array(
    '/world/i',
    '/hello world/i'
);

foreach ( $regex_array as $regex ) {
    if ( preg_match_all($regex, $html, $matches) ) {
        foreach ( $matches[0] as $match ) {
            $html = str_replace($match, '<span>' . $match . '</span>', $html);
        }
    }
}

print '<h4>Result:</h4>' 
. htmlentities($html, ENT_QUOTES, 'utf-8');
print '<h4>Expected result:</h4>'
. htmlentities('<span>hello <span>world</span></span>', ENT_QUOTES, 'utf-8');

结果是:

hello <span>world</span>

但预期的结果是:

<span>hello <span>world</span></span>

我该怎么做?

是的,我可以改变正则表达式规则的顺序,它可以解决问题,但我真的做不到!

【问题讨论】:

  • 为什么不能改变正则表达式的顺序?
  • 我相信你的例子是不必要的抽象。
  • @mario:是的,但我仍然相信这是可能的。
  • 好吧,那么接受我在黑暗中的选择:递归正则表达式,或匹配查找表/回调中的开关。

标签: php regex nested replace


【解决方案1】:

您应该使用preg_replace_callback 而不是preg_match_all + str_replace

function handle_matches($matches) {
    return '<span>' . $matches[0] . '</span>';
}
foreach ( $regex_array as $regex ) {
    $html = preg_replace_callback($regex, 'handle_matches', $html);
}

或使用 PHP5.3:

foreach ( $regex_array as $regex ) {
    $html = preg_replace_callback($regex, function($matches) {
        return '<span>' . $matches[0] . '</span>';
    }, $html);
}

对于标签顺序问题,没有真正的解决方案是你不能改变那里的顺序或修改它们。

【讨论】:

  • $matchhandle_matches 中未定义。 $matches 是某种数组/哈希,所以看起来不像是错字。