1

我遇到了正则表达式的问题:

$var = preg_replace("/\[doxer_quote\]([^]]+)\[\/doxer_quote\]/", '<blockquote>$1</blockquote>', $var);

我试图让它显示blockquote标签内的内容,但我无法弄清楚。它也需要经过多行。有人可以帮我吗。

4

2 回答 2

3

您的正则表达式适用于内部不包含“标签”的字符串[doxer_quote],例如:

[doxer_quote]my 
  multiline 
  text[/doxer_quote]

但它会因嵌套标签而失败,即使是单行内容,例如:

[doxer_quote]my [strong]formatted[/strong] text[/doxer_quote]

原因是你]通过这个重复的字符类匹配所有的字符:[^]]+,所以当遇到第一个嵌套标签时它会中断。

解决方案:替换[^]]+为 a .+并将-modified包含s到您的正则表达式中,即:

$var = preg_replace("/\[doxer_quote\](.+)\[\/doxer_quote\]/s", '<blockquote>$1</blockquote>', $var);

-修饰符s(称为PCRE_DOTALL)使点匹配任何字符,包括换行符。


处理嵌套元素

如果您的标记语言允许包含嵌套[doxer_quote]元素,则它不是常规的。正则表达式仅用于处理常规语言。

没有优雅的方法可以通过正则表达式匹配嵌套元素。考虑以下情况:

[doxer_quote]
  [doxer_quote]
    Lorem ipsum dolor sit amet
  [/doxer_quote]
[/doxer_quote]

consetetur sadipscing elitr

[doxer_quote]
  sed diam nonumy
[/doxer_quote]

您无法使用单个正则表达式调用来处理它。
但它可以在一个循环中完成,如下所示:

while(($var2 = preg_replace("/\[doxer_quote\]((?:(?!\[doxer_quote\]).)+?)\[\/doxer_quote\]/s", '<blockquote>$1</blockquote>', $var)) !== $var)
  $var = $var2;

分步说明:

  • .匹配任何字符

  • (?!\[doxer_quote\]).匹配任何不是序列“[doxer_quote]”开头的字符。(?!)称为负前瞻

  • (?:(?!\[doxer_quote\]).)是以上分组为非捕获子模式

  • (?:(?!\[doxer_quote\]).)+匹配重复一次或多次的子模式。

  • (?:(?!\[doxer_quote\]).)+?-重复量词?之后使量词变得懒惰(也称为非贪婪)。+

  • ((?:(?!\[doxer_quote\]).)+?)- 括号定义了一个捕获子模式$1它在替换表达式中被引用。

  • 在循环中,每一步都会替换最里面的标签。如果迭代后字符串没有改变,则循环中断。

最后的笔记

  • 如果您确定您的标记始终格式正确(例如,每个开始标记都是关闭的)并且您的标记语言的标记不包含属性等,请考虑直接替换开始标记和结束标记,而不匹配内容:

     $var = str_replace(
              array('[doxer_quote]', '[/doxer_quote]'), 
              array('<blockquote>', '</blockquote>'), 
              $var
            ); 
    

    [doxer_quote]您可以通过这种方式一步处理多个标签(不仅是)。

  • 考虑解析您的标记语言。

于 2013-05-08T21:40:55.577 回答
-1

请参阅https://stackoverflow.com/a/2101427/2277620。使用 multiline- 修饰符,但如果你让 "+" 贪心,你会得到从第一个块开始到最后一个块结束的文本。

于 2013-05-08T21:30:44.393 回答