Python正则表达式与re模块

不管学什么语言,正则表达是都是逃不了的,当时学Java的时候也学了下正则表达,属于学了不用要不了多久就会忘的东西,这次是第二次还是第三次学正则表达式了,希望能记住吧!

regex

0x00 正则表达式

正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器裡,正則表达式通常被用来检索、替换那些符合某个模式的文本。

正则表达是主要分为元字符与量词组成。

regex-metacharacters元字符比较好记,基本都是成对出现的。

这里值得注意的是[A-z],这个可不是表示英文字母的大小写哦!由于-是通过ASCII码表来链接范围的,在ASCII码表中,大写字母与小写字母直接有6个特殊符号,因而这样书写范围会扩大。

量词的作用主要是指定元素的重复次数。

regex- classifier

在记忆正则表达是的元字符与量词的时候可以成对记忆。

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)  # &lt;callable_iterator object at 0x10195f940&gt;
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中<>会出现问题,所以直接截图吧!

regex-tag通过(?P<标签名称>正则表达式)来给分组加上标签,之后在调用.group()的时候就可以通过标签名字来匹配到需要的内容了。

2 thoughts on “Python正则表达式与re模块

  1. Google Chrome 63.0.3239.132 Google Chrome 63.0.3239.132 Windows 7 x64 Edition Windows 7 x64 Edition

    谢谢博主分享

    • xzymoe
      Firefox 59.0 Firefox 59.0 Ubuntu x64 Ubuntu x64

      谢谢支持!

发表评论