python正则-- re模块



匹配数字相关
'.' 默认匹配除\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}
'[]' 字符集,匹配[]中的字符(其中的字符是或的关系),其中的字符可以一一列出,也可以给出范围,元字符在其中失去意义,除非元字符前面加了反斜杠。有几种特殊的元字符依然有意义:表示范围的'-', 取反的'^',和'\'
1 >>> re.search('[a|b]','aabcd').group()   # search方法在字符集匹配时只匹配一次
2 'a'
3 >>> re.search('[a|b]+','aabcd').        # '+' 匹配一次或多次字符集中的内容
4 'aab'
5 
6 >>> re.findall('[a|b]','aabcd')
7 ['a', 'a', 'b']
8 >>>    
View Code
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c。 分组匹配时,findall只返回分组括号中的内容,返回到一个列表,分组作用:为了在已经匹配到的内容中再去提取过滤内容,有几个括号就提取几次
'\' 1.后面跟元字符去除特殊功能,2.跟普通字符实现特殊功能(\d:匹配数字),3.引用序号对应的字组所匹配的字符串
1 >>> re.search(r"(whisky)(\d+)com\2","whisky211985com211985").group()
2 'whisky211985com211985'
View Code

 


'\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’  匹配一个单词边界,即单词和空格(或特殊字符)间的位置,字符串开头结尾及空格回车等的位置,不会匹配空格符本身
 1 >>> import re
 2 >>> re.findall('abc\b','asdas abc ')
 3 []                                                   # 没有声明原生字符串或转义,所以结果为空
 4 >>> re.findall('abc\\b','asdas abc ')
 5 ['abc']
 6 >>> re.findall(r'abc\b','asdas abc ')
 7 ['abc']
 8 >>> re.findall(r'abc\b','asdas abc*')
 9 ['abc']                                           # 特殊字符作为单词边界
