正则表达式匹配文本

技术博客 (148) 2023-09-16 15:39:10

在正则表达式中,匹配是最最基本的操作。使用正则表达式,换种说法就是“用正则表达式去匹配文本”。但这只是广义的“匹配”,细说起来,广义的“匹配”又可以分为两类:提取和验证。所以,本篇文章就来专门讲讲提取和验证。

提取

提取可以理解为“用正则表达式遍历整个字符串,找出能够匹配的文本”,它主要用来提取需要的数据,常见的任务有:找出文本中的电子邮件地址,找出HTML代码中的图片地址、超链接地址……提取数据时,首先要注意的,就是准确性。

准确

准确性分为两方面:完整精确 。前者是要提取出需要的所有文本,不能漏过;后者是要保证提取的结果中没有不需要的文本,不可出错。

为保证完整,我们需要考虑足够多的变体,覆盖所有情况。一般来说,要提取的数据都只有概念的描述(比如,提取一个电子邮件地址,提取一个身份证号),如果没有拿到完整规范的特征描述,可能只能凭经验总结出几条特征,然后逐步完善,也就是不断考虑新的情况,照顾到各种情况。

拿“提取文本中的浮点数字符串”为例。最容易想到的情况,就是3.14、3999.2、0.36之类,也就是“数字字符串 + 小数点 + 数字字符串”,所以用表达式『\d+\.\d+』,按照我们上一篇文章说过的“与或非”,三个部分都是必须出现的,所以这个表达式似乎是没问题了。

\d+\.\d+ 

但是有些时候,0.7是写作.7的,上面的表达式无法照顾这种情况,所以必须修改表达式:整数部分是可能出现也可能不出现的,所以小数点之前的\d+应该改为\d*,就成了『\d*\.\d+』。

\d*\.\d+ 

但是且慢,浮点数还包括负数,比如-0.7,但现在这个表达式无法匹配最开始的符号,所以还应该改成『-?\d*\.\d+』。

-?\d*\.\d+

但仅仅保证完整性还不够,提取的另一方面是精确,就是排除掉那些“能够由正则表达式匹配,但其实并非期望”的字符串,所以我们还需要仔细观察目前的正则表达式,适当添加限制条件。

仍然用上面的正则表达式作例子,『-?\d*\.\d+』中,『-?』和『\d*』都是可能出现的元素,所以它们可能都不出现,这时候表达式能匹配.7之类,没有错;如果只出现了『\d*』能匹配的文本,可以匹配3.14之类,也没有错;但是,如果只出现『-?』呢?-.7,通常来说,负的浮点数是应该写作-0.7的,而-.7显然是不合法的。所以,这个表达式应该修改为『(-?\d+|\d*)\.\d+』。

(-?\d+|\d*)\.\d+ 

事情到这里就完整了吗?似乎还不是。我们知道有些地方,日期字符串是“2010.12.22”的形式,如果你要处理的文本中不包含这种日期字符串还好,否则,上面的表达式会错误匹配2010.12 .22或者2010.12.22 。为了避免这种情况,我们需要给表达式加上更多的限制。最直接想法就是,限定表达式两端不能出现点号.,变成『(?!<.)(-?\d+|\d*)\.\d+(?!.)』。

(?!<.)(-?\d+|\d*)\.\d+(?!.) 

这样确实避免了2010.12.22的错误匹配,但它也造成了新的问题,比如“…the value of π is 3.14. Therefore…”,3.14本来是我们需要提取的浮点数,但加上这个限制之后,因为3.14之后的有一个作为英文句号使用的点号,所以3.14无法匹配。仔细观察我们要排除的2010.12.22这类字符串,我们发现点号.的另一端仍然是数字,而用作句号的点号,另一端必定不是数字(一般是空白字符,或者就是字符串的开头/末尾),所以应当把限制条件表达的更精确些,变为『(?!<\d.)(-?\d+|\d*)\.\d+(?!.\d)』。

(?!<\d.)(-?\d+|\d*)\.\d+(?!.\d) 

好了,关于浮点数的匹配就

THE END

发表回复