
从下面的HTML代码片段中匹配 到 span#test 标签内容
1 |
<span> |
首先要找到 <span id="test"> 标签 和 </span>标签 ,如果这两个不会,后面不用看了……补基础吧~~
1 |
//起始 |
我们会发现代码中夹杂着多个HTML标签,em还好,因为正则里面写死了是 span, 所以它是可以直接忽略掉的, 但是多余的 </span>会造成干扰。那么如果是在程序中,我们是怎么处理的呢? 可以使用计数器(或者说是stack结构,但是我们只需要关心里面的元素个数,所以使用计数器就行了)。从id=”test” 后面的开始处理,遇到<span> 计数+1 ,遇到 </span> 时,如果计数>0则-1否则 就匹配到了
找到#test 的span 后开始,(如果找不到这个id的span,其实可以直接结束匹配了)
var c = 0; // 初始栈
遇到<span id="span1">,入栈,栈内标签数量: c=c+1=1;
遇到<span id="span2">,入栈: c=c+1=2;
遇到虫虫后面的</span>(关闭span3) , 因为 c>0 所以c=c-1=1;
下一个</span>(关闭span1), 因为 c>0 所以所以c=c-1=0;
遇到<span id="span3">c=c+1 = 1
下一个</span>(关闭span3), 因为 c>0 所以所以c=c-1=0;
下一个</span>(关闭test),因为此时 c==0 , 所以匹配到这里结束了。
有同学会纠结<em>标签怎么办?em并不是我们要查找的标签名称,直接当普通字符串忽略掉就是了……
根据这个思路 ,我们可以使用正则表达式中平衡组的概念,首先将span定义到一个分组中,那么查找 #test 的开始标签就可以是<(?'tag'span)[^>]*id="test"[^>]*> 结束符使用反向引用 </k'tag'>
说明一下:
(?'分组名'表达式)表示将表达式匹配到的内容放入分组中。k'分组名'表示引用之前的分组。上面的例子中
(?'tag'span)表达式是span如果匹配到这四个字符的话,放进名称为tag的组中。那么后面k'tag'其实就是匹配span字符。
中间部分情况比较多:
一类是普通字符,包含类似
<em>这样的标签,直接使用([dD])一类是span的标签,我们同样,定义一个计数器 c 专门处理它:
遇到开始标签时 c+1 使用(?'c'<k'tag'[^>]*>)// 其实是将匹配到的标签推送到c组
遇到结束标签时 c-1 使用(?'-c'</k'tag'[^>]*>)// 其实是如果匹配到结束标签,从c组移除一个匹配项
上面这几个情况可以重复任意次,于是用(......)*,将它们串起来得到((?'c'<k'tag'[^>]*>)|(?'-c'</k'tag'[^>]*>)|([dD]))*
最后,加上头尾的两个标签,最终的正则表达式是:<(?'tag'span)[^>]*id="test"[^>]*>((?'c'<k'tag'[^>]*>)|(?'-c'</k'tag'[^>]*>)|([dD]))*</k'tag'>
如果 #test 不是 span 而是其他标签,为了匹配到任意标签,可以把span替换成 w+<(?'tag'w+)[^>]*id="test"[^>]*>((?'c'<k'tag'[^>]*>)|(?'-c'</k'tag'[^>]*>)|([dD]))*</k'tag'>
匹配结果是:
1 |
<span id="test"> |
如果不需要带标签,只要里面的内容,那么加上两个断言(?<=(<(?'tag'w+)[^>]*id="test"[^>]*>))((?'c'<k'tag'[^>]*>)|(?'-c'</k'tag'[^>]*>)|([dD]))*(?=(</k'tag'>))
匹配结果是
<span id="span1"> hi~
<span id="span2"> 虫虫</span>
<em>:</em>
</span>
<span id="span3">早上好</span>。
说明一下(?<=表达式) :前面要包含表达式匹配到的项目,但是不会被匹配进去(?=表达式) :后面要包含表达式匹配到的项目,但是不会被匹配进去




近期评论