正则表达式的基本使用规则相信大家都已经有所了解,如果你是新手,可以移步正则表达式30分钟入门教程,这个教程非常详细,并且深入浅出。
这里要讲的有两个问题,也是我在开发过程中花了些时间才解决的:
(1)re.findall(pattern,string,flag=0)函数,flag参数的意义
(2)当处理的数据量非常大时,如何提高执行效率
第一个问题是在分析爬取的网页时,习惯用re.findall(pattern,string),导致总有内容匹配不到,后来了解了flag参数默认为0,导致`.`不能匹配换行符。这个其实只要查看一下api中对flag参数的定义即可明白。
在编写程序时,应多关注库函数的api,弄懂每一个参数的意义就能高效码代码了。这里的需求是让`.`能匹配`\n`,所以函数调用应该为re.findall(pattern,string,re.S)
第二个问题就比较蛋疼了,因为这种问题并不是一个很常见的问题,虽然网络上也有人问这个,但几乎没有回答。我的需求是在近20w行数据里识别出类似下面的结构体:
没错,这就是github的commit日志格式,题主需要从这些日志中分析出一些信息,具体到在每个结构体中分析。
所以这里的正则并不是很难写,题主先写成这样:
regx = `(commit ([0-9a-f]{40})\nAuthor:.*?Date:.*?\n\n)commit`最后一个\n\ncommit字段是用来标识该结构体的结束以及新结构体的开始,取之前的数据即为一个完整结构。然后对每个结构进行处理和匹配。
题主测试了一下当数据量只有1w左右时,几乎一秒不到就可以处理完,然而超过了这个限度,则大有几十分钟也跑步出结果的样子。
查了下原因,以及regex optimization
`.*`is too permissive and can cause a catastrophic backtracking and regex is very expensive
所以,在处理大量数据的时候应该要少用`.*`、`.+`等greedy模式的匹配,尽量用一些字段明确的方式来找,所以使用了如下的方式:
regex = `commit ([0-9a-f]{40})\nAuthor`来匹配标识每个数据集合,并通过引入index脚标的方式来剥离区分每一个数据集合。核心的算法如下:
主要是通过数据块的id的index来完成数据集合的剥离与区分,正则表达式部分基本没有用到其它贪婪模式的匹配,效果立竿见影,分分钟出结果2333~