python正则-- re模块

时间:2023-01-01 03:14:18

匹配数字相关
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a'],如果想控制一个组,可以加()
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次,常用来表示可有可无(出现1次或0次)的一个符号
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb'] ,可以替代'*' '+' '?' 为:{0,} {1,} {0,1}
'[]' 字符集,匹配[]中的字符(其中的字符是或的关系),其中的字符可以一一列出,也可以给出范围,元字符在其中失去意义,除非元字符前面加了反斜杠。有几种特殊的元字符依然有意义:表示范围的'-', 取反的'^',和'\'
 >>> re.search('[a|b]','aabcd').group()   # search方法在字符集匹配时只匹配一次
'a'
>>> re.search('[a|b]+','aabcd'). # '+' 匹配一次或多次字符集中的内容
'aab' >>> re.findall('[a|b]','aabcd')
['a', 'a', 'b']
>>>
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c。 分组匹配时,findall只返回分组括号中的内容,返回到一个列表,分组作用:为了在已经匹配到的内容中再去提取过滤内容,有几个括号就提取几次
'\' 1.后面跟元字符去除特殊功能,2.跟普通字符实现特殊功能(\d:匹配数字),3.引用序号对应的字组所匹配的字符串
 >>> re.search(r"(whisky)(\d+)com\2","whisky211985com211985").group()
'whisky211985com211985'
'\A'    效果和^是一样的,只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z' 匹配字符结尾,同$  
'\d' 匹配单个  数字0-9
'\D' 匹配非数字
'\w' 匹配[A-Za-z0-9],注意:不能匹配空格、特殊字符等
'\W' 匹配[A-Za-z0-9]
'\s' 匹配空白字符、\t、\n、\r、\f、\v, re.search("\s+","ab\tc1\n3").group() 结果 '\t'
‘\b’  匹配一个单词边界,即单词和空格(或特殊字符)间的位置,字符串开头结尾及空格回车等的位置,不会匹配空格符本身
 >>> import re
>>> re.findall('abc\b','asdas abc ')
[] # 没有声明原生字符串或转义,所以结果为空
>>> re.findall('abc\\b','asdas abc ')
['abc']
>>> re.findall(r'abc\b','asdas abc ')
['abc']
>>> re.findall(r'abc\b','asdas abc*')
['abc'] # 特殊字符作为单词边界 >>> re.findall(r'i\b','i miss iou')
['i']
>>> re.findall(r'i\b','imiss iou')
[]
>>> re.findall(r'\bi',' imiss iou') # 以空格为单词边界
['i', 'i']
>>> re.findall(r'\bi','imiss iou') #以字符串开头和空格为单词边界
['i', 'i']

例子

'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
注意:?P为固定语法格式
写法:(?P<组名>正则表达式),输出(以字典的形式输出):{'组名':'正则匹配的结果'}

(*|+|?|{})? : *、+、?、{}后面加?使用非贪婪模式
 正则表达式中 .*? 代表什么?
解答:
点代表的是任意字符。* 代表的是取 0 至 无限长度问号代表的是非贪婪模式。三个链接在一起是取尽量少的任意字符,一般不会这么单独写。 用法:
他大多用在:.*?a 解释:
就是取前面任意长度的字符,到底一个 a 出现,匹配如下q@wer_qwerqweraljlkjlkjlkj, 得到:q@wer_qwerqwera 这部分,如果匹配不到后面的 a 字符,则匹配为空。

注意,re的若干方法:
match方法是从字符串开头往后匹配(用的少)
例:
res = re.match('^Chen', 'Chenronghua123')  语法:pattern,string
print(res)
#输出:<_sre.SRE_Match object; span=(0, 4), match='Chen'>
#res = re.match('r.+', 'Chen123ronghua123')  #匹配结果为空,match从字符串开头开始匹配
# res = re.search('r.+', 'Chen123ronghua123') #search 从整个文本中搜索
# print(res.group())
# 结果:ronghua
#如果匹配不到返回None,即res为None,res.group()会报错
常用方法如下
1.search是从整个文本中搜索,匹配到一个就返回
2.findall是从整个文本中搜索,贪婪匹配,如果匹配到多个全部返回,所有结果都放在一个列表中,findall没有group方法
 >>> re.findall('[a-z]','wwwa.d')
