在正则表达式知识详解之实战 读取网页中超链接 (java版示例)中,有个匹配超链接的正则为<[Aa]\\s+(.*?\\s+)*?href\\s*=\\s*([\"']).+?\\2\\s*(\\s+.*?\\s*)*?>.+?</[Aa]>
,这篇文件主要介绍该正则是如何一步一步写出来的。
上面正则表达式组合过程
1、匹配最简单的<a></a>
空的标签,由于a可以大写,所以又下面几种情况
- 字符串
<a></a>
,前后都小写,正则为<a></a>
。 - 字符串
<a></A>
,前小写,后大写,正则为<a></A>
。 - 字符串
<A></A>
,前后都大写,正则为<A></A>
。 - 字符串
<A></a>
,前大写,后小写,正则为<A></a>
。
即,超链接前面可能是<A>
或<a>
,后面可能是</A>
或</a>
,把上面4种合起来的正则即为<[Aa]></[Aa]>
。
当然,如果你确定超链接使用的小写或大写,简单点,把[Aa]
换成a
或A
即可。
2、超链接里总归会有点内容的,如中文、英文、空格等等,<a>我是超链接</a>
。
在前面的基础上继续完善:
- 由于超链接的内容可以为任意东西,所以我们方便点,直接用英文句号点
.
来表示。 - 内容长度不固定,但至少你得有一个字符吧,所以需要一次或多次,即,用
+
来限定长度。 - 一个页面超链接会有很多,如
<a>超链接1</a><a>超链接2</a>
,肯定要作为两个超链接,不能当成一个超链接,把超链接1</a><a>超链接2
作为内容吧。所以要用?
限定为非贪婪模式。
综上,得出内容的正则为.+?
,与步骤1合并,即:<[Aa]>.+?</[Aa]>
3、超链接至少要有个href
属性吧,现在给a
标签加个href
属性。
为了方便,href
属性的内容我们不细致匹配,直接用.+?
,这里?
可以不加的,一般把+
、*
这种次数不固定的限制为非贪婪模式不容易出错,除非需要贪婪模式或确定不会导致贪婪匹配。
字符串内容(为了方便我直接用小写的a标签):
<a href= 'http://blog.csdn.net/gnail_oug'>链接1</a><a href ="javascript:void(0);">链接2</a>
- 根据上面我们知道
http://blog.csdn.net/gnail_oug
和javascript:void(0);
都可以用.+?
来匹配。 - a标签href属性之间至少要有一个空格,所以
\s+
来表示。 - href属性面
=
两边可以没空格也可以有空格,所以用\s*
,至此完整正则表达式为(假设只用单引号)<[Aa]\s+href\s*=\s*'.+?'>.+?</[Aa]>
。 - 由于html中引号可用单引号也可用双引号,所以正则要换成
<[Aa]\s+href\s*=\s*['"].+?['"]>.+?</[Aa]>
。 - 正常情况下,步骤4用
["']
是没问题的。一般情况下前面用单引号后面也会用单引号,前面双引号后面也是双引号,即成对出现。严谨起见,我们排除href='aa"
这种前后引号不一致的情况。
这就用到了回溯引用。\
加数字表示引用当前正则里第几个表达式。
所以正则表达式变为:<[Aa]\s+href\s*=\s*(['"]).+?\1>.+?</[Aa]>
4、其他属性
超链接除了href属性,有时还会有title等其他属性,这些属性有可能在href属性前,有可能在href属性后。
这里我们不知道有没有其他属性,也不需要知道是什么属性,值是多少,所以我直接用.*?
,?
表示非贪婪模式。
如果在href属性前,那么其他属性和href中间至少要有个空格,如果在href属性后,那么其他属性前和href值中间至少要有一个空格,其他属性后可有空格,也可没有直接是>
。
因此,正则完善成:<[Aa]\s+(.*?\s+)*?href\s*=\s*(['"]).+?\2(\s+.*?\s*)*?>.+?</[Aa]>
注意,这里\1
变成了\2
,因为前面的分组(.*?\s+)*?
占用了序号1。
5、转义
至此,相对比较完善的超链接正则已经完成,由于java里面\
需要转义,所以使用了两个斜线\\
。
本文主要说明一个复杂的正则怎么从一个简单的正则演变的,里面涉及的有些知识点可以参考正则分类。