【问题标题】:Remove nested quotes删除嵌套引号
【发布时间】:2013-09-12 01:50:35
【问题描述】:

我有这个文本,我正在尝试删除所有内部引号,只保留一个引用级别。引号内的文本包含任何字符,甚至换行符等。 这可以使用正则表达式还是我必须编写一个小解析器?

[quote=foo]I really like the movie. [quote=bar]World 

War Z[/quote] It's amazing![/quote]
This is my comment.
[quote]Hello, World[/quote]
This is another comment.
[quote]Bye Bye Baby[/quote]

这里是我想要的文字:

[quote=foo]I really like the movie.  It's amazing![/quote]
This is my comment.
[quote]Hello, World[/quote]
This is another comment.
[quote]Bye Bye Baby[/quote]

这是我在 PHP 中使用的正则表达式:

%\[quote\s*(=[a-zA-Z0-9\-_]*)?\](.*)\[/quote\]%si

我也尝试了这个变体,但它与 ., 不匹配,我想不出在引用中还能找到什么:

%\[quote\s*(=[a-zA-Z0-9\-_]*)?\]([\w\s]+)\[/quote\]%i

问题出在这里:

(.*)

【问题讨论】:

  • (.*) 有什么问题?不匹配新行?
  • @justhalf 问题是它不会停在正确的报价上,而是在最后一个上。
  • @andy 我会检查一下,似乎是一个可行的解决方案,我需要编写一些代码来测试它。

标签: php regex bbcode


【解决方案1】:

你可以用这个:

$result = preg_replace('~\G(?!\A)(?>(\[quote\b[^]]*](?>[^[]+|\[(?!/?quote)|(?1))*\[/quote])|(?<!\[)(?>[^[]+|\[(?!/?quote))+\K)|\[quote\b[^]]*]\K~', '', $text);

详情:

\G(?!\A)              # contiguous to a precedent match
(?>                   ## content inside "quote" tags at level 0
  (                    ## nested "quote" tags (group 1)
    \[quote\b[^]]*]
    (?>                ## content inside "quote" tags at any level
      [^[]+
     |                  # OR
      \[(?!/?quote)
     |                  # OR
      (?1)              # repeat the capture group 1 (recursive)
    )*
    \[/quote]
  )
 |
  (?<!\[)           # not preceded by an opening square bracket
  (?>              ## content that is not a quote tag
    [^[]+           # all that is not a [
   |                # OR
    \[(?!/?quote)   # a [ not followed by "quote" or "/quote"
  )+\K              # repeat 1 or more and reset the match
)
|                   # OR
\[quote\b[^]]*]\K   # "quote" tag at level 0 

【讨论】:

  • 我试过了,但它不起作用,因为它去掉了最后两个引号,而不仅仅是内部的。
  • 我能说什么?你摇滚!谢谢,这适用于任何情况。 :-)
【解决方案2】:

使用这种模式

\[quote=?[^\]]*\][^\[]*\[/quote\](?=((.(?!\[q))*)\[/)

并且什么都不替换 就像在这个example

【讨论】:

  • 这里仍然是一个问题,但一个好的开始。如果引号内有其他标签,它不起作用。例如,如果我在引号内有 [b]foo[/b]。抱歉,我没有提到在引号内我可以有任何格式的标签。
【解决方案3】:

我认为编写解析器会更容易。

使用正则表达式找到[quote][\quote],然后分析结果。

preg_match_all('#(\[quote[^]]*\]|\[\/quote\])#', $bbcode, $matches, PREG_OFFSET_CAPTURE);
$nestlevel = 0;
$cutfrom = 0;
$cut = false;
$removed = 0
foreach($matches(0) as $quote){
    if (substr($quote[0], 0, 1) == '[') $nestlevel++; else $nestlevel--;
    if (!$cut && $nestlevel == 2){ // we reached the first nested quote, start remove here
        $cut = true;
        $cutfrom = $quote[1];
    }
    if ($cut && $nestlevel == 1){ // we closed the nested quote, stop remove here
        $cut = false;
        $bbcode = substr_replace($bbcode, '', $cutfrom - $removed, $quote[1] + 8 - $removed); // strlen('[\quote]') = 8
        $removed += $quote[1] + 8 - $cutfrom;
    }
);

【讨论】:

  • 我明白了,但上面的正则表达式不匹配任何东西。
  • 抱歉,缺少一个括号。我纠正了。我也没有测试PHP代码,希望没有其他错误。
  • 是的。正则表达式最适合匹配正则语言语法,因此得名。嵌套标签不符合此标准(与您无法使用正则表达式解析 html 的原因相同)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 1970-01-01
  • 2011-05-18
  • 2020-02-14
相关资源
最近更新 更多