纸上得来终觉浅,绝知此事要躬行。
Python
的 re
模块提供各种正则表达式的匹配操作,和 Perl
脚本的正则表达式功能类似,使用这一内嵌于 Python
的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。Python
会将正则表达式转化为字节码,利用 C
语言的匹配引擎进行深度优先的匹配。
1. 正则匹配方式
- match
- 匹配格式:
re.match(pattern, string, flags=0)
- 使用说明:从给定字符串的首字母开始逐个匹配
In [2]: re.match('test', 'test')
Out[2]: <_sre.SRE_Match object; span=(0, 4), match='test'>
In [3]: re.match('test', 'atest')
- search
- 匹配格式:
re.search(pattern, string, flags=0)
- 使用说明:从给定字符串中任意位置开始匹配
In [4]: re.search('test', 'atest')
Out[4]: <_sre.SRE_Match object; span=(1, 5), match='test'>
In [5]: re.search('test', 'test123')
Out[5]: <_sre.SRE_Match object; span=(0, 4), match='test'>
In [6]: re.search('test', 'test')
Out[6]: <_sre.SRE_Match object; span=(0, 4), match='test'>
- compile
- 匹配格式:
re.compile(r'xxx', flags=0)
- 使用说明:编译正则表达式是为了加速执行效率
In [37]: regex = re.compile(r'^\d{1,3}$')
In [38]: regex.match('12')
Out[38]: <_sre.SRE_Match object; span=(0, 2), match='12'>
In [39]: regex.search('12')
Out[39]: <_sre.SRE_Match object; span=(0, 2), match='12'>
In [42]: regex.pattern
Out[42]: '^\\d{1,3}$'
In [43]: regex.flags
Out[43]: 32
In [44]: regex.groups
Out[44]: 0
In [45]: regex.groupindex
Out[45]: mappingproxy({})
语法 |
说明 |
re.I |
re.IGNORECASE ;忽略字母大小写 |
re.M |
re.MULTILINE ;多行模式,改变'^' 和'$' 的行为 |
re.S |
re.DOTALL ;使用. 匹配包括换行在内的所有字符 |
re.L |
re.LOCALE ;使预定字符类\w \W \b \B \s \S 取决于当前区域设定 |
re.U |
re.UNICODE ;使预定字符类\w \W \b \B \s \S \d \D 取决于 unicode 定义的字符属性 |
re.X |
re.VERBOSE ;详细模式,该模式下正则表达式可以是多行,忽略空白字符且可以加入注释 |
In [34]: re.search('.', '\n')
In [35]: re.search('.', '\n', re.S)
Out[35]: <_sre.SRE_Match object; span=(0, 1), match='\n'>
In [36]: re.search('a.', 'A\n', re.S|re.I)
Out[36]: <_sre.SRE_Match object; span=(0, 2), match='A\n'>
2. 正则匹配符号
语法 |
说明 |
. |
小圆点符号表示匹配除换行符以外的任意字符 |
? |
匹配前面的子表达式零次或一次 |
+ |
匹配前面的子表达式一次或多次 |
* |
匹配前面的子表达式零次或多次 |
x/y |
匹配 x 或 y 其中的一个字符即可 |
[xyz] |
字符集合,匹配所包含的任意一个字符 |
[a-z] |
字符范围,匹配指定范围内的任意字符 |
[^x] |
匹配除了 x 以外的任意字符 |
[^abc] |
匹配除了 abc 这几个字母以外的任意字符 |
{m} |
重复前面的子表达式 m 次 |
{m,} |
重复前面子表达式 m 次或者更多次 |
{m,n} |
重复前面的子表达式至少 m 次至多 n 次 |
In [8]: re.search('\d{5}', '123456')
Out[8]: <_sre.SRE_Match object; span=(0, 5), match='12345'>
In [9]: re.search('ca*t', 'catzzz')
Out[9]: <_sre.SRE_Match object; span=(0, 3), match='cat'>
In [10]: re.search('catz{1,2}', 'catzzz')
Out[10]: <_sre.SRE_Match object; span=(0, 5), match='catzz'>
In [12]: re.search('..', 'cat')
Out[12]: <_sre.SRE_Match object; span=(0, 2), match='ca'>
In [14]: re.search('a|e', 'abcd')
Out[14]: <_sre.SRE_Match object; span=(0, 1), match='a'>
In [15]: re.search('[a12]', 'abcd')
Out[15]: <_sre.SRE_Match object; span=(0, 1), match='a'>
In [16]: re.search('[a-z]', 'abc')
Out[16]: <_sre.SRE_Match object; span=(0, 1), match='a'>
语法 |
说明 |
\d |
匹配任意十进制数,相当于 [0-9] |
\D |
匹配任意非数字字符,相当于 [^0-9] |
\s |
匹配任意空白字符,相当于 [<空格>\t\n\r\f\v] |
\S |
匹配任意非空白字符,相当于 [^<空格>\t\n\r\f\v] |
\w |
匹配任意字母或数字或下划线或汉字,相当于 [a-zA-Z0-9_] |
\W |
匹配任意非字母或数字或下划线或汉字,相当于 [^a-zA-Z0-9_] |
In [17]: re.search('..', 'hi')
Out[17]: <_sre.SRE_Match object; span=(0, 2), match='hi'>
In [18]: re.search('\w\w\w\w', 'a1_哈')
Out[18]: <_sre.SRE_Match object; span=(0, 4), match='a1_哈'>
In [19]: re.search('\s\s\s', ' \t\r')
Out[19]: <_sre.SRE_Match object; span=(0, 3), match=' \t\r'>
In [20]: re.search('\d\d', '12')
Out[20]: <_sre.SRE_Match object; span=(0, 2), match='12'>
语法 |
说明 |
^ |
匹配字符串的开始 |
$ |
匹配字符串的结束 |
\A |
仅匹配字符串开头 |
\Z |
仅匹配字符串结尾 |
\b |
匹配单词的开始或结束元字符 |
\B |
匹配非单词的开始或结束元字符 |
In [21]: re.search('^test', 'test123')
Out[21]: <_sre.SRE_Match object; span=(0, 4), match='test'>
In [22]: re.search('^test', '123test123')
In [23]: re.search('123$', 'test123')
Out[23]: <_sre.SRE_Match object; span=(4, 7), match='123'>
In [24]: re.search('123$', 'test123t')
3. 正则惰性匹配
语法 |
说明 |
? |
匹配前面的子表达式零次或一次 |
+ |
匹配前面的子表达式一次或多次 |
* |
匹配前面的子表达式零次或多次 |
{n,} |
重复 n 次或更多次 |
{n,m} |
重复 n 到 m 次 |
语法 |
说明 |
? |
重复任意次,但尽可能少重复 |
+? |
重复 1 次或更多次,但尽可能少重复 |
?? |
重复 0 次或 1 次,但尽可能少重复 |
{n,}? |
重复 n 次以上,但尽可能少重复 |
{n,m}? |
重复 n 到 m 次,但尽可能少重复 |
In [30]: re.search('a.*b', 'aabab')
Out[30]: <_sre.SRE_Match object; span=(0, 5), match='aabab'>
In [31]: re.search('a.*b', 'aabab').group()
Out[31]: 'aabab'
In [32]: re.search('a.*?b', 'aabab')
Out[32]: <_sre.SRE_Match object; span=(0, 3), match='aab'>
In [33]: re.search('a.*?b', 'aabab').group()
Out[33]: 'aab'
4. 正则匹配内容
语法 |
说明 |
表达式实例 |
/ |
表示左右表达式匹配任意一个,总是从左到右匹配 |
- |
(...) |
被括起来的表达式将作为分组,从表达式左边开始每遇到一个分组的左括号,编号递增1 |
- |
<number> |
引用编号为<number> 的分组匹配到的字符串 |
(\d)abc\1 表示可以匹配到1abc1 /2abc2 等 |
(?P<name>...) |
分组,除了原有的编号外再制定一个额外的别名 |
(?P<name>escape) 表示只能匹配到escape 而name 是起的别名,可以在后续使用到 |
(?P=name) |
引用别名为<name> 的分组匹配到的字符串 |
(?P<id>\d)abc(?P=id) 表示可以匹配到1abc1 /2abc2 等 |
In [46]: re.findall('\d', '1a2b3c4d')
Out[46]: ['1', '2', '3', '4']
In [47]: for i in re.finditer('\d', '1a2b3c4d'):
...: print(i)
...:
<_sre.SRE_Match object; span=(0, 1), match='1'>
<_sre.SRE_Match object; span=(2, 3), match='2'>
<_sre.SRE_Match object; span=(4, 5), match='3'>
<_sre.SRE_Match object; span=(6, 7), match='4'>
In [48]: m = re.match('(a)b', 'ab')
In [49]: m.group(1)
Out[49]: 'a'
In [50]: m = re.match('([a-c]+).*(\w)', 'abcbde')
In [51]: m.groups()
Out[51]: ('abcb', 'e')
In [52]: m.group(1), m.group(2), m.group(1, 2)
Out[52]: ('abcb', 'e', ('abcb', 'e'))
In [53]: pattern = '(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
In [54]: m = re.match(pattern, '2018-06-23')
In [55]: m.groupdict()
Out[55]: {'day': '23', 'month': '06', 'year': '2018'}
In [56]: m.group('year')
Out[56]: '2018'
In [57]: m.groups()
Out[57]: ('2018', '06', '23')
5. 正则高阶函数
正则表达式中提供了一些高阶函数用于提到匹配的效率和使用的方便
5.1 split 函数
- 格式说明
split(string[, maxsplit])
re.split(pattern, string[, maxsplit])
- 使用说明
- 按照能够匹配的子串将
string
分割后返回列表
- 如果在模式中使用捕获括号,则模式中所有组的文本也作为生成列表的一部分返回
- 参数
maxsplit
用于指定最大分割次数,不指定将全部分割
- 参数
maxsplit
不为零,则最多会出现maxsplit
拆分,并将该字符串的其余部分作为列表的最后一个元素返回
p = re.compile(r'\d+')
print(p.split('one1two2three3four'))
>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']
5.2 findall 函数
- 格式说明
findall(string[, pos[, endpos]])
re.findall(pattern, string[, flags])
- 使用说明
p = re.compile(r'\d+')
print(p.findall('one1two2three3four4'))
5.3 finditer 函数
- 格式说明
finditer(string[, pos[, endpos]])
re.finditer(pattern, string[, flags])
- 使用说明
- 搜索
string
,返回一个顺序访问每一个匹配结果(Match
对象)的迭代器
p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
print(m.group()),
3.4 sub 函数
- 格式说明
sub(repl, string[, count])
re.sub(pattern, repl, string[, count])
- 使用说明
- 使用
repl
替换string
中每一个匹配的子串后返回替换后的字符串
- 当
repl
是一个字符串时,可以使用\id
或\g<id>
、\g<name>
引用分组,但不能使用编号0
- 当
repl
是一个方法时,这个方法应当只接受一个参数(Match
对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)
- 参数
count
用于指定最多替换次数,不指定时全部替换
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print(p.sub(r'\2 \1', s))
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print(p.sub(func, s))
3.5 subn 函数
- 格式说明
subn(repl, string[, count])
re.sub(pattern, repl, string[, count])
- 使用说明
- 返回
(sub(repl, string[, count])
, 替换次数)
- 多返回一个替换次数的数值,如实例中的数值
2
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
print(p.subn(r'\2 \1', s))
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print(p.subn(func, s))
3.6 fullmatch 函数
- 格式说明
- 使用说明
- 如果一个字符串全部匹配才会返回匹配对象,否则返回
None
- 请注意,这与零长度匹配不同
- 在
Python 3.4
引入的函数
>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog")
>>> pattern.fullmatch("ogre")
>>> pattern.fullmatch("doggie", 1, 3)
<_sre.SRE_Match object; span=(1, 3), match='og'>
3.7 purge 函数
re.purge()