不管学什么语言,正则表达是都是逃不了的,当时学Java的时候也学了下正则表达,属于学了不用要不了多久就会忘的东西,这次是第二次还是第三次学正则表达式了,希望能记住吧!
0x00 正则表达式
正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器裡,正則表达式通常被用来检索、替换那些符合某个模式的文本。
正则表达是主要分为元字符与量词组成。
这里值得注意的是[A-z],这个可不是表示英文字母的大小写哦!由于-是通过ASCII码表来链接范围的,在ASCII码表中,大写字母与小写字母直接有6个特殊符号,因而这样书写范围会扩大。
量词的作用主要是指定元素的重复次数。
在记忆正则表达是的元字符与量词的时候可以成对记忆。
0x01 关于Regex的匹配模式
下面的例子用的是<javascript>和</javascript>,但是代码插件会将<>转化为超文本标记,所以换为(),尴尬 ̄□ ̄||
a.贪婪模式
在默认情况下,正则表达的匹配模式为贪婪匹配,就是尽可能长的匹配出字符来。
import re str = '(javascript) xxxoooxxoo (/javascript)' rex = re.compile('[(].*[)]') if rex:print(rex.search(str).group()) #(javascript) xxxoooxxoo (/javascript)
从上面的结果可以看出,正则表达式由于默认是贪婪模式为了匹配到更长的字符串,因而并没有在第一个>就完成匹配,而是到了最后一个>才完成匹配,之后才有返回值。
b.惰性匹配
还是上面的例子,由于默认情况下为贪婪匹配,如果只想匹配到第一个<xxx>点的内容的话,那么只能请出‘?’来完成,将正则表达的贪婪匹配变为惰性匹配的任务了。惰性匹配就是尽可能短的匹配到字符串。
import re str = '(javascript) xxxoooxxoo (/javascript)' rex = re.compile('[(].*?[)]') if rex:print(rex.search(str).group()) #(javascript)
上面的例子,只想在量词后加上一个‘?’就完成里惰性匹配。
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
贪婪匹配有一个比较多的用法为.*?c(这里c是随便写的),其表示的意思是就是取前面任意长度的字符,直到一个c出现,就是前面是什么都无所谓了,物色到第一个c(惰性嘛,不想找了),就完成了匹配任务。
0x02 re模块
正则表达是的英语为Regex,从而re模块就是Python中处理正则表达的模块了。
re模块主要方法
在re模块中最常用的方法有3个,分别是findall()/search()/match()。
a.findall()
import re str = '(javascript) xxxoooxxoo (/javascript)' li = re.findall('[(].*?[)]',str) print(li) #['(javascript)', '(/javascript)']
上面的例子就是在将匹配到的结果放入一个列表中,若没有匹配到则返回一个空列表。
关于分组优先问题
由于findall()没有search()与match()的分组机制,因而会采用优先匹配分组里的内容。
import re ret = re.findall('www.(xzymoe|google).com','pythonwww.xzymoe.comgoogle') print(ret) #xzymoe
我们想要匹配到的结果为www.xzymoe.com或者www.google.com,但是由于括号的存在,加之没有分组机制,所以会优先匹配出括号里的结果。如果想匹配到和我们预期一起的www.xzymoe.com,我们需要将分组优先的匹配机制取消,操作如下:
import re ret = re.findall('www.(?:xzymoe|google).com','pythonwww.xzymoe.comgoogle') print(ret) #['www.xzymoe.com']
还是用?:将扩后里优先的内容,惰性了和整体一起返回。这样就可以搜索到我们想要的结果。
b.search()
import re str = '(javascript) xxxoooxxoo (/javascript)' gen = re.search('[(].*?[)]',str) if gen: print(gen.group()) #(javascript) print(gen.group()) #(javascript) print(gen.group()) #(javascript)
search()的作用是从前向后查找,找到第一个值就返回一个变量,之后该变量需用使用.group()方法才可以拿到里面的值;如果没有找到找到就返回None,因为为了防止报错,所以上面写了if。
关于search()里的分组
括号有分组的作用,下面这个例子正则表达式中就有括号的存在,因而具有分组作用。
ret = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199912122277') print(ret.group()) #110105199912122277 print(ret.group(1)) #10105199912122 print(ret.group(2)) #227
通过结果可以看出,在group()中的参数就代表第几个括号中,匹配到的结果,而默认情况下则没有分组作用,将匹配出左右答案。
c.match()
match()的作用于search()差不多,其匹配是从头开始匹配,如果匹配成功就返回一个变量,调用也需要.group(),没有匹配到则返回一个None。
import re ret = re.match('\d[a-z]*','1a1ab1abc1abcd1') if ret: print(ret.group()) #1a ret = re.match('\d[a-z]{2}', '1a1ab1abc1abcd1') if ret: print(ret.group()) #None
match()是从头开始匹配,因而第二个匹配并没有匹配出1ab来。
re模块的更多方法
除了上面的三个方法外,还有类似split()/sub()/subn()/compile()/finditer()方法也很重要。
a.splite()
li = re.split('[ab]','abcdaefbgh') print(li) #['', '', 'cd', 'ef', 'gh']
从上面的结果可以看出,其分割的方法是先用a分割一次,在用b分割一次,位于最开始的地方,由于前面没有内容,因而产生一个空字符。
b.sub()
import re li = re.sub('\d','X','a1b2c34d5a6e6f7b8g9h',3) li2 = re.sub('\d','X','a1b2c34d5a6e6f7b8g9h') print(li) #aXbXcX4d5a6e6f7b8g9h print(li2) #aXbXcXXdXaXeXfXbXgXh
替换功能,不过还可以指定替换次数,若未指定替换次数则默认全部替换。
c.subn()
import re li = re.subn('\d','X','a1b2c34d5a6e6f7b8g9h') print(li) #('aXbXcXXdXaXeXfXbXgXh', 10)
对于我个人而言,该方法相较于sub()方法,我使用的较少。其主要作用就是替换字符串里的所有内容,并返回一个总替换次数,最终保存在一个元祖(tuple)里返回。
d.compile()
import re x_reg = re.compile('[\+\*-/]') t = '5+3-8/9*6-7' ret = x_reg.sub('X',t,4) print(ret) #5X3X8X9X6-7
对于需要经常使用的一段正则表达式,可以先将其编译好了,之后就不用再去复制该表达了,直接调用编译好的对象即可,有点类似内置函数里的compile()方法。
e.finditer()
看见iter就猜测肯定是生成一个可迭代对象。
import re ret = re.finditer('\d', 'xzy1moe234xzymoe56789') #finditer返回一个存放匹配结果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一个结果 #1 print(next(ret).group()) #查看第二个结果 #2 print(next(ret).group()) #查看第三个结果 #3 print([i.group() for i in ret]) #查看剩余的左右结果 #['4', '5', '6', '7', '8', '9']
就是将匹配到的结果返回一个迭代器,之后通过group()方法调出结果。
0x03 关于标签匹配
由于标签要用到<>,这个代码插件python中<>会出现问题,所以直接截图吧!
通过(?P<标签名称>正则表达式)来给分组加上标签,之后在调用.group()的时候就可以通过标签名字来匹配到需要的内容了。
谢谢博主分享
谢谢支持!