正则表达式基础知识
re.compile
compile 函数用于编译正则表达式,生成一个 Pattern 对象1
2
3import re
regex = re.compile(r'(\d+)')
re.match
match(string[, pos[, endpos]])方法回从字符串开头开始匹配,也可以指定起始位置和结束位置,找到第一个匹配就返回。成功匹配的话把各分组匹配到的字符串放入到一个Match对象,需要使用group(分组编号)获取对应分组的字符串或使用groups()方法获取所有分组的结果,匹配不成功返回None。
1 | import re |
但是,match返回的是每个分组的结果,所以必须在正则表达式里带上()进行分组,否则(即一个()分组都没),在存在满足正则表达式的情况下使用groups返回的很有可能是一个空的元组1
2
3
4
5
6
7
8
9
10
11import re
# 正则没有使用分组
regex = re.compile(r'\d+')
str1 = '66abcd78dfg9sdf0'
# match 的使用
result = regex.match(str1)
print(result.groups()) # ()
print(result.group(1)) # IndexError: no such group
re.search
search(string[, pos[, endpos]])方法用于查找字符串的任何位置,也可以指定起始和结束位置,只要找到了一个匹配的结果就返回。使用方法和match一样,区别在于match是从字符串开头,search不限定从字符串开头匹配。匹配不成功返回None1
2
3
4
5
6
7
8
9
regex = re.compile(r'(\d+)')
str1 = 'abcd78dfg9sdf0'
# search 的使用
result = regex.search(str1)
print(result.groups()) # ('78',)
print(result.group(1)) # 78
因为search返回的是每个分组的结果,和match一样,所以必须在正则表达式里带上()进行分组,否则(即一个()分组都没),在存在满足正则表达式的情况下使用groups返回的很有可能是一个空的元组1
2
3
4
5
6
7
8
9
10import re
regex = re.compile(r'\d+')
str1 = 'abcd78dfg9sdf0'
# search 的使用
result = regex.search(str1)
print(result.groups()) # ()
print(result.group(1)) # IndexError: no such group
re.findall
findall(string[, pos[, endpos]])方法是查找这个字符串符合正则表达式的所有结果并放到一个列表中,返回一个列表,而不是成功匹配一个就结束,全部匹配不成功就返回空列表[]。1
2
3
4
5
6
7
8import re
regex = re.compile(r'\d+')
str1 = '66abcd78dfg9sdf0'
# findall 的使用
result = regex.findall(str1)
print(result) # ['66', '78', '9', '0']
re.finditer
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import re
regex = re.compile(r'\d+')
str1 = '66abcd78dfg9sdf0'
# finditer 的使用
result = regex.finditer(str1)
print(type(result)) # <class 'callable_iterator'>
for item in result: # item 是Match 对象
print(item.group())
#66
#78
#9
#0
re.split
split(string[, maxsplit])按照匹配到的子符串将原字符串分割后返回到一个列表,maxsplit 用于指定最大分割次数,不指定将全部分割。1
2
3
4
5
6
7import re
regex = re.compile(r'[\s;,:]+')
str1 = 'a;b,c:d e f'
print(regex.split(str1))
# ['a', 'b', 'c', 'd', 'e', 'f']
re.sub
sub(repl, string[, count])方法用于替换。
其中,repl 可以是字符串也可以是一个函数,count 用于指定最多替换次数,不指定时全部替换即会像findall那样匹配整个字符串。
如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
1
2
3
4
5
6
7
8
9
10import re
regex = re.compile(r'(\w+) (\w+)')
str1 = 'hello 123, hello 456'
print (regex.sub(r'hello world', str1))
# hello world, hello world
print (regex.sub(r'\2 \1', str1))
# 123 hello, 456 hello如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
1 | import re |
贪婪与非贪婪
贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );
非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );
Python里数量词默认是贪婪的。1
2
3
4
5
6
7
8
9
10
11
12
13
14import re
str1 = '<div>abcd</div><div>efgh</div>'
regex_greed = re.compile(r'<div>.*</div>')
regex_not_greed = re.compile(r'<div>.*?</div>')
result_greed = regex_greed.findall(str1)
result_not_greed = regex_not_greed.findall(str1)
print(result_greed)
# ['<div>abcd</div><div>efgh</div>']
print(result_not_greed)
# ['<div>abcd</div>', '<div>efgh</div>']
匹配中文
中文的 unicode 编码范围 主要在 [u4e00-u9fa5]1
2
3
4
5
6
7import re
str1 = '你好世界,hello world'
pattern = re.compile(r'[\u4e00-\u9fa5]+')
result = pattern.findall(str1)
print (result) # 你好世界
特殊构造?:的用法
当?:出现在正则表达式时,虽然正则表达式中使用()但这时()已经失去分组的特殊功能,表示(?:…)不分组版本,后面可以接|或这数量词,看例子:
?:结合|的使用
我们想获取所有abc或者efg的字符串,当没有使用?:的情况:1
2
3
4
5
6
7import re
regex = re.compile(r'(abc)|(efg)')
str1 = 'abchhggefg'
result = regex.findall(str1)
print(result) # [('abc', ''), ('', 'efg')]
我们想获取所有abc或者efg的字符串,使用了?:之后,符合我们的预期:1
2
3
4
5
6
7import re
regex = re.compile(r'(?:abc)|(?:efg)')
str1 = 'abchhggefg'
result = regex.findall(str1)
print(result) # ['abc', 'efg']
?:结合数量词{m}的使用
我们想匹配abc连续出现2次的字符串
没结合?:的输出结果
1
2
3
4
5
6
7import re
str1 = 'edabcabcefg'
regex = re.compile(r'(abc){2}')
result = regex.findall(str1)
print(result) # ['abc']结合?:的输出结果,符合预期
1
2
3
4
5
6
7import re
str1 = 'edabcabcefg'
regex = re.compile(r'(?:abc){2}')
result = regex.findall(str1)
print(result) # ['abcabc']