项目背景
在字节实习的时候遇到了一个需求,简单来说就是支持用户上传音乐链接,并对链接做风险检查。但是考虑到用户可能上传的是文本中蕴含着链接,常用分享的朋友可能经常会见到这种格式的连接分享:
1 | 9微xR52XUVGuBR嘻 https://m.tb.cn/h.4HiWOMs?sm=c079e2 【淘饱店】Xraypad Aqua Control+ 纯黑纯白鼠标垫AC+粗面多尺寸 |
当时的状况是,公司内部有团队提供了连接风险检测的接口(实际是结合google的API), 但是只支持纯连接风险检测,不支持以上这种分享格式。同时,前端的同学也希望后端能够帮助提取连接。于是,当时就参考了组内之前使用python提取网易云链接的思路和一些开源的库,使用Go中的regex正则框架实现了一个文本中提取链接的工具库。
设计思路
本身项目设计的初衷,是乐观的认为用户分享的文本格式不会出现极端的案例,而是属于正常的分享行为。所以,并没有对一些特别极端的案例进行覆盖。首先介绍以下整体的设计思路。
wiki上关于URI的定义如下图所示,变化非常多:
但是一般用户上传的URL,一般呈现出以下格式:
格式一:[Scheme] + [Host] + [PathCont]
1 | http://www.example.com/index.html |
格式二:[Domain] + [Top Level Domain] + [PathCont] (web URL 格式)
1 | www.example.com/index.html |
格式三:[hostName] + [Port] + [PathCont]
1 | 192.168.178.111:9090/index.html |
对于URL匹配,我想最关键的是找到起始点和终止点,那么基于以上三种格式,分别设计了不同的正则表达式来进行匹配。
首先对于格式一特征的URL,这种格式的链接最显著的特点就是Scheme,而且Scheme的构成是固定的,我们可以首先将对所有Scheme集合进行匹配,匹配成功,那么就找到了URL的起点。下面的网址是国际上维护的Scheme列表:
1 | https://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv |
对于格式二特征的URL,这种域名格式链接,低等级域名并不固定,但是我们发现顶级域名的注册是固定的,所以还是老方法,先匹配出顶级域名的位置,再根据响应的正则前后进行匹配,具体细节见后文。这两处维护了最新的顶级域名列表(TLDs):
1 | "https://data.iana.org/TLD/tlds-alpha-by-domain.txt" |
对于格式三特征的URL,hostName有可能是格式二的域名形式,也可能是IP地址,但是无论是以上哪种格式,都是可以圈定范围的。比如IPv4地址的范围和IPv6的地址范围:
1 | `(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])` |
对于文本URL提取,我们就从以上这三个角度分别做匹配。但是正如我之前所述,这种匹配方式并不能保证完全的匹配,但是在实现的功能完全符合业务的需求。
正则表达式基础
正则表达式描述了一种字符串匹配模式,通过这种模式来检验字符串中是否含有对应模式的子串,子串替换,取出子串等操作。
https://www.regular-expressions.info/
普通字符
1 | [ABCD]:允许匹配[]中所有的字符 |
特殊字符
1 | (): 标记子表达式的起始位置 \进行转义 |
限定符
1 | 限定符用来指定一个组件满足要求的匹配次数 |
定位符
1 | ^: 匹配输入字符串开始的位置。 |