标准库:一些最爱
re
re模块包含对正则表达式的支持,因为曾经系统学习过正则表达式,所以基础内容略过,直接看python对于正则表达式的支持。
正则表达式的学习,见《Mastering Regular Expressions》(精通正则表达式)
re模块的内容
最重要的一些函数
函数 |
描述 |
compile(pattern[,flags]) |
根据包含正则表达式的字符串创建模式对象 |
search(pattern,string[,flags]) |
在字符串中寻找模式 |
match(pattern,string[,flags]) |
在字符串的开始处匹配模式 |
split(pattern,string,maxsplit=0]) |
根据模式的匹配项来分隔字符串 |
findall(pattern,string) |
列出字符串中模式的所有匹配项 |
sub(pat,repl,string[,count=0]) |
将字符串中所有pat的匹配项用repl替换 |
escape(string) |
将字符串中所有特殊正则表达式字符转义 |
函数re.compile将正则表达式(以字符串书写的)转换为模式对象,可以实现更有效率的匹配。如果在调用search或者match函数的时候使用字符串表示的正则表达式,它们会在内部将字符串转换为正则表达式对象。使用compile完成一次转换之后,在每次使用模式的时候就不用进行转换。模式对象本身也有查找/匹配的函数,就像方法一样,所以re.search(pat,string)(pat是用字符串表示的正则表达式)等价于pat.searching(string)(pat是用compile创建的模式对象)。经过compile转换的正则表达式对象也能用于普通的re函数。
函数re.search会在给定字符串中寻找第一个匹配给定正则表达式的子字符串。一旦找到子字符串,函数就会返回MatchObject(值为True),否则返回None(值为False)。
函数re.match会在给定字符串的开头匹配正则表达式。因此,match(‘p’,’python’)返回真,而re.match(‘p’,’www.python.org’)则返回假(None)。
注意:如果模式与字符串的开始部分相匹配,那么match函数会给出匹配的结果,而模式并不需要匹配整个字符串。如果要求模式匹配整个字符串,那么可以在模式的结尾加上美元符号。美元符号会对字符串的末尾进行匹配,从而顺延了整个匹配。
函数re.split会根据模式的匹配项来分割字符串。类似于字符串的split,不过是用完整的正则表达式代替了固定的分隔符字符串。
>>> import re
>>> some_text="alpha, beta .... gamma delta"
>>> re.split(‘[. ]+‘,some_text)
[‘alpha,‘, ‘beta‘, ‘gamma‘, ‘delta‘]
>>> re.split(‘ta‘,some_text)
[‘alpha, be‘, ‘ .... gamma del‘, ‘‘]
maxsplit参数表示字符串最多可以分割成的部分数:
>>> re.split(‘[. ]+‘,some_text,maxsplit=1)
[‘alpha,‘, ‘beta .... gamma delta‘]
>>> re.split(‘[. ]+‘,some_text,maxsplit=2)
[‘alpha,‘, ‘beta‘, ‘gamma delta‘]
>>> re.split(‘[. ]+‘,some_text,maxsplit=0)
[‘alpha,‘, ‘beta‘, ‘gamma‘, ‘delta‘]
>>> re.split(‘[. ]+‘,some_text,maxsplit=-2)
[‘alpha, beta .... gamma delta‘]
函数re.findall以列表形式返回给定模式的所有匹配项:
>>> re.findall(‘[. ]+‘,some_text)
[‘ ‘, ‘ .... ‘, ‘ ‘]
函数re.sub的作用在于:使用给定的替换内容将匹配模式的子字符串(最左端并且非重叠的子字符串)替换掉。
>>> re.sub(‘{name}‘,some_text,‘Dear {name}‘)
‘Dear alpha, beta .... gamma delta‘
re.escape是一个很实用的函数,它可以对字符串中所有可能被解释为正则运算符的字符进行转义的应用函数。
>>> re.escape(‘`~-_=+[{]}\|;:"/?.>,<‘)
‘\\`\\~\\-\\_\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\"\\/\\?\\.\\>\\,\\<‘
>>> re.escape(‘www.baidu.com‘)
‘www\\.baidu\\.com‘
匹配对象和组
对于re模块中那些能够对字符串进行模式匹配的函数而言,当能找到匹配项的时候,它们都会返回MatchObject对象。这些对象包括匹配模式的子字符串的信息。它们还包含了哪个模式匹配了子字符串哪部分的信息——组(group)。
组就是放置在圆括号内的子模式。组的序号取决于它左边的括号数。组0就是整个模式。
re匹配对象的一些重要方法
方法 |
描述 |
group([group1,...]) |
获取给定子模式(组)的匹配项 |
start([group]) |
返回给定组的匹配项的开始位置 |
end([group]) |
返回给定组的匹配项的结束位置(和分片一样,不包括组的结束位置) |
span([group]) |
返回一个组的开始和结束位置 |
>>> m=re.match(‘.{4}://(.{4})\.(.{4})\..{3}/.{8}‘,‘http://blog.csdn.net/signjing‘)
>>> m.group(1)
‘blog‘
>>> m.group(2)
‘csdn‘
>>> m.start(1)
7
>>> m.start(2)
12
>>> m.span(1)
(7, 11)
>>> m.span(2)
(12, 16)
作为替换的组号和函数
见证re.sub强大功能的最简单方式就是在替换字符串中使用组号。在替换内容中以’\\n’形式出现的任何转义序列都会被模式中与组n匹配的字符串替换掉。
将”http://blog.csdn.net/signjing”中的’/’(不包括http头中的’/’)变为’\\’:
>>> pat=r‘([^:/])/([^:/]*)‘
>>> re.sub(pat,r‘\1\\\2‘,‘http://blog.csdn.net/signjing‘)
‘http://blog.csdn.net\\signjing‘
注意:正则表达式很容易变得难以理解,使用有意义的变量名或加上一两句注释是很重要的。
让正则表达式变得更加易读的方式是在re函数中使用VERBOSE标志。它允许在模式中添加空白(空白字符、tab、换行符,等等),re则会忽略它们——除非将其放在字符类或者用反斜线转义。也可以在冗长的正则式中添加注释。
>>> pat=re.compile(r‘‘‘
( #开始第一个组
[^:/] #匹配一个不包括:和/的字符,主要目的是排除http头中的/
) #结束第一个组
/ #匹配/
( #开始第二个组
[^:/]* #匹配任意多个不包括:和/的字符串
) #结束第二个组
‘‘‘,re.VERBOSE)
>>> re.sub(pat,r‘\1\\\2‘,‘http://blog.csdn.net/signjing‘)
‘http://blog.csdn.net\\signjing‘
模板系统
模板是一种通过放入具体值从而得到某种已完成文本的文件。python有一种高级的模板机制——字符串格式化。但正则表达式可以让系统更加高级。
精通任何程序设计语言的最佳方法是实践——测试它的限制,探索它的能力。
练习 匹配字符串
脚本内容
$ cat re-example-1.py
#File : re-example-1.py
import re
text="The Attila the Hun Show"
print text
m=re.match(".",text)
if m: print repr("."),"=>",repr(m.group(0))
m=re.match(".*",text)
if m: print repr(".*"),"=>",repr(m.group(0))
m=re.match("\w+",text)
if m: print repr("\w+"),"=>",repr(m.group(0))
m=re.match("\d+",text)
if m: print repr("\d+"),"=>",repr(m.group(0))
执行结果
$ python re-example-1.py
The Attila the Hun Show
‘.‘ => ‘T‘
‘.*‘ => ‘The Attila the Hun Show‘
‘\\w+‘ => ‘The‘
练习 提取匹配的子字符串
脚本内容
$ cat re-example-2.py
#File: re-example-2.py
import re
text="2014/06/24"
m=re.match(‘(\d{4})/(\d{2})/(\d{2})‘,text)
if m:
print m.group(1,2,3)
执行结果
$ python re-example-2.py
(‘2014‘, ‘06‘, ‘24‘)
练习 查找子字符串
脚本内容
$ cat re-example-3.py
#File: re-example-3.py
import re
text="There is one Date: 2014/6/24 in here!"
m=re.search(‘(\d{4})/(\d{1,2})/(\d{1,2})‘,text)
print m.group(1),m.group(2),m.group(3)
month,day,year=m.group(2,3,1)
print month,day,year
date=m.group(0)
print date
执行结果
$ python re-example-3.py
2014 6 24
6 24 2014
2014/6/24
练习 替换子字符串
脚本内容
$ cat re-example-4.py
# File : re-example-4.py
import re
text="You‘re no fun anymore ..."
print re.sub(‘fun‘,‘interesting‘,text)
print re.sub("[^\w]+","-",text)
print re.sub("\S+","-BEEP-",text)
执行结果
$ python re-example-4.py
You‘re no interesting anymore ...
You-re-no-fun-anymore-
-BEEP- -BEEP- -BEEP- -BEEP- -BEEP-
练习 通过回调函数替换子字符串
脚本内容
$ cat re-example-5.py
#File : re-example-5.py
import re
import string
text="a line of text\\012another line of text\\012etc..."
def octal(match):
return chr(string.atoi(match.group(1),8))
octal_pattern=re.compile(r"\\(\d\d\d)")
print text
print octal_pattern.sub(octal,text)
执行结果
$ python re-example-5.py
a line of text\012another line of text\012etc...
a line of text
another line of text
etc...
练习 匹配多个模式中的一个
脚本内容
$ cat re-example-6.py
#File : re-example-6.py
import re,string
def combined_pattern(patterns):
p=re.compile(
string.join(map(lambda x: "("+x+")",patterns),"|")
)
def fixup(v,m=p.match,r=range(0,len(patterns))):
try:
regs=m(v).regs
except AttributeError:
return None
else:
for i in r:
if regs[i+1] != (-1,-1):
return i
return fixup
patterns=[
r"\d+",
r"abc\d{2,4}",
r"p\w+"
]
p = combined_pattern(patterns)
print p("129391")
print p("abc800")
print p("abc1600")
print p("python")
print p("perl")
print p("tcl")
执行结果
$ python re-example-6.py
0
1
1
2
2
None