子模式正则表达式在嵌套引号内匹配

时间:2018-01-16 14:54:39

标签: php regex preg-replace

我正在从一些旧的论坛软件升级,其中包含许多不必要的嵌套[QUOTE]标签,我想通过Regex(使用PHP preg_replace)删除它。其中大部分已经完成,但我正在努力使用以下类型。

帖子中有嵌套的引用块,但只需保留顶级[QUOTE]内容(因为一些嵌套引号的深度为3或4级)。

例如:

Here is some normal post content

[QUOTE]
This is an appropriate quote
[/QUOTE]

Here is more post content

[QUOTE]
This is a a valid quote, as it's only 1 level deep.
   [QUOTE="User 2"]
   Here's an unnecessary nested quote.
       [QUOTE]
       Here's a 3nd level unnecessary nested quote.
       [/QUOTE]
   [/QUOTE]
[/QUOTE]

Here is more post content

我想删除第二级和第三级嵌套引号,但无法弄清楚如何。

我完全对strip nested quotes提出了一些很好的建议,但我无法修改正则表达式以适合这个例子。

2 个答案:

答案 0 :(得分:2)

与您链接的正则表达式相同的限制(引号内没有其他标记),您可以使用

((?:\[QUOTE\]|\G(?!^))[^][]+)((\[QUOTE[^][]*\](?:[^][]++|(?2))++\[/QUOTE\])) 

搜索,然后$1仅替换嵌套引号。

这基本上匹配单独组中的最外层引用,并且仅匹配递归中的内部引号,因此只允许删除它们。

请参阅https://regex101.com/r/y39Xaf/2

我在外引号中添加了一个带有两个不同引号的测试用例。

((?:\[QUOTE\]|\G(?!^))[^][]+)上的细分:

  • 一切都包含在捕获组中以允许重新插入
  • (?:\[QUOTE\]|\G(?!^)匹配文字[QUOTE]或上一场比赛的结尾
  • [^][]+匹配任何普通文字

答案 1 :(得分:1)

是的,您可以使用链接答案中的相同正则表达式并将 两次 与一些编程逻辑结合使用:

<?php

$regex = '~
        (\[QUOTE[^][]*\]
        (?:[^][]++|(?1))++
        \[/QUOTE\])
        ~x';

$data = preg_replace_callback($regex, 
    function($match) use($regex) {
        return $match[0][0] . preg_replace($regex, '', substr($match[0], 1));
    },
    $your_data_string_here);

echo $data;
?>

<小时/> 这样可以得到您的示例:

Here is some normal post content

[QUOTE]
This is an appropriate quote
[/QUOTE]

Here is more post content

[QUOTE]
This is a a valid quote, as it's only 1 level deep.

[/QUOTE]

Here is more post content

<小时/> 这里的想法是匹配每个引用标记(嵌套或不嵌套),然后将相同的表达式应用于匹配的字符串,但偏移量为+1。当我们获取子字符串时,只找到下一个嵌套的[QUOTE]集,然后替换它。

demo on regex101.comon ideone.com进一步澄清了这一点。