通过正则表达式匹配带url链接的<a></a>标签

正则表达式小白,记录最近一次正则表达式的实践。一直以来觉得正则就是天书,经过这次实践,感觉正则已不是那么可怕,只要学习、细心、认真,就一定能使用好它。

需求:

需要将一段文字中带有url链接的a标签进行高亮展示,因此需要用正则取出整个<a></a>。

关键点:

a标签,带url链接。

实现

首先a标签的格式如下:

<a attrFront="属性值" href="网址链接" attrFront="属性值">显示的文字内容</a>

前面的a标签必须要有href,href里面是有网址链接的。href的前面或者后面可能会有其他的属性,也可能没有。前面后面的属性都可能会有多个。属性的格是:attrFront="属性值"。属性值不仅是英文字母,也可能是中文、方法等。

url链接正则:

((https?|ftp|http)://)?(([\w-]+\.)+[A-Za-z]{2,}|((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]{2,5})(/[\w-./?%&!;#,=|]*)?

可以匹配带path及参数的url,网址可以是域名,也可以是ip:port格式。前面的http前缀有无都可匹配。

属性值正则:

[\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]

[\w-\.]+\s*=\s*['][:/\.?"();,%&!#|=\w-\u4e00-\u9fa5\s]*[']

非常关键的一点:属性值正则,需要两个,因为属性值带方法时,可能会有单引号或者双引号,跟包裹属性值外面的引号冲突,导致无法匹配。所以外面是单引号时,里面是双引号。外面是双引号时,里面是单引号。

带方法的a标签示例:

<a href="https://www.cnblogs.com/jingdenghuakai/p/11701122.html" οnclick="window.open(this.href, '', 'resizable=no,status=no,location=no,toolbar=no,menubar=no,fullscreen=no,scrollbars=no,dependent=no,width=700,height=500'); return false;">url地址弹出窗口超链接</a>

最终使用的正则也是两个,引号外双内单、外单内双:

<\s*a\s+([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*\s*href\s*=\s*["](((https?|ftp|http)://)?(([\w-]+\.)+[A-Za-z]{2,}|((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]{2,5})(/[\w-./?%&!;#,=|]*)?)["]\s*([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*\s*>(.+?)</\s*a\s*>?

<\s*a\s+([\w-\.]+\s*=\s*['][:/\.?"();,%&!#|=\w-\u4e00-\u9fa5\s]*[']\s*)*\s*href\s*=\s*['](((https?|ftp|http)://)?(([\w-]+\.)+[A-Za-z]{2,}|((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]{2,5})(/[\w-./?%&!;#,=|]*)?)[']\s*([\w-\.]+\s*=\s*['][:/\.?"();,%&!#|=\w-\u4e00-\u9fa5\s]*[']\s*)*\s*>(.+?)</\s*a\s*>?

正则表达式详细解释,以外双内单为例:

<\s*a\s+([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*\s*href\s*=\s*["](((https?|ftp|http)://)?(([\w-]+\.)+[A-Za-z]{2,}|((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]{2,5})(/[\w-./?%&!;#,=|]*)?)["]\s*([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*\s*>(.+?)</\s*a\s*>?

(ps:可能有些地方解释的不太正确,欢迎指正,文明用语^_^。)

第一部分:<\s*a\s+

用来匹配"<a ",\s的意思是空格,*的意思是可以有0个或多个。\s*的意思是可有0个或多个空格。+的意思是至少有一个,\s+的意思是有至少一个空格。

第二部分:([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*

用来匹配一个或多个属性。括号是分组的意思,括号外面的*代表这个分组可以是0次也可以是多次。

\w匹配英文字母大小写和下划线,\w-就是比\w多了-,\.匹配点号,因为点号本身匹配所有,所以要加\转义。[\w-\.],中括号代表,里面的哪种都行都是或的关系,但只是一个字母。[\w-\.]+,外面放一个+,代表这些元素至少出现一次。在这类代表属性的key至少有一个元素。\s*=\s*代表等号前面或者后面可能有0个以上的空格。["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]中的红色部分匹配中文。括号中的\s*代表一个属性后接另一个属性时至少有0个空格,这个地方也很关键,在实现的过程中踩了坑,导致匹配问题。

第三部分:\s*

href前的属性,跟href之间有0个以上空格。

第四部分:href\s*=\s*["](((https?|ftp|http)://)?(([\w-]+\.)+[A-Za-z]{2,}|((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]{2,5})(/[\w-./?%&!;#,=|]*)?)["]

匹配href=url。

第五部分:\s*

herf后面至少0个空格

第六部分:([\w-\.]+\s*=\s*["][:/\.?'();,%&!#|=\w-\u4e00-\u9fa5\s]*["]\s*)*

同第二部分。

第七部分:\s*>

最后一个属性值跟后面的尖括号之间至少0个空格

第八部分:(.+?)

a标签中间可以是任意字符。点号指一个任意字符,点号和加号一起,指至少1个任意字符,问号指惰性模式,简单说就是尽少匹配,详细的我也说不太清。

第九部分:</\s*a\s*>

后面的尖括号部分

第十部分:?

惰性模式。如果不加的话几个a标签就会匹配成一个。

总结

这次实践算是入了门。

其中使用到的工具,帮了大忙:在线正则表达式测试

java的工具类

java.util.regex包下的Pattern、Matcher
    
	private static void printMatchInfo(String content, String regex) {
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(content);
		while (m.find()) {
            System.out.println(m.group(0));//匹配到的所有内容
            System.out.println(m.group(2));//匹配到的url
            System.out.println(m.start());//匹配到内容的起始位置
            System.out.println(m.end());//匹配到内容的结束位置
		}
	}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值