['w', 'w', 'w', 'a', 'd']
>>> re.findall('[0-9]','w0w3w4a.99d')
['', '', '', '', ''] >>> re.findall('\d','w0w3w4a.99d')
['', '', '', '', '']
>>> re.findall('\d', 'aa22ww2qq123qwe333')
['', '', '', '', '', '', '', '', '']
>>> re.findall('\d\d', 'aa22ww2qq123qwe333')
['', '', '']
>>> re.findall('\d+', 'aa22ww2qq123qwe333')
['', '', '', ''] >>> re.findall('\w','w0w3w4a.99d')
['w', '', 'w', '', 'w', '', 'a', '', '', 'd']
>>> re.findall('\s','w0w3 w4a.99d')
[' ']

findall结合字符集例子

findall常和分组()搭配使用,分组后利用findall方法只返回分组括号中的数据,爬虫常用,也可取消这种功能,例:
 >>> re.findall('www.(?:baidu|123).com','asd www.baidu.com')  # 在括号的组中加上'?:'即可匹配全部内容,而非仅是分组中的内容
['www.baidu.com']
 findall的分组、无分组:
>>> string = 'hello sky asd sky age sky qwe 19w'
>>>
>>> r = re.findall('a\w+', string)
>>> print(r)
['asd', 'age']
>>> r = re.findall('a(\w+)', string) #此时findall作用相当于groups,但groups把结果放入元组,findall则放入列表中
>>> print(r)
['sd', 'ge']
>>>
>>> string = 'hello sky asd sky age sky qwe 19w'
>>> r = re.findall('(a)(\w+)', string)
>>> print(r)
[('a', 'sd'), ('a', 'ge')] # string从前到后每次匹配到的字符串都放入元组,所有匹配到的内容都放入列表
>>>
>>> r = re.findall('(s)(\w+)(y)', string) # 相当于把groups中的内容放到一起
>>> print(r)
[('s', 'k', 'y'), ('s', 'k', 'y'), ('s', 'k', 'y')] #每个组中都有一个元素,共三个元素
>>>
>>> string = 'hello whisky asd whisky age whisky qwe 19w'
>>> r = re.findall('(i)(\w+(k))(y)', string) #第一个元素是i 第二个:sk 第三个k 第四个:y,有几个括号就提取几次,取出的元素一次放入元组中,最后再把每次匹配的结果放入列表 ,另外,这里不支持re.findall('(i)(\w+(k))(?P<n1>y)', string)模版组名,用finditer可以支持
>>> print(r)
[('i', 'sk', 'k', 'y'), ('i', 'sk', 'k', 'y'), ('i', 'sk', 'k', 'y')]
>>>
>>> string = 'hello whisky asd whisky age whisky qwe 19w'
>>> r = re.finditer('(i)(\w+(k))(?P<n1>y)', string) # 迭代方式可匹配组名
>>> for i in r:
... print(i,i.group(),i.groups(),i.groupdict())
...
<_sre.SRE_Match object; span=(8, 12), match='isky'> isky ('i', 'sk', 'k', 'y') {'n1': 'y'}
<_sre.SRE_Match object; span=(19, 23), match='isky'> isky ('i', 'sk', 'k', 'y'){'n1': 'y'}
<_sre.SRE_Match object; span=(30, 34), match='isky'> isky ('i', 'sk', 'k', 'y'){'n1': 'y'}
>>>

findall 分组,无分组

 findall:注意两个问题
