如何修复BBcode正则表达式

3

我有一个正则表达式可以匹配BBcode标签,它很好用,但是有一个小问题。

以下是当前的正则表达式:

\[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](.+)\[/\1\]

这是一些文本,成功匹配的内容以及它建立的组:
[url=http://www.google.com]Go to google![/url] 1:url 2:http://www.google.com 3:前往google!
[img]http://www.somesite.com/someimage.jpg[/img] 1:img 2:NULL 3:http://www.somesite.com/someimage.jpg [quote][quote]first nested quote[/quote][quote]second nested quote[/quote][/quote] 1:quote 2:NULL 3:[quote]first nested quote[/quote][quote]second nested quote[/quote]
所有这些都很好。我可以通过对第三个匹配组运行相同的正则表达式并递归处理所有嵌套的标记来处理嵌套标记。问题在于使用 [quote] 标记的示例。请注意,第三个匹配组是一组两个引用标记,因此我们期望有两个匹配项。但是,我们只得到一个匹配项,如下所示:
[quote]first nested quote[/quote][quote]second nested quote[/quote] 1:quote 2:NULL 3:first nested quote[/quote][quote]second nested quote 啊啊啊!这根本不是我们想要的。有一种相当简单的方法来解决它,我将正则表达式从以下内容修改为:
\[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](.+)\[/\1\]

转化为:

\[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](((?!\[/\1\]).)+)\[/\1\]

通过添加((?!\[/\1\]).),如果第三个匹配组包含关闭BBcode标签,则使整个匹配无效。所以现在这个正则表达式能够工作,我们得到了两个匹配结果:

[quote]first nested quote[/quote][quote]second nested quote[/quote]

[quote]first nested quote[/quote]
1: quote
2: NULL
3: first nested quote

[quote]second nested quote[/quote]
1: quote
2: NULL 3: second nested quote

我很高兴它修复了问题,但是现在我们又有了另一个问题。当我们把两个引用标签嵌套在一个更大的引用标签下时,这个新的正则表达式会失败。我们得到了两个匹配结果,而不是一个:

[quote][quote]first nested quote[/quote][quote]second nested quote[/quote][/quote]

[quote][quote]first nested quote[/quote]
1: quote
2: NULL
3: [quote]first nested quote

[quote]second nested quote[/quote]
1: quote
2: NULL
3: second nested quote

第一个匹配完全错误,第二个匹配虽然格式正确,但不是我们想要的匹配结果。我们希望得到一个大的匹配,第三个匹配组是两个嵌套的引用标签,就像我们使用第一个表达式时一样。

有什么建议吗?如果我能跨越这个障碍,我应该会有一个相当强大的BBcode表达式。

1个回答

4
使用平衡组,您可以构建如下的正则表达式:
(?>
  \[ (?<tag>[^][/=\s]+) \s*
  (?: = \s* (?<val>[^][]*) \s*)?
  ]
)

(?<content>
  (?>
    \[(?<innertag>[^][/=\s]+)[^][]*]
    |
    \[/(?<-innertag>\k<innertag>)]
    |
    [^][]+
  )*
  (?(innertag)(?!))
)

\[/\k<tag>]

根据Kobi的例子简化。


在以下内容中:
[foo=bar]baz[/foo]
[b]foo[/b]
[i][i][foo=bar]baz[/foo]foo[/i][/i]
[i][i][i][i]foo[/i][/i][/i][i][i]foo[/i][/i][/i]
[quote][quote][b][img]foo[/img][b]bold[/b][b][b]deep[/b][/b][/b][/quote]bar[quote]baz[/quote][/quote]

它找到了以下匹配项:
  • [foo=bar]baz[/foo]
  • [b]foo[/b]
  • [i][i][foo=bar]baz[/foo]foo[/i][/i]
  • [i][i][i][i]foo[/i][/i][/i][i][i]foo[/i][/i][/i]
  • [quote][quote][b][img]foo[/img][b]bold[/b][b][b]deep[/b][/b][/b][/quote]bar[quote]baz[/quote][/quote]

完整示例请参见 http://ideone.com/uULOs

(旧版本 http://ideone.com/AXzxW)


1
不错。您可以简化它并消除一些嵌套的量词:http://ideone.com/AXzxW。如果您不介意捕获标记之间的空格和单词,您甚至可以进一步简化它:http://ideone.com/82lLX。是的,我喜欢平衡组。 - Kobi
你的第一个链接是什么?你复制了我的原始链接。你的第二个例子(即使它没有捕获所需的部分)是一种很好的结构方式。而且,平衡组是一个不错的功能。 - Qtax
1
哦,抱歉。应该是这个链接:http://ideone.com/cvlNM 至于第二个 - 不可否认还有改进的空间。在开头加上简单的(?=\[)就足以仅捕获标签,并且还可以添加一些组来捕获其他标签的名称和内容 - .Net允许对其捕获进行微调。 - Kobi
1
Kobi,+1,写法好多了。如果您不介意的话,我会在答案中加入它。 :-) - Qtax
1
@Alex,请仔细阅读手册,了解每个功能。虽然我认为.NET正则表达式唯一特殊的是这些平衡组(捕获堆栈)(以及某些功能的缺失)。我看到Kobi在他的博客上有一些很好的平衡组示例,你可以查看一下。我想“精通正则表达式”也是一本不错的读物。 - Qtax
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接