10 
11 >>> re.findall(r'i\b','i miss iou')
12 ['i']
13 >>> re.findall(r'i\b','imiss iou')
14 []
15 >>> re.findall(r'\bi',' imiss iou')     # 以空格为单词边界
16 ['i', 'i']
17 >>> re.findall(r'\bi','imiss iou')      #以字符串开头和空格为单词边界
18 ['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<组名>正则表达式),输出(以字典的形式输出):{'组名':'正则匹配的结果'}


(*|+|?|{})? : *、+、?、{}后面加?使用非贪婪模式

 

 1 正则表达式中 .*? 代表什么?
 2 解答:
 3 点代表的是任意字符。* 代表的是取 0 至 无限长度问号代表的是非贪婪模式。三个链接在一起是取尽量少的任意字符,一般不会这么单独写。
 4 
 5 用法:
 6 他大多用在:.*?a
 7 
 8 解释:
 9 就是取前面任意长度的字符,到底一个 a 出现,匹配如下q@wer_qwerqweraljlkjlkjlkj,
10 
11 得到: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方法
 1 >>> re.findall('[a-z]','wwwa.d')
 2 ['w', 'w', 'w', 'a', 'd']
 3 >>> re.findall('[0-9]','w0w3w4a.99d')
 4 ['0', '3', '4', '9', '9']
 5 
 6 >>> re.findall('\d','w0w3w4a.99d')
 7 ['0', '3', '4', '9', '9']
 8 >>> re.findall('\d', 'aa22ww2qq123qwe333')
 9 ['2', '2', '2', '1', '2', '3', '3', '3', '3']
10 >>> re.findall('\d\d', 'aa22ww2qq123qwe333')
11 ['22', '12', '33']
12 >>> re.findall('\d+', 'aa22ww2qq123qwe333')
13 ['22', '2', '123', '333']
14 
15 >>> re.findall('\w','w0w3w4a.99d')
16 ['w', '0', 'w', '3', 'w', '4', 'a', '9', '9', 'd']
17 >>> re.findall('\s','w0w3 w4a.99d')
18 [' ']
findall结合字符集例子
findall常和分组()搭配使用,分组后利用findall方法只返回分组括号中的数据,爬虫常用,也可取消这种功能,例:
1 >>> re.findall('www.(?:baidu|123).com','asd www.baidu.com')  # 在括号的组中加上'?:'即可匹配全部内容,而非仅是分组中的内容
2 ['www.baidu.com']
View Code
 1 findall的分组、无分组:
 2 >>> string = 'hello sky asd sky age sky  qwe 19w'
 3 >>>
 4 >>> r = re.findall('a\w+', string)
 5 >>> print(r)
 6 ['asd', 'age']
 7 >>> r = re.findall('a(\w+)', string)    #此时findall作用相当于groups,但groups把结果放入元组,findall则放入列表中
 8 >>> print(r)
 9 ['sd', 'ge']
10 >>>
11 >>> string = 'hello sky asd sky age sky  qwe 19w'
12 >>> r = re.findall('(a)(\w+)', string)
13 >>> print(r)
14 [('a', 'sd'), ('a', 'ge')]        # string从前到后每次匹配到的字符串都放入元组,所有匹配到的内容都放入列表
15 >>>
16 >>> r = re.findall('(s)(\w+)(y)', string)    # 相当于把groups中的内容放到一起
17 >>> print(r)
18 [('s', 'k', 'y'), ('s', 'k', 'y'), ('s', 'k', 'y')]   #每个组中都有一个元素,共三个元素
19 >>>
20 >>> string = 'hello whisky asd whisky age whisky  qwe 19w'
21 >>> r = re.findall('(i)(\w+(k))(y)', string)             #第一个元素是i 第二个:sk 第三个k 第四个:y,有几个括号就提取几次,取出的元素一次放入元组中,最后再把每次匹配的结果放入列表 ,另外,这里不支持re.findall('(i)(\w+(k))(?P<n1>y)', string)模版组名,用finditer可以支持
22 >>> print(r)
23 [('i', 'sk', 'k', 'y'), ('i', 'sk', 'k', 'y'), ('i', 'sk', 'k', 'y')]
24 >>>
25 >>> string = 'hello whisky asd whisky age whisky  qwe 19w'
26 >>> r = re.finditer('(i)(\w+(k))(?P<n1>y)', string)        # 迭代方式可匹配组名
27 >>> for i in r:
28 ...     print(i,i.group(),i.groups(),i.groupdict())
29 ...
30 <_sre.SRE_Match object; span=(8, 12), match='isky'> isky ('i', 'sk', 'k', 'y') {'n1': 'y'}
31 <_sre.SRE_Match object; span=(19, 23), match='isky'> isky ('i', 'sk', 'k', 'y'){'n1': 'y'}
32 <_sre.SRE_Match object; span=(30, 34), match='isky'> isky ('i', 'sk', 'k', 'y'){'n1': 'y'}
33 >>>
34  
findall 分组,无分组
 1 findall:注意两个问题
 2 1.findall无分组时匹配所有符合pattern的字符串
 3 >>> n = re.findall('\d+\w\d+','a2b3c4d5')
 4 >>> print(n)
 5 ['2b3', '4d5']     # 结果不是3c4,可知findall方法是从前向后逐个匹配,匹配到结果2b3,则去掉2b3,再继续向后匹配
 6 >>>
 7 
 8 2.匹配到空的内容会返回
 9 >>> n = re.findall('','a2b3c4d5')
10 >>> print(n)
11 ['', '', '', '', '', '', '', '', '']
12 >>>
13 
14 3.指定分组次数时,因为只有一个括号(分组),所以只匹配最后一次内容
15 >>> a = 'whisky'
16 >>> n = re.findall('(\w)(\w)(\w)(\w)', a)  #表示分4组,全部返回
17 >>> print(n)
18 [('w', 'h', 'i', 's')]
19 >>> n = re.findall('(\w){4}', a)  # 表示拿分组取字符串中匹配4次
20 >>> print(n)
21 ['s']
22 >>>
23 
24 4. findall中的正则(如 *)会匹配到空,那么结果就会输出空,在开发时要避免正则表达式内容为空:
25 >>> n = re.findall('(\dasd)*','1asd2asdp3asd98kif')
26 >>> print(n)
27 ['2asd', '', '3asd', '', '', '', '', '', '']   #*默认贪婪匹配,只有一个分组(括号),所以只返回2asd, *为空时,匹配结果为空,字符串最后默认有一个空字符,所以5个字符,匹配出6个空
28 >>>
29 >>> n = re.findall('(\dasd)+','1asd2asdp3asd4asd')  #改为+,可以匹配想要的内容,不是输出空的结果
30 >>> print(n)
31 ['2asd', '4asd']   # 因为只有一个括号分组,所以只返回4asd,没有3asd
findall 要注意的问题
 1 >>> import re
 2 >>> p = re.compile(r'\d+')
 3 >>> w = p.finditer('12 qwesdad44ers running, 22 ... 11 ...')
 4 >>> for match in w:
 5 ...     match.group(),match.span()
 6 ...
 7 ('12', (0, 2))
 8 ('44', (10, 12))
 9 ('22', (25, 27))
10 ('11', (32, 34))
finditer方法

 

小结:

findall其实就是一个一个的search,把search中的groups组合起来成为findall的内容,如果正则表达式中有一个分组,那么会去匹配组中的元素,放入列表;如果正则表达式中有多个组,会把组匹配到内容放到一个元组里面当作列表的一个元素,从前到后,重复此过程最后组成一个列表

3.match,group方法:
 1 match 无分组:
 2 >>> string = 'hello sky asd sky age sky  qwe 19'
 3 >>> r = re.match('h\w+',string)
 4 >>> print(r.group())      # 获取匹配到的所有结果
 5 hello
 6 >>> print(r.groups())    # 只获取匹配到的分组结果
 7 ()
 8 >>> print(r.groupdict())  # 获取匹配到的分组中所有执行了key的组
 9 {}
10 >>>
11 
12 match 有分组(分组作用:提取匹配成功的指定内容。先匹配成功全部正则,再把匹配成功的局部内容提取出来):
13 >>> string = 'hello sky asd sky age sky  qwe 19'
14 >>> r = re.match('h(\w+)',string)
15 >>> print(r.group())
16 hello
17 >>> print(r.groups())
18 ('ello',)
19 >>> print(r.groupdict())
20 {}
21 >>>
22 指定分组名,放入字典
23 >>> string = 'hello sky asd sky age sky  qwe 19'
24 >>> r = re.match("(?P<n1>h)(?P<n2>\w+)",string)
25 >>> print(r.group())
26 hello
27 >>> print(r.groups())
28 ('h', 'ello')
29 >>> print(r.groupdict())
30 {'n1': 'h', 'n2': 'ello'}
31 >>>
32 
33 小结:
34  对于group方法,无论是否有分组,将会匹配正则表达式中匹配到的所有结果
35  对于groups方法,在有分组时,将匹配分组括号中(可以有多个分组)的内容,无分组则结果为空
36  对于groupdict方法,在有分组时,将匹配分组中所有执行了key的组。无分组则结果为空
37 写法:(?P<组名>正则表达式),输出(以字典的形式输出):{'组名''正则匹配的结果'},常用语jangle中的路由系统
38 无分组匹配时,上述三个方法,只有group有意义
View Code
4.split分隔方法
 1 # split
 2 # 无分组
 3 string = 'hello sky ald qwe lge zxc 27'
 4 n = re.split('s\w+', string)
 5 print(n)
 6 # 输出 ['hello ', ' ald qwe lge zxc 27']
 7 
 8 # 有分组,split方法输出的结果如果用了分组,只保留分组中的内容
 9 n = re.split('(s\w+)', string)
10 print(n)
11 # 输出 ['hello ', 'sky', ' ald qwe lge zxc 27']
12 n = re.split('s(\w+)', string)
13 print(n)
14 # 输出 ['hello ', 'ky', ' ald qwe lge zxc 27']
15 
16 inpp = '1-2*((60-30 +(-40-5)*(9-2*5/3 + 7/3*99/4*2998 +10 * 568/14)) - (-4*3)/(16-3*2))'
17 n = re.split('\(([^()]+)\)', inpp)    # 分割不含括号的最里层表达式,并去掉括号(表达式中转义符去匹配括号,里边括号作用split结果只取分组中的内容)
18 print(n)
19 # 输出 ['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替换方法
 1 # sub不涉及分组
 2 string = '1qqas2uuii234ashjd888kkasd333'
 3 n = re.sub('\d+', '----', string)
 4 print(n)
 5 new_str, count = re.subn('\d+', 'KKK', string)
 6 print(new_str, count)
 7 
 8 #输出:
 9 ----qqas----uuii----ashjd----kkasd----
10 ('KKKqqasKKKuuiiKKKashjdKKKkkasdKKK', 5)
sub,subn方法
5.start() 返回匹配开始的位置
end()  返回匹配结束的位置  
6.span() 返回一个元组包含匹配(开始,结束)的位置


几个匹配模式
1.re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
2.re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图) [用得很少]
3.re.S(DOTALL): 使.匹配包括换行在内的所有字符,点任意匹配模式,改变'.'的行为

