首页 > 其他随笔 > Java/Js如何使用正则表达式匹配嵌套Html标签

Java/Js如何使用正则表达式匹配嵌套Html标签

其他随笔

以前写过一篇文章讲解如何使用正则表达式完美解决Html嵌套标签的匹配问题(使用正则表达式匹配嵌套Html标签),但是里头用到了平衡组这样的高级特性,貌似只有DotNet还有Perl正则引擎支持,因此通用性不高。有朋友留言说Java直接使用的话会报错。我后来查了一下,发现Java正则引擎支持的特性相对比较少。在1.6版本中不能使用命名组(貌似1.7的时候开始支持了),否则会报以下错误,更别说平衡组了。因此感觉要实现无限级的嵌套匹配不大现实。

java.util.regex.PatternSyntaxException: Look-behind group does not have an obvious maximum length near index XX

在网上搜了好久也没找到完美的解决方案。不过,我们可以实现有限级Html嵌套标签匹配。思路相对于无限级来说就简单了好多,不需要那么多高级的特性。

示例:

<div id='container'>
    <div style='background-color:gray;' id='footer'>
        <a id='gotop' href='#' onclick='MGJS.goTop();return false;'>Top</a>
        <a id='powered' href='http://wordpress.org/'>WordPress</a>
        <div id='copyright'>
            Copyright &copy; 2009 简单生活 —— Kevin Yang的博客
         </div>
        <div id='themeinfo'>
            Theme by <a href='http://www.neoease.com/'>mg12</a>. Valid <a href='http://validator.w3.org/check?uri=referer'>XHTML 1.1</a>
            and <a href='http://jigsaw.w3.org/css-validator/'>CSS 3</a>.
        </div>
    </div>
</div>

在上面这个示例中,我们打算匹配id为footer的这个嵌套div,而且假设我们预先知道footer这个div里面最多只会嵌套一级div。更多级的情况我们一会儿再讲。

footer的开始和结束标签匹配很简单:

<div [^>]*id='footer'[^>]*>......(这里的省略号是一会要填写的)</div>

夹在开始和结束标签之间的内容无非有两种情况:

  • 内容A: div标签,并且此div内无嵌套div
  • 内容B: 任意其他内容

然后就是这两种内容的不断重复而已。正则表示如下:

(<div[^>]*>.*?</div>|.)*?

注意最后面的问号必须要加上,否则由于正则的贪婪匹配特性,footer的闭合标签会匹配失误。

OK了,匹配最多嵌套一级div的正则表达式如下:

<div [^>]*id='footer'[^>]*>(<div[^>]*>.*?</div>|.)*?</div>

那么如果footer标签里头最多会嵌套两级div的话怎么办呢?

其实也不难,我们只需要把上面的“内容A”部分中的点号稍作替换即可。修改如下:

<div [^>]*id='footer'[^>]*>(<div[^>]*>(<div[^>]*>.*?</div>|.)*?</div>|.)*?</div>

到这里你可能就知道,如果要匹配最多嵌套三级div的话,正则应该怎么写了:

<div [^>]*id='footer'[^>]*>(<div[^>]*>(<div[^>]*>(<div[^>]*>.*?</div>|.)*?</div>|.)*?</div>|.)*?</div>

所以实际上,只要你的html结构不是特别复杂的话,也就是说嵌套不会很深的话,那么你完全可以使用这种方式来匹配嵌套html标签。

这个正则在Java和Javascript中都可以使用,因为它没有用到任何高级特性。

——Kevin Yang

本博客遵循CC协议2.5,即署名-非商业性使用-相同方式共享
写作很辛苦,转载请注明作者以及原文链接~
如果你喜欢我的文章,你可以订阅我的博客:-D点击订阅我的文章

  1. | #1

  2. Gray
    | #2

    博主有心了,上次留言了,这么快就给解答了,十分感谢。
    我在java下试了下,确实可行。不过如果匹配的内容超过800多汉字时,在java下容易报Exception in thread "main" java.lang.StackOverflowError的错误,一级嵌套,两级嵌套都有这个问题,三级未试。网上搜了下,有人说这是jdk的bug。但如果没有嵌套的情况下,似乎对匹配的内容长度没有限制,我试了下7万汉字都没问题。
    对于嵌套问题,似乎结合字符串查找比较容易解决。

    • Kevin Yang
      | #3

      这个就还真不清楚了,我自己也不是做java开发的,只懂皮毛而已。我稍微搜索了一下,确实好多人反应了类似的问题,但是至今未有结论。

  3. | #4

    留个脚印

  4. | #5

    低调的飘过

  5. 电脑
    | #6

    恩,不错!来了留个小脚丫,呵呵

  6. 电脑
    | #7

    创造第一高楼

  7. frank
  8. sky
    | #10

    好像有点小问题,.*?应该不能匹配空行吧、

    • Kevin Yang
      | #11

      需要设置SingleLine选项,这样点号才能匹配到换行符

  1. 暂时没有trackbacks.