1.findall无分组时匹配所有符合pattern的字符串
>>> n = re.findall('\d+\w\d+','a2b3c4d5')
>>> print(n)
['2b3', '4d5'] # 结果不是3c4,可知findall方法是从前向后逐个匹配,匹配到结果2b3,则去掉2b3,再继续向后匹配
>>> 2.匹配到空的内容会返回
>>> n = re.findall('','a2b3c4d5')
>>> print(n)
['', '', '', '', '', '', '', '', '']
>>> 3.指定分组次数时,因为只有一个括号(分组),所以只匹配最后一次内容
>>> a = 'whisky'
>>> n = re.findall('(\w)(\w)(\w)(\w)', a) #表示分4组,全部返回
>>> print(n)
[('w', 'h', 'i', 's')]
>>> n = re.findall('(\w){4}', a) # 表示拿分组取字符串中匹配4次
>>> print(n)
['s']
>>> 4. findall中的正则(如 *)会匹配到空,那么结果就会输出空,在开发时要避免正则表达式内容为空:
>>> n = re.findall('(\dasd)*','1asd2asdp3asd98kif')
>>> print(n)
['2asd', '', '3asd', '', '', '', '', '', ''] #*默认贪婪匹配,只有一个分组(括号),所以只返回2asd, *为空时,匹配结果为空,字符串最后默认有一个空字符,所以5个字符,匹配出6个空
>>>
>>> n = re.findall('(\dasd)+','1asd2asdp3asd4asd') #改为+,可以匹配想要的内容,不是输出空的结果
>>> print(n)
['2asd', '4asd'] # 因为只有一个括号分组,所以只返回4asd,没有3asd

findall 要注意的问题

 >>> import re
>>> p = re.compile(r'\d+')
>>> w = p.finditer('12 qwesdad44ers running, 22 ... 11 ...')
>>> for match in w:
... match.group(),match.span()
...
('', (0, 2))
('', (10, 12))
('', (25, 27))
('', (32, 34))

finditer方法

小结:

findall其实就是一个一个的search,把search中的groups组合起来成为findall的内容,如果正则表达式中有一个分组,那么会去匹配组中的元素,放入列表;如果正则表达式中有多个组,会把组匹配到内容放到一个元组里面当作列表的一个元素,从前到后,重复此过程最后组成一个列表
3.match,group方法:
 match 无分组:
>>> string = 'hello sky asd sky age sky qwe 19'
>>> r = re.match('h\w+',string)
>>> print(r.group()) # 获取匹配到的所有结果
hello
>>> print(r.groups()) # 只获取匹配到的分组结果
()
>>> print(r.groupdict()) # 获取匹配到的分组中所有执行了key的组
{}
>>> match 有分组(分组作用:提取匹配成功的指定内容。先匹配成功全部正则,再把匹配成功的局部内容提取出来):
>>> string = 'hello sky asd sky age sky qwe 19'
>>> r = re.match('h(\w+)',string)
>>> print(r.group())
hello
>>> print(r.groups())
('ello',)
>>> print(r.groupdict())
{}
>>>
指定分组名,放入字典
>>> string = 'hello sky asd sky age sky qwe 19'
>>> r = re.match("(?P<n1>h)(?P<n2>\w+)",string)
>>> print(r.group())
hello
>>> print(r.groups())
('h', 'ello')
>>> print(r.groupdict())
{'n1': 'h', 'n2': 'ello'}
>>> 小结:
对于group方法,无论是否有分组,将会匹配正则表达式中匹配到的所有结果
对于groups方法,在有分组时,将匹配分组括号中(可以有多个分组)的内容,无分组则结果为空
对于groupdict方法,在有分组时,将匹配分组中所有执行了key的组。无分组则结果为空
写法:(?P<组名>正则表达式),输出(以字典的形式输出):{'组名':'正则匹配的结果'},常用语jangle中的路由系统
无分组匹配时,上述三个方法,只有group有意义
4.split分隔方法
 # split
