php - 是否有可能找到与单个正则表达式重叠的匹配项?

标签 php regex pcre

这是一个执行 preg_replace 的示例多次查找嵌套/重叠的匹配项:

$text = '[foo][foo][/foo][/foo]';
//1st:   ^^^^^     ^^^^^^
//2nd:        ^^^^^      ^^^^^^
//3rd: fails

do {
    $text = preg_replace('~\[foo](.*?)\[/foo]~', '[bar]$1[/bar]', $text, -1, $replace_count);
} while ($replace_count);

echo $text; //'[bar][bar][/bar][/bar]'

我对结果和行为感到满意。但是,如上例所示,将整个字符串扫描 3 次似乎效率很低。是否有任何正则表达式魔术可以在单个替换中执行此操作?

条件:

  • 我不能简单地替换 ~\[(/)?foo]~[$1bar] ,我需要确保有一个匹配的关闭 [/foo]打开后标记 [foo]标记并一次更换它们。它们是否嵌套并不重要。未配对 [foo][/foo]不应被替换。

在 JS 中我可以设置 Regex 对象的 lastIndex属性添加到匹配的开头,以便它从上一个匹配的开头再次开始匹配。我找不到任何 startIndex在 PHP 中替换正则表达式并使用 substr() 的选项ing 也可能效率低下。我四处查看了 PCRE 是否会有“在这个位置开始下一场比赛”或类似的 anchor ,但我没有运气。

有没有更好的方法?


为了澄清未配对的标签,给定输入:

[foo][foo][/foo]

我对 [bar][foo][/bar] 都满意或 [foo][bar][/bar]作为输出。前者是遗留行为。

最佳答案

对于这种特定情况,完整的正则表达式解决方案是不可能的。

您的解决方案适用于匹配配对标签(常识):

$pattern = '~\[foo]((?>[^[]++|\[(?!/?foo]))*)\[/foo]~';
$result = $text;
do {
    $result = preg_replace($pattern, '[bar]$1[/bar]', $result, -1, $count);
} while ($count);

另一种只解析一次字符串的方法:

$arr = preg_split('~(\[/?foo])~', $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
$stack = array();
foreach ($arr as $key=>$item) {
    if ($item == '[foo]') $stack[] = $key;
    else if ($item == '[/foo]' && !empty($stack)) {
        $arr[array_pop($stack)] = '[bar]';
        $arr[$key] = '[/bar]'; 
    }
}
$result = implode($arr);

第二个脚本的性能与深度无关。

要回答标题问题,是的,可以找到与单个正则表达式重叠的匹配项,但是,您不能使用这种模式执行替换,例如:

$pattern = '~(?=(\[foo]((?>[^[]++|\[(?!/?foo)|(?1))*)\[/foo]))~';
preg_match_all($pattern, $text, $matches);

诀窍是使用前瞻和捕获组。请注意,整个匹配始终是一个空字符串,这就是为什么不能将此模式与 preg_replace 一起使用的原因。

关于php - 是否有可能找到与单个正则表达式重叠的匹配项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22121286/

相关文章:

php - Oauth2有没有Php客户端?

php - 计算页面 PHP 中的所有 HTML 标签

regex - 使用基于DFA的(线性时间)正则表达式: possible?捕获组

c++ - 在 C/C++ 中存储 PCRE 编译的正则表达式

php - PayPal guest 结帐停止在移动设备上工作

php - Magento 模块中的 Mydomain 错误

php - 条件平均值的平均值

javascript - iMacros FF Eval If Else .match .replace 正则表达式捕获组被忽略

正则表达式 (PCRE) : Match all digits conditional upon presence of a string

php - 正则表达式反向引用在 PHP PCRE 中不起作用