元字符释义
-
.
代指任意字符 -
^
从字符串开始匹配 -
$
匹配字符串的结尾 -
*
匹配前面挨着的字符,能匹配0
到无穷次 -
+
同*
,能匹配1
到无穷次(最少1
个) -
?
匹配前面挨着的字符,匹配0
或1
次 -
{}
自定义匹配次数,{1,6}
匹配1
到6
次,{6}
匹配6
次(重复匹配前面挨着的字符) -
[]
匹配中括号中的任意字符,[x,y*]
匹配x
或y
或,或*
(括号中无特殊字符),但以下几个除外-
如[a-z]
,匹配a
到z
中的任意字符^
如[^a-z]
,非,匹配不是a
到z
以外的任意字符\
转义
-
|
或,如'a|b'
匹配'a'
或'b'
-
()
分组,如'(abc)'
匹配'abc'
(?P<name>\w+)
'?P<name>'
为固定格式,name
为对该组进行命名,'\w'
为真正的匹配规则- 上面的固定格式可不写,主要便于阅读和读取返回结果
-
\
转义,有以下功能- 将无意义的普通字符变为有意义
-
\d
匹配任何十进制数,即0-9
-
\D
匹配任何非数字字符,相当于[^0-9]
-
\s
匹配任何空白字符,相当于[\t\n\r\f\v]
-
\S
匹配任何非空白字符,相当于[^\t\n\r\f\v]
-
\w
对于 Unicode (str) 样式:
匹配Unicode
词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配[a-zA-Z0-9_]
。对于
8
位(bytes)样式:
匹配ASCII
字符中的数字和字母和下划线,就是[a-zA-Z0-9_]
。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。 -
\W
匹配非单词字符的字符。这与 \w 正相反。如果使用了 ASCII 旗标,这就等价于[^a-zA-Z0-9_]
。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。 -
\b
匹配一个特殊字符边界,如空格,&
,#
等
-
- 将有意义的元字符变为无意义
如\. \* \^ \$
等
- 将无意义的普通字符变为有意义
基本使用
查找所有匹配的内容
In [6]: re.findall(r'\d', '12+(34*6+2-5*(2-1))')
Out[6]: ['1', '2', '3', '4', '6', '2', '5', '2', '1']
查找第一个匹配的内容
In [10]: m = re.search(r'(\d)', '12+(34*6+2-5*(2-1))')
In [11]: m.groups()
Out[11]: ('1',)
使用分组
分组可以在需要其他规则辅助定位,但是又不想获取这些规则所匹配到的内容时使用。
In [68]: re.findall(r'(\w+)\.', 'abd. efg. 123sd')
Out[68]: ['abd', 'efg']
可以使用 ?P<name>
为分组命名,并通过分组名获取内容:
In [70]: re.search(r'(?P<wgroup>\w+)\.', 'abd. efg. 123sd').groups('wgroup')
Out[70]: ('abd',)
迭代返回匹配的结果
如果匹配的内容太多,可以使用该方法优化内容使用。
In [5]: re.finditer(r'\d', '12+(34*6+2-5*(2-1))')
Out[5]: <callable_iterator at 0x283dbd4bdf0>
从字符串起始位置开始匹配
In [15]: re.match(r'h', 'hello')
Out[15]: <re.Match object; span=(0, 1), match='h'>
In [16]: re.match(r'e', 'hello') # None
分割字符串
In [22]: re.split('ab', 'abcd')
Out[22]: ['', 'cd']
用括号将分割的标志包裹起来,可以保留分割的内容:
In [23]: re.split('(ab)', 'abcd')
Out[23]: ['', 'ab', 'cd']
替换字符串
In [31]: re.sub('[a-z]', '-', 'a123b')
Out[31]: '-123-'
指定最大的替换次数:
In [32]: re.sub('[a-z]', '-', 'a123b', 1)
Out[32]: '-123b'
同时获取替换的次数
In [33]: re.subn('[a-z]', '-', 'a123b')
Out[33]: ('-123-', 2)
替换时引用前面匹配到的内容
使用命名组:
In [37]: re.sub('(?P<w>[a-z])', '\g<w>-', 'a123b') # 将 'a' 替换为 'a-', 'b' 替换为 'b-'
Out[37]: 'a-123b-'
不使用命名组:
In [39]: re.sub('([a-z])', '\g<1>-', 'a123b')
Out[39]: 'a-123b-'
预编译规则
预编译可以避免每次调用时的编译性能消耗,虽然 re
库也会在内部做缓存,但缓存的数量是有限的,这会导致所传入的表达式不总是能走缓存,使用预编译可以保证只编译一次。
In [40]: comp = re.compile(r'\d+')
In [41]: comp.findall('nasa1') # 编译后的对象可以调用 search, findall 等匹配方法
Out[41]: ['1']
常用技巧
多行文本匹配时,匹配每一行的内容
In [17]: text = """
...: this is
...: a
...: multiple
...: line
...: text
...: .
...: """
In [19]: re.findall('^[al]', text, re.M) # 匹配以字母 a, l 开始的行首字母
Out[19]: ['a', 'l']
使用多个 flags
如果要同时忽略大小写,以及多行模式匹配,可以使用 |
将多个 flag
拼接起来
In [20]: text = """
...: this is
...: A
...: multiple
...: Line
...: text
...: .
...: """
In [21]: re.findall('^[al]', text, flags=re.M | re.I)
Out[21]: ['A', 'L']
匹配中文
In [3]: re.findall(r'[\u4e00-\u9fa5]', '你好,我是 john')
Out[3]: ['你', '好', '我', '是']
或使用双字节字符匹配(可以包含中文标点符号):
In [4]: re.findall(r'[^\x00-\xff]', '你好,我是 john')
Out[4]: ['你', '好', ',', '我', '是']
匹配不包含某个字符串的的内容
In [64]: re.findall(r'\b((?!abc)\w+)', 'abcdefg123')
Out[64]: []
In [66]: re.findall(r'\b((?!abc)\w+)', 'abdefg123')
Out[66]: ['abdefg123']
对上述表达式的解释:
\b
匹配单词的开始或结束?!<exp>
零宽负向先行断言,只会匹配后缀<exp>
不存在的位置\w
匹配字母或数字或下划线或汉字+
重复一次或更多次\b((?!abc)\w)+
匹配由字母或数字或下划线或汉字组成的字串,但字串中不能出现abc
匹配多个连串的字符(去掉分组优先级)
比如,想匹配以 abc
或 123
开始的内容,但是又不想把 abc
或 123
作为一个分组,可以使用 ?:
去掉分组优先级:
In [73]: re.findall(r'(?P<wgroup>(?:123|abc)\.)', 'abc. efg. 123.')
Out[73]: ['abc.', '123.']
其中 (?:123|abc)
使用了分组的语法,但不会被视为一个分组。
其它实例
匹配可有可无的字符
如 http/https 中的 s
In [78]: pat = re.compile(r'((?:http|https)://.*?/)')
In [79]: pat.findall('http://www.zhparks.com/upload/')
Out[79]: ['http://www.zhparks.com/']
In [80]: pat.findall('https://www.zhparks.com/upload/')
Out[80]: ['https://www.zhparks.com/']