【问题标题】:How to fix a BBcode regular expression如何修复 BBcode 正则表达式
【发布时间】:2011-08-10 21:52:41
【问题描述】:

我有一个抓取 BBcode 标签的正则表达式。它工作得很好,除了一个小故障。

这是当前的表达式:

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

这是它成功匹配的一些文本以及它构建的组:

[url=http://www.google.com]Go 到谷歌![/url]
1:网址
2:http://www.google.com
3:去谷歌!

[img]http://www.somesite.com/someimage.jpg[/img]
1:图片
2:空
3:http://www.somesite.com/someimage.jpg

[quote][quote]第一个嵌套引用[/quote][quote]第二个嵌套引用[/quote][/quote]
1:报价
2:空
3:[quote]第一个嵌套引用[/quote][quote]第二个嵌套引用[/quote]

这一切都很棒。我可以通过对同一个正则表达式运行第三个匹配组来处理嵌套标签,并递归处理所有嵌套标签。问题在于使用 [quote] 标签的示例。请注意,第三个匹配组是一组两个引号标签,因此我们期望两个匹配项。但是,我们得到一个匹配,如下所示:

[quote]第一个嵌套引用[/quote][quote]第二个嵌套引用[/quote]
1:报价
2:空
3:第一个嵌套引用[/quote][quote]第二个嵌套引用

啊啊啊!这根本不是我们想要的。有一个相当简单的方法来修复它,我从这个修改正则表达式:

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

到这里:

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

通过添加((?!\[/\1\]).),如果第三个匹配组包含结束 BBcode 标记,我们会使整个匹配无效。所以现在这行得通,我们得到了两个匹配项:

[quote]第一个嵌套引用[/quote][quote]第二个嵌套引用[/quote]

[quote]第一个嵌套引用[/quote]
1:报价
2:空
3:第一个嵌套引用

[quote]第二个嵌套引用[/quote]
1:报价
2:空 3:第二个嵌套引用

我很高兴修复了它,但现在我们遇到了另一个问题。这个新的正则表达式在我们将两个引号标签嵌套在一个更大的引号标签下的第一个上失败了。我们得到两个匹配而不是一个:

[quote][quote]第一个嵌套引用[/quote][quote]第二个嵌套引用[/quote][/quote]

[quote][quote]第一个嵌套引用[/quote]
1:报价
2:空
3: [quote]第一个嵌套引用

[quote]第二个嵌套引用[/quote]
1:报价
2:空
3:第二个嵌套引用

第一个匹配完全错误,第二个匹配虽然格式良好,但不是理想的匹配。我们想要一个大匹配,第三个匹配组是两个嵌套的引号标签,就像我们使用第一个表达式时一样。

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

【问题讨论】:

    标签: c# .net regex regex-negation recursive-regex


    【解决方案1】:

    使用balancing groups,您可以像这样构造一个正则表达式:

    (?>
      \[ (?<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)

    【讨论】:

    • 不错。您可以稍微简化它并消除一些嵌套量词:ideone.com/AXzxW。如果您不介意在标签之间捕获空格和单词,您可以进一步简化它:ideone.com/82lLX。是的,我喜欢平衡小组。
    • 你的第一个链接是什么?您粘贴了我的原始链接。您的第二个示例(即使它没有捕获所需的部分)是一种构造它的好方法。是的,平衡组是一个不错的功能。
    • 哦,对不起。应该是这个:ideone.com/cvlNM 至于第二个 - 诚然还有改进的余地。一开始一个简单的(?=\[) 就足以仅捕获标签,还可以添加一些组来捕获其他标签的名称和内容 - .Net 允许对其捕获进行微调。
    • Kobi,+1,更好的写作方式。如果您不介意,我会将其包含在答案中。 :-)
    • @Alex,通读手册了解每个功能。尽管如此,我认为 .NET 正则表达式的唯一特别之处是这些平衡组(捕获堆叠)(以及缺少一些功能)。我看到 Kobi 在他的博客上有一些很好的平衡组示例,您可以查看。我想“掌握正则表达式”也可能是一本好书。
    猜你喜欢
    • 2013-07-04
    • 1970-01-01
    • 2015-04-24
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2011-03-17
    • 1970-01-01
    相关资源
    最近更新 更多