正则表达式――详细讲解平衡组
这篇文章适合你吗? 要读懂这篇文章的精髓,你最好要有一点正则匹配原理的基础。比如".*?"匹配文本内容"asp163",稍懂正则表达式的人都知道可以匹配,但是你知道他的匹配过程吗?如果你不太清楚,那么下面的内容,对你来说可能不太适合,或许,看的太吃力且无法领悟平衡组的用法。因此,我建议你先了解正则表达式NFA引擎的匹配原理。想要整理一份易懂易描述的话,的确要费些时间,但不知道这篇内容会不会达到我预期的效果。慢慢完善吧~(注:这是我2010年写的,现在拿过来,有时间将自己做为读者来看本篇文章,修改有问题的地方,并增加些实例,尽量做到通俗易懂。) 一般正则教程中对平衡组的介绍 如果想要匹配可嵌套的层次性结构的话,就得使用平衡组了。举个例子吧,如何把“xx <aa <bbb> <bbb> aa> yy”这样的字符串里,最长的尖括号内的内容捕获出来? 这里需要用到以下的语法构造: 如果你不是一个程序员(或者你是一个对堆栈的概念不熟的程序员),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个(或再写一个)"group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配no部分。 < #最外层的左括号 [^<>]* #最外层的左括号后面的不是括号的内容 ( ( (?'Open'<) #碰到了左括号,在黑板上写一个"Open" [^<>>]* #匹配左括号后面的不是括号的内容 )+ ( (?'-Open'>) #碰到了右括号,擦掉一个"Open" [^<>]* #匹配右括号后面不是括号的内容 )+ )* (?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果有,则匹配失败 > #最外层的右括号 我为什么写这篇文章 看了上面的介绍,你明白了吗?在我未理解正则表达式匹配原理之前,看上面对于平衡组的介绍,似懂非懂,且只能当做模板记住,而不能灵活运用。因此查阅大量有关正则方面的资料,这里尤其感谢lxcnn的技术文档及《精通正则表达式》这本书,让我对正则表达式有了更深入、更系统的理解,因此,在它们的基础之上,我就结合自己的学习经历做个小结,一来做为学习笔记存档,另外,如果能解决你的疑惑,也是件让人高兴的事。 平衡组的概念及作用 平衡组,故名思义,平衡即对称,主要是结合几种正则语法规则,提供对配对出现的嵌套结构的匹配。平衡组有狭义与广义两种定义,狭义平衡组指 源字符串: ( #普通字符“(” ( #分组构造,用来限定量词“*”修饰范围 (?<Open>() #命名捕获组,遇到开括弧“Open”计数加1 | #分支结构 (?<-Open>)) #狭义平衡组,遇到闭括弧“Open”计数减1 | #分支结构 [^()]+ #非括弧的其它任意字符 )* #以上子串出现0次或任意多次 (?(Open)(?!)) #判断是否还有“Open”,有则说明不配对,什么都不匹配 ) #普通闭括弧 对于一个嵌套结构而言,开始和结束标记都是确定的,对于本例开始为“(”,结束为“)”,那么接下来就是考察中间的结构,中间的字符可以划分为三类,一类是“(”,一类是“)”,其余的就是除这两个字符以外的任意字符。 那么平衡组的匹配原理就是这样的 1、先找到第一个“(”,作为匹配的开始。即上面的第1行,匹配了:a+(b*(c+d))/e+f-(g/(h-i))*j (红色显示部分) 2、在第1步以后,每匹配到一个“(”,就入栈一个Open捕获组,计数加1 3、在第1步以后,每匹配到一个“)”,就出栈最近入栈的Open捕获组,计数减1 也就是讲,上面的第一行正则“(”匹配了: 4、后面的 5、最后的“)”,作为匹配的结束 匹配过程 首先匹配第一个“(”,然后一直匹配,直到出现以下两种情况之一时,把控制权交给(?(Open)(?!)): 下面在看个例子: <table> <tr> <td id="td1"> </td> <td id="td2"> <table> <tr> <td>snhame</td> <td>f</td> </tr> </table> </td> <td></td> </tr> </table> 以上为部分的HTML代码.现在我们的问题是要提取出其<td id="td2">的<td>标签并将其删除掉,以往我们惯用的方法都是直接去取,像<tds*id="td2">[sS]+?&;/td>,不过问题出来了,我们提取到的不是我们想要的内容,而是 <td id="td2"> <table> <tr> <td>snhame</td> 原因也很简单,它和离他最近的</td>标签匹配上了,不过它不知道这个标签不是它的-_-,是不是就是?符号的原因呢,我们去掉让他无限制贪婪,可这下问题更大了,什么乱七八糟的东东它都匹配到了 <td id="td2"> <table> <tr> <td>snhame</td> <td>f</td> </tr> </td> <td></td> 这个结果也不是我们想要的。那么我就用“平衡组”来解决吧。 <tds*id="td2"[^>]*>((?<mm><td[^>]*>)+|(?<-mm></td>)|[sS])*?(?(mm)(?!))</td> 匹配的结果是 <td id="td2"> <table> <tr> <td>snhame</td> <td>f</td> </tr> </table> </td> <td></td> 这正是我们想要的 <tds*id="td2"[^>]*>((?<mm><td[^>]*>)+|(?<-mm></td>)|[sS])*(?(mm)(?!))</td> 匹配的结果是 <td id="td2"> <table> <tr> <td>snhame</td> <td>f</td> </tr> </table> </td> <td></td> 一个问题 正则表达式: ( ( (?<mm>() | (?<-mm>)) | . )*? (?(mm)(?!)) ) 匹配的结果是:(-(g/(h-i)) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |