source:Regular Expression HOWTO
简介
正则表达式(Regular expressions, REs,regexes regex patterns)在python
中主要通过re
包实现。使用正则表达式,你可以匹配任意你想匹配的字符串, 比如email, 电话号码,英文单词,$\TeX$命令等。
正则表达式的pattern被编译成一系列的bytecode,然后通过C
语言写的引擎执行匹配。高级的使用者应当考虑不同的写法的执行速度。
简单的patterns
匹配字符
.
匹配除换行符以外的任意字符
[]
中括号里的任一字符出现一次
\d
匹配数字,相当于[0-9]
\D
匹配非数字
\s
匹配任意的空白符
\S
匹配任意的非空白符
\w
匹配字母或数字或下划线或汉字
\W
匹配非字母或数字或下划线或汉字
^
匹配字符串的开始
$
匹配字符串的结束u
重复
*
重复0次或多次
+
重复一次或更多次
?
重复0次或1词
{n}
重复n次
{n,}
重复n次或更多次
{n, m}
重复n次到m次
在python
中使用正则表达式
在python
中,re
模块为我们提供了使用正则表达式的引擎。
编译正则表达式
1 2 3
| import re p = re.compile('ab*') p
|
re.compile(r'ab*', re.UNICODE)
re.compile
函数能产生pattern对象,我们可以用pattern匹配字符实现查找或者替代等功能。re.compile
还有其它一些语法变量,比如忽略大小写等。
1 2
| p = re.compile('ab.*', re.IGNORECASE) p
|
re.compile(r'ab.*', re.IGNORECASE|re.UNICODE)
进行匹配
如果RE
是某个pattern
match()
是否是以RE
开头的
search()
扫描整个字符串,检查是否存在RE
findall()
寻找所有的子字符串, 返回一个list
finditer()
类似上, 返回一个iterator
<_sre.SRE_Match object; span=(0, 5), match='abcde'>
使用match()
匹配,返回的结果是一个match
对象,如果想调用结果的话,参考下面的几种方法:
group()
: 返回RE
匹配的字符串
start()
: 返回匹配结果的开始位置
end()
: 返回匹配结果的末尾位置
span()
: 返回字符位置的区间
'abcde'
(0, 5)
(0, 5)
1 2
| m = p.search("xabcde") m.group()
|
'abcde'
在实际编程时, 往往把match
对象存成一个变量, 然后检查是否是空, 如下
1 2 3 4 5 6
| p = re.compile('[a-z]+', re.IGNORECASE) m = p.match("Abdedfscf") if m: print('Matched found:', m.group()) else: print('Matched not found')
|
Matched found: Abdedfscf
如果想要返回所有的匹配字符串的话, 可以使用findall()
1 2
| p = re.compile('[\d.]+') p.findall('1.4 billions people in 34 provinces')
|
['1.4', '34']
当然也可以返回一个迭代对象, 以便进行迭代操作
1 2 3 4
| p = re.compile('[\d.]+') iterator = p.finditer('1.4 billions people in 34 provinces') for it in iterator: print(it.span())
|
(0, 3)
(23, 25)
Module-Level Functions
如果嫌每次都使用compile()
生成RE
太麻烦, 你也可以像下面这种方式进行匹配:
1
| print(re.findall(r'[\d.]+', '1.4 billions people in 34 provinces'))
|
['1.4', '34']
这里的r
表示regex的意思
Compilation Flags
允许你修改一些参数, 实现大小写忽略, 多行匹配等功能
I IGNORECASE
1
| re.findall(r'\ba[a-z]+', "abc, abandon, banana, Ana, AB",re.I)
|
['abc', 'abandon', 'Ana', 'AB']
A
ASCII
1
| re.findall(r'\w+', "hello! Hey! 你好",re.A)
|
['hello', 'Hey']
1
| re.findall(r'\w+', "hello! Hey! 你好")
|
['hello', 'Hey', '你好']
更多元字符
|
或 操作符 需要注意的时abc|xyz
匹配的时abc
或xyz
, 而不是c
或x
1
| re.findall(r'Bill|Jim', "Tom, Jimmy, Zhang&Bill")
|
['Jim', 'Bill']
分组(Grouping)
有时候我们进行匹配的时候会需要把匹配的结果区分为不同的组成部分,这我们就用得到分组grouping
, 我们使用’()
‘作为分组的标记
1 2 3
| p = re.compile('(a(b)c)d') m = p.match('abcd') m.group(0)
|
'abcd'
'abc'
'b'
1 2 3
| mail = "mayun@alibaba.com.cn mail of Jack Ma" p = re.compile("(^[a-z][a-z1-9._]+)@([a-z1-9][a-z1-9._]+)", re.I) m = p.match(mail)
|
'mayun@alibaba.com.cn'
'mayun'
'alibaba.com.cn'
('mayun', 'alibaba.com.cn')
分组命名
分组命名是Python独有的正则的功能, 通过(?P<name>...)
可以为分组命名
1 2 3
| mail = "mayun@alibaba.com.cn mail of Jack Ma" p = re.compile("(?P<User>^[a-z][a-z1-9._]+)@(?P<Company>[a-z1-9][a-z1-9._]+)", re.I) m = p.match(mail)
|
'mayun'
'alibaba.com.cn'
字符修改
split()
在正则匹配的位置分离
sub()
查找替代
subn()
1
| re.split(r"\W+", 'This is a test, short and sweet, of split().')
|
['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
1
| re.split(r"\W+", 'This is a test, short and sweet, of split().',3)
|
['This', 'is', 'a', 'test, short and sweet, of split().']
1
| re.split(r"(\W+)", 'This is a test, short and sweet, of split().')
|
['This',
' ',
'is',
' ',
'a',
' ',
'test',
', ',
'short',
' ',
'and',
' ',
'sweet',
', ',
'of',
' ',
'split',
'().',
'']
查找并替代
1 2
| p = re.compile('(blue|white|red)') p.sub('colour', 'blue socks and red shoes')
|
'colour socks and colour shoes'
1
| p.sub('colour', 'blue socks and red shoes', count=1)
|
'colour socks and red shoes'
1
| p.subn('colour', 'blue socks and red shoes')
|
('colour socks and colour shoes', 2)
常见问题
使用正则还是字符串方法
1 2
| string1 = "swordfish" string1.replace("word", 'deed')
|
'sdeedfish'
1 2
| p = re.compile('word') p.sub(string1, 'deed')
|
'deed'
match()
和search
前者只匹配从0位置开始的结果, search()
会匹配不从0开始的结果
1
| print(re.match(r'super', 'superstition').span())
|
(0, 5)
1
| print(re.match('super', 'insuperable'))
|
None
1
| print(re.search('super', 'insuperable').span())
|
(2, 7)
贪婪和非贪婪
前者是指匹配尽可能多的符合条件的字符, 后者则会匹配尽可能少的或指定的符合条件的字符
1 2
| s = '<html><head><title>Title</title>' len(s)
|
32
1
| print(re.match('<.*>', s).span())
|
(0, 32)
1
| print(re.match('<.*>', s).group())
|
<html><head><title>Title</title>
如果想要非贪婪可以使用?
1
| print(re.match('<.*?>', s).group())
|
<html>
使用re.VERBOSE
有时候我们要匹配比较复杂的文本时,正则表达式要写很长,如果携程一行的话,可读性就比较差,可以使用re.VERBOSE
增加pattern的易读性
1 2 3 4 5 6 7 8
| pat = re.compile(r""" \s* # Skip leading whitespace (?P<header>[^:]+) # Header name \s* : # Whitespace, and a colon (?P<value>.*?) # The header's value -- *? used to # lose the following trailing whitespace \s*$ # Trailing whitespace to end-of-line """)
|
1
| pat = re.compile(r"\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s*$")
|