1.本文内容来自个人编写、python官方文档、参考菜鸟教程和网上部分解析。 2.本文加入大部分个人理解,并删去部分官方解释。可能存在理解错误,造成本文存在错误。
特殊符号 | 代表含义 |
---|---|
\ | 转义字符,用于转义特殊符号. * ? 等,可以通过\. \* \?来进行匹配相对应字符 |
. | 在默认模式,匹配除了换行的任意字符。 |
* | 限定,对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 |
+ | 限定,对它前面的正则式匹配1到任意次重复。 尽量多的匹配字符串。 |
? | 限定, 对它前面的正则式匹配0到1次重复。 当位于* + {} 等之后则是限制,尽可能的少匹配字符串。 |
^ | 定位,匹配字符串的开头当形式为[^...]时,则表示不匹配...中的字符 |
$ | 定位,匹配字符串尾 |
| | 或字符,A|B, A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B. 任意个正则表达式可以用 '|' 连接。 |
{} | 限定,{m}对它前面的正则式匹配m次,少于m个无法匹配。{m,n}对它前面的正则式匹配至少m次最多n次,尽量多的匹配字符串。 |
[] | 集合,例如[abc]则进行匹配'a'、'b'、'c'中任意字符,其余写法:[0-9]:0到9任意数字。[a-z]:a到z任意字符,除此之外还有[1-5]、[0-9A-Za-z]等多种多样。当形式为[^...]时,则表示不匹配...中的字符 |
() | 组合,匹配括号内的任意正则表达式,会储存匹配结果。()内看作一个整体,子表达式 |
组合 | 代表含义 |
---|---|
(?#...) | ...为注释,无作用的正则表达式 |
(?:...) | ...为表达式(...通常时 | 的语句) 用来匹配字符串,但不保存匹配的(?:...)的结果。 |
(?=...) | ...为自定义正则表达式。整体位置在表达式之后,将从后向前匹配,如果后面字符为...,则开始匹配表达式,匹配结果不包括... |
(?!...) | ...为自定义正则表达式。整体位置在表达式之后,将从后向前匹配,如果后面字符为...,则不匹配表达式,不是…则开始匹配 |
(?<=...) | ...为自定义正则表达式。整体位置在表达式之前 ,将从前向后匹配,如果前面字符为...,则开始匹配表达式,匹配结果不包括... |
(?<!...) | ...为自定义正则表达式串。整体位置在表达式之前 ,将从前向后匹配,如果前面字符为...,则不匹配表达式,不是…则开始匹配 |
(?P<name>...) | ...为自定义正则表达式...中匹配的字符串将赋值给name,可以通过group('name')进行读取访问,案例在下方代码区 |
(?P=name) | 通过name传递的字符串来匹配。使用此规则,必须先用(?P…)确定name的值,之后才能使用,案例在下方代码区 |
(?(id/name)yes-...|no-...) | 通过判断id或name是否匹配成功,来决定选择yes-...或no-...表达式,例如(?P<name><)h1(?(name)>|$)来匹配<h1>或h1,当(?P<name>>)匹配到<后,则?(name)会匹配yes-...反之匹配no-... |
案例 请阅读完下方函数使用方法后观看案例
text='iammebyz.cn mebyz'
a=re.search(r'(?#我是半叶子,注释)mebyz',text)
print(a.group())
b=re.search(r'(?:m|e)byz',text)
print(b.group())
c=re.search(r'm(?=m)',text)#对比c、d观察m的位置
print(c)
d=re.search(r'm(?!m)',text)#对比c、d观察m的位置
print(d)
e=re.search(r'(?<=a)m',text)#对比e、f观察m的位置
print(e)
f=re.search(r'(?<!a)m',text)#对比e、f观察m的位置
print(f)
g=re.search(r'(?P<name>me)byz',text)#name为定义的名称,可随意
print(g['name'],":",g.group())
h=re.search(r'(?P<name>me).*?(?P=name)',text)
print(h['name'],":",h.group())
i=re.search(r'(?P<name>me).*?(?(name)cn|me)',text)
print(i['name'],":",i.group())
#运行结果如下:
#a:mebyz
#b:ebyz
#c:<re.Match object; span=(2, 3), match='m'>
#d:<re.Match object; span=(3, 4), match='m'>
#e:<re.Match object; span=(2, 3), match='m'>
#f:<re.Match object; span=(3, 4), match='m'>
#g:me : mebyz
#h:me : mebyz.cn me
#i:me : mebyz.cn
运算符 | 描述 |
---|---|
\ | 转义符 |
(), (?:), (?=), [] | 圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, 任何元字符(例:\?则是字符?)、任何字符 | 定位点和序列(即:位置和顺序) |
| | 替换,"或"操作 |
转义字母 | 含义 |
---|---|
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字及下划线 |
\s | 匹配任意空白字符,等价于 [ \t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于[0-9] |
\D | 匹配任意非数字 |
\A | 匹配字符串开始,和^相似 |
\Z | 匹配字符串结束 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\number | number指的是一个数,匹配数字代表的组合。每个括号是一个组合,组合从1开始编号,最大为99。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '[' 和 ']' 字符集合内,任何数字转义都被看作是字符。 |
\g<id/name> | 需要与Match.expand()方法连用才可,可见案例3 |
案例1
text='''mebyz123_=-+!@#$%^&*(),./;'[]\。我是半叶子 iam
mebyz'''
a=re.search(r'\w+',text)
print(a)
b=re.search(r'\W+',text)
print(b)
c=re.search(r'\s+',text)
print(c)
d=re.search(r'\S+',text)
print(d)
e=re.search(r'\d+',text)
print(e)
f=re.search(r'\D+',text)
print(f)
g=re.search(r'\A.*',text)
print(g)
h=re.search(r'.\Z',text)
print(h)
i=re.search(r'.+\b',text)
print(i)
j=re.search(r'.+\B',text)
print(j)
#运行结果:
#a:<re.Match object; span=(0, 9), match='mebyz123_'>
#b:<re.Match object; span=(9, 31), match="=-+!@#$%^&*(),./;'[]\\。">
#c:<re.Match object; span=(36, 37), match=' '>
#d:<re.Match object; span=(0, 36), match="mebyz123_=-+!@#$%^&*(),./;'[]\\。我是半叶子">
#e:<re.Match object; span=(5, 8), match='123'>
#f:<re.Match object; span=(0, 5), match='mebyz'>
#g:<re.Match object; span=(0, 40), match="mebyz123_=-+!@#$%^&*(),./;'[]\\。我是半叶子 iam">
#h:<re.Match object; span=(45, 46), match='z'>
#i:<re.Match object; span=(0, 40), match="mebyz123_=-+!@#$%^&*(),./;'[]\\。我是半叶子 iam">
#j:<re.Match object; span=(0, 39), match="mebyz123_=-+!@#$%^&*(),./;'[]\\。我是半叶子 ia">
案例2 ()的判断方法:从左到右,左括号(在最左面为1,其次为2,以此类推。(此括号不包括(?…)扩展标记方法在内。)
text='h1 i am byz h1 mebyz.cn'
a=re.search(r'(h1).*?(byz) \1.*?\2',text)
print(a[1],a[2])
print(a.group())
#运行结果:
#h1 byz
#h1 i am byz h1 mebyz
案例3
text='2020年08月'
x=re.search(r'(\d{2,}).+',text)
print(x.expand(r'\g<1>你好'))
y=re.search(r'(?P<name>\d{2,}).+',text)
print(y.expand(r'\g<name>你好'))
#输出结果如下:
#2020你好
#2020你好
(仅列举常见常用的) 以下为各方法中参数的含义 pattern:正则表达式 string:待匹配字符串 flags为:用于控制正则表达式的匹配方式(可省略)
re.match(pattern, string, flags=0)
从字符串的起始位置匹配,如果不是起始位置匹配成功的话,match()
就返回none。如果从开头开始到正则匹配结束全部符合,则返回匹配结果。
实例:m.{2,4}
表示:匹配m开始后面进跟着2到4个任意字符(除换行符),且尽可能的为4个(贪婪模式)
text='mebyz.cn'
x=re.match(m'i.{2,4}', text)#开头为m
print(x)
y=re.match(r'a.{2,4}', text)#开头为a
print(y)
#输出结果如下:
#x:<re.Match object; span=(0, 5), match='mebyz'>
#y:None
输出结果表明:当字符串开头为不符合情况则返回none,如果全部符合则返回字符的位置和字符串,可以用x.group()取出匹配结果:mebyz
。
re.seach(pattern, string, flags=0)
从字符串的起始位置匹配,如果不是起始位置匹配成功的话,则跳到下一个字符开始匹配,以此类推,直到成功匹配或匹配失败返回none。
text='mebyz.cn'
x=re.search(r'm.{2,4}', text)
print(x)
y=re.search(r'e.{2,4}', text)
print(y)
z=re.search(r'a.{2,4}', text)
print(z)
#输出结果如下:
#x:<re.Match object; span=(0, 5), match='mebyz'>
#y:<re.Match object; span=(1, 6), match='ebyz.'>
#z:None
输出结果表明:如果开头符合则进行匹配,匹配成功则返回结果,开头不符合则进行下一个字符来匹配,以此类推。当全部都不符合后则返回None,可以用x.group()取出匹配结果:mebyz
。
re.finditer(pattern, string, flags=0)正则表达式在 string 里所有的非重复匹配,返回为一个迭代器保存匹配对象。string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。 可以看作是re.search()升级版,re.search()是匹配到第一个成功字符串后就停止,而re.finditer()则是全部进行匹配,并返回一个迭代器(可以用for i in x等取出)
text='2020年08月04日'
x=re.finditer(r'(\d{2,4})(年|月|日)', text)
for i in x:
print(i.group())
y=re.search(r'(\d{2,4})(年|月|日)', text)
print(y.group())
#输出结果如下:
#i:2020年
# 08月
# 04日
#y:2020年
输出结果表明:结果re.finditer()将全部符合的全进行匹配,而re.search()匹配首个符合正则的字符串。
groups() 所有()内的匹配部分的结果的元组集合。可以看作是为元组(group(1),group(2), .....group(n)) n等于()的个数
text='2020年08月04日'
y=re.search(r'(\d{2,4})(年|月|日)', text)
print(y.group(),y.group(1),y.group(2))
print(y.groups())
#输出结果如下:
#2020年 2020 年
#('2020', '年')
结果表明: group()(等价与group(0))输出为整个表达式的值,group(1)为第一个()匹配的结果,group(2)为第二个()匹配的结果。 groups()则输出所有的()所匹配的结果构成的元组。
re.findall(pattern, string, flags=0)对 string 返回一个不重复的的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。 1.如果正则表达式中无()则返回整体正则表达式 匹配列表。 2.如果表达式中有一个(),则返回正则表达式中()内的匹配结果。 3.如果大于一个(),则返回一个列表元素是元组的列表。 记:(?...)不属于()
text='2020年08月04日'
x=re.findall(r'\d{2,4}(?:年|月|日)', text)
print(x)
y=re.findall(r'\d{2,4}(年|月|日)', text)
print(y)
z=re.findall(r'(\d{2,4})(年|月|日)', text)
print(z)
#输出结果如下:
#x:['2020年', '08月', '04日']
#y:['年', '月', '日']
#z:[('2020', '年'), ('08', '月'), ('04', '日')]
re.split(pattern, string, maxsplit=0, flags=0)用pattern分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。
text='2020-08-04'
x=re.split('-',text)
print(x)
text1='2020年08月04日'
x1=re.split('年|月|日',text1)
print(x1)
#输出结果如下:
['2020', '08', '04']
['2020', '08', '04', '']
re.sub(pattern, repl, string, count=0, flags=0) 返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数; 如为字符串,则将进行常规替换。 如为函数,传递给函数返回本次传递匹配的结果(需用group()取出字符串),函数返回的结果为替换值
def resub(re_str):
if re_str[0]=='年':
return '-'
elif re_str[0]=='月':
return '--'
else:
return ''
text='2020年08月04日'
x=re.sub('年|月|日', '-', text, count=0)
print(x)
y=re.sub('年|月|日', resub, text, count=0)
print(y)
#运行结果如下:
#2020-08-04-
#2020-08--04
re.subn(pattern, repl, string, count=0, flags=0) 行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数)
转义 re.escape(pattern) 中的特殊字符。
x=re.escape('?*+')
print(x)
#运行及如果如下:
#\?\*\+
清除正则表达式的缓存。
re.compile(pattern, flags=0)将正则表达式的样式编译为一个正则表达式对象(Pattern),可以用于匹配,通过这个对象的方法 match(), search() 以及其他如下描述。
Pattern.split(string, maxsplit=0)等价于 split() 函数,使用了编译后的样式。
Pattern.findall(string[, pos[, endpos]])类似函数 findall() , 使用了编译后样式,但也可以接收可选参数 pos 和 endpos ,限制搜索范围,就像 search()。
text='2020年08月'
m=re.compile(r'\d{2,}.*')
x=m.findall(text,pos=5,endpos=7)
print(x)
#运行结果如下:
#['08']
Pattern.finditer(string[, pos[, endpos]])类似函数 finiter() , 使用了编译后样式,但也可以接收可选参数 pos 和 endpos ,限制搜索范围,就像 search()。 案例见:Pattern.findall()
Pattern.sub(repl, string, count=0)等价于 sub() 函数,使用了编译后的样式。
Pattern.subn(repl, string, count=0)等价于 subn() 函数,使用了编译后的样式。
正则匹配标记。这是可以传递给 compile() 的参数,任何 (?…) 内联标记,隐性标记比如 UNICODE 的结合。
捕获到的模式串中组的数量。
映射由 (?P) 定义的命名符号组合和数字组合的字典。如果没有符号组,那字典就是空的。
m=re.compile(r'(?P<name>\d{2,})(?P<name1>.*)')
print(m.groupindex)
#运行结果如下:
#{'name': 1, 'name1': 2}
编译对象的原始样式字符串。
对 template 进行反斜杠转义替换并且返回,就像 sub() 方法中一样。转义如同 \n 被转换成合适的字符,数字引用(\1, \2)和命名组合(id或name) 替换为相应组合的内容。
text='2020年08月'
x=re.search(r'(\d{2,}).+',text)
print(x.expand(r'\g<1>你好'))
y=re.search(r'(?P<name>\d{2,}).+',text)
print(y.expand(r'\g<name>你好'))
#输出结果如下:
#2020你好
#2020你好
Match.group([group1, ...])(类似x.group(0,1))返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。
Match.groups(default=None)返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None。
Match.groupdict(default=None)返回一个字典,包含了所有的 命名 子组。key就是组名。 default 参数用于不参与匹配的组合;默认为 None。 例如
m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
print(m.groupdict())
#运行结果如下:
#{'first_name': 'Malcolm', 'last_name': 'Reynolds'}
Match.start([group])和Match.end([group])返回 group 匹配到的字串的开始和结束标号。 group 默认为0(意思是整个匹配的子串)。如果 group 存在,但未产生匹配,就返回 -1 。
m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
print(m.start(1),m.end(1))
#运行结果如下:
#0 7
对于一个匹配对象 m, 和一个未参与匹配的组 g ,组 g (等价于 m.group(g))产生的匹配是 m.string[m.start(g):m.end(g)]
#这个例子会从email地址中移除掉 remove_this
email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
print(email[:m.start()] + email[m.end():])
#运行结果如下:
'tony@tiger.net'
对于一个匹配 m , 返回一个二元组 (m.start(group), m.end(group)) 。 注意如果 group 没有在这个匹配中,就返回 (-1, -1) 。group 默认为0,就是整个匹配。
pos 的值,会传递给 search() 或 match() 的方法 a 正则对象 。这个是正则引擎开始在字符串搜索一个匹配的索引位置。
endpos 的值,会传递给 search() 或 match() 的方法 a 正则对象 。这个是正则引擎停止在字符串搜索一个匹配的索引位置。
捕获组的最后一个匹配的整数索引值,或者 None 如果没有匹配产生的话。比如,对于字符串 'ab',表达式 (a)b, ((a)(b)), 和 ((ab)) 将得到 lastindex == 1 , 而 (a)(b) 会得到 lastindex == 2 。
最后一个匹配的命名组名字,或者 None 如果没有产生匹配的话。
返回产生这个实例的 正则对象 , 这个实例是由 正则对象的 match() 或 search() 方法产生的。
传递到 match() 或 search() 的字符串。
及参数中的flags部分,可以设置零个或多个
符号 | 代表含义 |
---|---|
re.I | (?i)设置后,使匹配对大小写不敏感 |
re.M | (?m)设置后,样式字符 ^ 匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);样式字符 $ 匹配字符串尾,和每一行的结尾(换行符前面那个符号)。()内为re.M设置后生效的 |
re.S | (?s)让 '.' 特殊字符匹配任何字符,包括换行符;如果没有这个标记,'.' 就匹配 除了 换行符的其他任意字符。 |
re.X | (?x)这个标记允许你编写更具可读性更友好的正则表达式。通过分段和添加注释。空白符号会被忽略,除非在一个字符集合当中或者由反斜杠转义,或者在 *?, (?: or (?P<...> 分组之内。当一个行内有 # 不在字符集和转义序列,那么它之后的所有字符都是注释。 |
re.L | (?L)做本地化识别(locale-aware)匹配 |
re.A | (?a)让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。 |
re.U | (?u)根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.DEBUG | 显示编译时的debug信息,没有内联标记。 |
(re.L官方不推荐使用,re.U是为了向下兼容而保留,python3默认为Unicode,因此无效。)
(?imsx)
:作用域为全表达式,写在表达式开头,例如(?i)[a-z]+
则是忽略字符串大小写进行匹配,作用与传递参数相同。可以一次性传递多个例如(?imsx)
则传递4个修饰符过去,可以自己根据需求决定传递哪些修饰符(共7种)。
(?imsx:...)
:作用域为括号内...部分,例如(?i:[a-z]+)
则是忽略字符串大小写进行匹配。可以一次性传递多个例如(?imsx:[a-z]+)
则传递4个修饰符过去。
(?-imsx:...)
:作用域为括号内...部分,例如(?-i:[a-z]+)
是取消忽略字符大小写进行匹配,可以一次性传递多个例如(?-imsx:[a-z]+)
则传递4个修饰符过去。
举例分析(仅针对re.I、re.M、re.S、re.X) re.I作用:
text='Mebyz'
x=re.search(r'[a-z]+', text)
print(x.group())
y=re.search(r'[a-z]+', text,re.I)
print(y.group())
#输出结果如下:
#ebyz
#Mbyz
re.M作用:
text='''me
byz'''
x=re.search(r'^byz$', text)
print(x)
y=re.search(r'^byz$', text,re.M)
print(y.group())
#输出结果如下:
#None
#byz
re.S作用:
text='''me
byz'''
x=re.search(r'.{2,4}', text)
print(x)
y=re.search(r'.{2,4}', text,re.S)
print(y)
#输出结果如下(为表现出换行符\\n,则直接输出x,y):
#x:<re.Match object; span=(0, 2), match='me'>
#y:<re.Match object; span=(0, 4), match='me\nb'>(\n为换行符)
re.X作用:
text='mebyz'
x=re.search(r'.{2,4}', text)
print(x.group())
y=re.search(r'''.# 我是半叶子,
{2,4}#这是注释
''', text,re.X)
print(y.group())
#输出结果如下:
#meby
#meby
内联形式写法
text='Mebyz.Cn'
m=re.findall(r'[a-z]+\.[a-z]*', text)#无限制符
print(m)
e=re.findall(r'[a-z]+\.[a-z]*', text,re.I)#参数传递形式
print(e)
b=re.findall(r'(?i)[a-z]+\.[a-z]*', text)#内联全局形式
print(b)
y=re.findall(r'(?i:[a-z]+)\.[a-z]*', text)#内联()内作用形式
print(y)
z=re.findall(r'(?i)[a-z]+\.(?-i:[a-z]*)', text)#内联()取消全局形式
print(z)
#输出结果如下:
#m:['ebyz.']
#e:['Mebyz.Cn']
#b:['Mebyz.Cn']
#y:['Mebyz.']
#z:['Mebyz.']