# 无分组
string = 'hello sky ald qwe lge zxc 27'
n = re.split('s\w+', string)
print(n)
# 输出 ['hello ', ' ald qwe lge zxc 27'] # 有分组,split方法输出的结果如果用了分组,只保留分组中的内容
n = re.split('(s\w+)', string)
print(n)
# 输出 ['hello ', 'sky', ' ald qwe lge zxc 27']
n = re.split('s(\w+)', string)
print(n)
# 输出 ['hello ', 'ky', ' ald qwe lge zxc 27'] inpp = '1-2*((60-30 +(-40-5)*(9-2*5/3 + 7/3*99/4*2998 +10 * 568/14)) - (-4*3)/(16-3*2))'
n = re.split('\(([^()]+)\)', inpp) # 分割不含括号的最里层表达式,并去掉括号(表达式中转义符去匹配括号,里边括号作用split结果只取分组中的内容)
print(n)
# 输出 ['1-2*((60-30 +', '-40-5', '*', '9-2*5/3 + 7/3*99/4*2998 +10 * 568/14', ') - ', '-4*3', '/', '16-3*2', ')']

split 分组,无分组

4.sub替换方法
 # sub不涉及分组
string = '1qqas2uuii234ashjd888kkasd333'
n = re.sub('\d+', '----', string)
print(n)
new_str, count = re.subn('\d+', 'KKK', string)
print(new_str, count) #输出:
----qqas----uuii----ashjd----kkasd----
('KKKqqasKKKuuiiKKKashjdKKKkkasdKKK', 5)

sub,subn方法

5.start() 返回匹配开始的位置
end()  返回匹配结束的位置  
6.span() 返回一个元组包含匹配(开始,结束)的位置 几个匹配模式
1.re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
2.re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图) [用得很少]
3.re.S(DOTALL): 使.匹配包括换行在内的所有字符,点任意匹配模式,改变'.'的行为
贪婪和非贪婪:
 >>> re.search(r'a(\d+)','a3333333345b').group()
'a3333333345'
>>> re.search(r'a(\d+?)','a3333333345b').group()
'a3'
>>> re.search(r'a(\d*)','a3333333345b').group()
'a3333333345'
>>> re.search(r'a(\d*?)','a3333333345b').group()
'a' 如果分组括号两侧都有限制条件即:a()b,则分组中的?非贪婪匹配不再起作用
>>> re.findall(r'a(\d+)b','a23b')
['']
>>> re.findall(r'a(\d+?)b','a23b')
['']
>>>

原生字符串:(字符串前面加r,即声明使用原生字符串):
正则表达式中的r:(使用r前缀后,匹配字符串中所有字符都不转义,特殊字符不再有转义功能,只代表一个字符串)
r意思就是raw data,也就是原始数据,不用转义的。比如在一个字符串里面包含斜杠和一个字母n,"\n"就错了,这里的斜杠和n的组合在python中表示一个换行,必须"\\n",也就是用反斜杠来转义反斜杠。但是用r后面接字符串就没这个问题了,r"\n"中的\n就是这两个个字母本身了。
 >>> import re
>>> re.search(r"\\","ba\cabc").group()
'\\'
>>> re.search("\\","ba\cabc").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
>>> re.search(r"\\","ba\cabc").group()
'\\'
>>> re.findall("\\","ba\cabc")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
>>> re.findall(r"\\","ba\cabc")
['\\']

注:

在python中,\n是换行,\r是回车,\b是退格

 python中关于正则内的\b,为什么使用\b时需要用r'\b',但是\w则不需要?
解答:
因为\b 有两种解释,而\w 只有一种。 \b的两种解释是: 1.'\b', 如果前面不加r, 那么解释器认为是转义字符“退格键backspace”;
2.r'\b', 如果前面加r, 那么解释器不会进行转义,\b 解释为正则表达式模式中的字符串边界。 而相比于\b, \w 只有第二种解释,并没有对应的转义字符,所以不加r, 也不会出错。

问答

 >>> import re
>>> re.findall('abc\b','asdas abc ') # 由于\b在python中表示退格,所以匹配不到内容
[]
>>> re.findall('abc\\b','asdas abc ') # 转义
['abc']
>>> re.findall(r'abc\b','asdas abc ') # 声明原生字符串,\b此时表示单词边界
['abc']
>>>

