preg_match_all 对于嵌套元素

preg_match_all for nested element

这是一种BB码。知道如何匹配 [LI]text[/LI] 和 [UL]text[/UL] 等所有元素吗?

preg_match_all("/(\[UL].*\[\/UL])|(\[LI].*\[\/LI])/", '[UL][LI]sadas[/LI][/UL]', $match);

想收到类似的东西:

0 => "[UL][LI]sadas[/LI][/UL]"
1 => "[UL][LI]sadas[/LI][/UL]"
2 => "[LI]sadas[/LI]"    <--- This is not captured now.

基本上是关于:如何获得这个 [LI]text[/LI] 部分而不是松散的 [UL]text[/UL] 部分?

要做到这一点,您需要两件事:

  • 递归子模式(捕获组中引用自身的子模式)
  • 将此递归模式放入先行断言中(因为断言不消耗字符,并且使用此技巧,您可以多次匹配相同的子字符串)

~(?=(\[(\w+)]([^[]*(?:(?1)[^[]*)*?)\[/]))~

(?=...) 是先行断言。 (当前位置后接...)
(\[(\w+)]([^[]*(?:(?1)[^[]*)*?)\[/]) 是捕获组 1。
(?1) 引用捕获组 1 中的子模式。
指的是捕获组2(标签名)的匹配。

demo