【问题标题】:Repeated match inside match匹配内重复匹配
【发布时间】:2017-03-04 15:57:10
【问题描述】:
   $regex = '/\[b\](.*?)\[\/b\]/is';

   $string = '[b][b][b]string[/b][/b][/b]';

这只会匹配到第一个 [/b],所以如果我使用这个正则表达式将此 bbcode 转换为 HTML,我最终会得到:

string[/b][/b]

我正在使用 PHP preg_replace,我怎么能只得到 string,所以 3 个 html 粗体标签。

【问题讨论】:

  • 也许 \[(\/?)b\]<$1strong> 这不会检查匹配的配对。这将与 str_replace(array('[b]','[/b]'), array('<strong>', '</strong>') 相同
  • 你不能做不对称替换(\[(\/|)b\]<$1b>)吗?
  • 可以反复替换,直到没有其他匹配为止。
  • ideone.com/15qAsY。你可以循环运行$re = '~\[b]((?:(?!\[/?b]).)*)\[/b]~is';,直到没有匹配。
  • @Wiktor Stribiżew 这也很有用,也许我可以使用 revo 解决方案来解析用户输入,因为它删除了不必要的标签,而且转换所有配对标签看起来更简单到 HTML。

标签: php regex preg-replace preg-match


【解决方案1】:

对于这种肮脏的情况:

this [b]is [b]a[/b][/b] test [b]string[/b]

递归解决方案有效:

\[b](?:(?:(?!\[b]).)*?|(?R))*\[/b]

Live demo

PHP 代码:

$str = 'this [b]is [b]a[/b][/b] test [b]string[/b]';

echo preg_replace_callback('~\[(\w+)](?:(?:(?!\[\1]).)*?|(?R))*\[/(\1)]~', function($m) {
    return "**".preg_replace("~\[/?$m[1]]~", '', $m[0])."**";
}, $str);

输出:

this **is a** test **string**

【讨论】:

  • 在 regex101 的 Live Demo 中,如果你点击 pcre flavor,它会因为最后一个斜杠而显示 'pattern error'。可以通过反斜杠修复。谢谢。
  • 我确定您没有仔细查看我的回答中提供的现场演示。 (它已经是 PCRE 风格了)@MohaMad
  • 我知道,这是 regex101 错误!尝试点击pcre或将其更改为javascript并返回pcre,请@revo
  • 这不是错误。当您重新选择 PCRE 风格时,正则表达式分隔符只是回到默认值 (/),现在是 @
  • 我从不更改分隔符,也从不检查,谢谢@revo
【解决方案2】:

您可以使用非捕获组来扩展重复计数:

(?:\[b\])+(.*?)(?:\[\/b\])+
^^^     ^^     ^^^       ^^

demo

【讨论】:

  • 有没有办法可以处理这样的字符串:[b][b][b]string[/b]string[/b]string[/b]
  • @revo 我不确定 BBCode 是否可以提供这样的冲突,是吗?
  • @Vixxs 除了这样的输入,你还有什么结果?
  • stringstringstring 也许是不可能的。
  • @Vixxs 您想删除[b] 或替换为*
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-27
相关资源
最近更新 更多