例子


split方法:
res = re.split('[0-9]+', 'abc12de3f45GH')
print(res)
输出:['abc', 'de', 'f', 'GH'] sub方法:
res = re.sub('[0-9]+', '|', 'abc12de3f45GH', count=2)
print(res)
输出:abc|de|f45GH 1.re.I(re.IGNORECASE): 忽略大小写
res = re.search('[a-z]+', 'abcGH', flags=re.I)
print(res.group())
输出:abcGH 2.M(MULTILINE): 多行模式,改变'^'和'$'的行为
res = re.search(r"^a", "\nabc\neee", flags=re.M)
print(res.group())
输出:a 3.S(DOTALL): 点任意匹配模式,改变'.'的行为
res = re.search(".+", "\nabc\neee", flags=re.S)
print(res.group())
输出:a 举例:
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 res = re.match('.+', 'Chen123ronghua123')
print(res.group())
输出:
Chen123ronghua123 '$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以 res = re.match('r.+', 'Chen123ronghua123') #匹配结果为空,match从字符串开头开始匹配
res = re.search('r.+', 'Chen123ronghua123') #search 从整个文本中搜索
print(res.group())
结果:ronghua '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
res = re.search('r[a-z]+a', 'Chen123ronghua123') #匹配ronghua
print(res.group())
结果:ronghua res = re.search('#.+#', '1123#hello#')
print(res.group())
结果:#hello# '?' 匹配前一个字符1次或0次
res0 = re.search('aal?', 'aalex')
res1 = re.search('aal?', 'aaex')
print(res0.group())
print(res1.group())
输出
aal
aa '{m}' 匹配前一个字符m次
res = re.search('[0-9]{3}', 'aa1xe2pp345lex') #匹配前面的数字三次
print(res.group()) '{n,m}' 匹配前一个字符n到m次
res = re.search('[0-9]{1,3}', 'aa1xe2pp345lex') #匹配前面的数字1到3次
print(res.group())
输出 1 findall 贪婪匹配
res = re.findall('[0-9]{1,3}', 'aa1xe2pp345lex') #findall,贪婪匹配,匹配前面的数字1到3次
print(res)
输出['1', '2', '345'] #以列表的形式返回 '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC' res = re.search('abc|ABC', 'ABCBabcCD')
print(res.group())
输出 ABC res = re.findall('abc|ABC', 'ABCBabcCD')
print(res)
输出 ['ABC', 'abc'] '(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c res = re.search('(abc){2}', 'alexabcabc')
print(res.group())
输出 abcabc res = re.search('(abc){2}(\|\|=){2}', 'alexabcabc||=||=') 匹配||= 两次,注意需要转义
print(res.group())
输出:abcabc||=||= '\D' 匹配非数字
res = re.search('\D+', '123$- a')
print(res.group())
输出:$- a '\w' 匹配[A-Za-z0-9] 除了特殊字符都匹配 res = re.search('\w+', '123$- a')
print(res.group())
输出:123 '\W' 匹配非[A-Za-z0-9] 只匹配特殊字符
res = re.search('\W+', '123$- ...a')
print(res.group())
输出:$- ... '\s' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
res = re.findall('\s', '123$- \r\n\t...a')
print(res)
输出:[' ', '\r', '\n', '\t'] >>> re.search('\s+', '123$- \r\n')
<_sre.SRE_Match object; span=(5, 9), match=' \t\r\n'> '\A' 效果和^是一样的,只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9 例:
res = re.search('\A[0-9]+[a-z]\Z', '123a')
print(res.group())
输出:123a * : 0个至多个
+ :1个至多个 res = re.match('^Chen\d+', 'Chen123ronghua123')
print(res)
print(res.group()) #查看匹配到的对象 输出:<_sre.SRE_Match object; span=(0, 7), match='Chen123'>
Chen123 '(?P<name>...)' 分组匹配
res = re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city")
print(res)
结果{'province': '3714', 'city': '81', 'birthday': '1993'}

python正则-- re模块