贪婪和非贪婪:
 1 >>> re.search(r'a(\d+)','a3333333345b').group()
 2 'a3333333345'
 3 >>> re.search(r'a(\d+?)','a3333333345b').group()
 4 'a3'
 5 >>> re.search(r'a(\d*)','a3333333345b').group()
 6 'a3333333345'
 7 >>> re.search(r'a(\d*?)','a3333333345b').group()
 8 'a'
 9 
10 如果分组括号两侧都有限制条件即:a()b,则分组中的?非贪婪匹配不再起作用
11 >>> re.findall(r'a(\d+)b','a23b')
12 ['23']
13 >>> re.findall(r'a(\d+?)b','a23b')
14 ['23']
15 >>>
View Code

 





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

 注:

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

 1 python中关于正则内的\b,为什么使用\b时需要用r'\b',但是\w则不需要?
 2 解答:
 3 因为\b 有两种解释,而\w 只有一种。
 4 
 5 \b的两种解释是:
 6 
 7 1.'\b', 如果前面不加r, 那么解释器认为是转义字符“退格键backspace”;
 8 2.r'\b', 如果前面加r, 那么解释器不会进行转义,\b 解释为正则表达式模式中的字符串边界。
 9 
10 而相比于\b, \w 只有第二种解释,并没有对应的转义字符,所以不加r, 也不会出错。
问答
1 >>> import re
2 >>> re.findall('abc\b','asdas abc ')   # 由于\b在python中表示退格,所以匹配不到内容
3 []
4 >>> re.findall('abc\\b','asdas abc ')  # 转义
5 ['abc']
6 >>> re.findall(r'abc\b','asdas abc ')    # 声明原生字符串,\b此时表示单词边界
7 ['abc']
8 >>>
例子

 



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'}





posted @ 2017-01-14 10:59  whitesky-root  阅读(429)  评论(0编辑  收藏  举报