1.1 通配符
正则表达式能够匹配对于一个的字符串,可以使用特殊字符创建这类模式。(图片来自cnblogs)
1.2 特殊字符的转义
由于在正则表达式中,有时需要将特殊字符作为普通字符处理,就需要用‘\’进行转义,例如‘python\\.org’就会匹配‘python.org’,那么为什么要用两个反斜杠呢,原因在于需要进行两层转义,首先是re模块表示正则表达式中需要转义一次,其次是python解释器即python的语法还要求再转义一次。也是因为这个原因,对于‘\’需要‘\\\\’来匹配。为了表示的简介性,可以使用原始字符串来处理,则上面两例分别可以写为r‘python\.org’和r‘\\’。
1.3 字符集
举例说明,例如‘[pj]python’可以匹配‘python’和‘jpython’,[a-zA-Z0-9]可以匹配任意一个大小写字母和数字(注意:是一个)。为了反转字符集,可以将‘^’放在字符串的开头,例如‘[^abc]’可以匹配除a,b,c以为的任意字符。
注意:如果希望‘.’,‘*’,‘?’这些特殊字符用作文本字符,则需‘\’进行转义,但是在字符集中无必要,尽管是合法的(因为可以调整顺序来解决)。记住以下两个规则:
a. 如果‘^’出现在字符集的开头则需要转义,除非希望用作字符集反转。
b. 右中括号‘]’和横线‘-’要么放在字符集开头,要么转义。
1.4 选择符和子模块
如果只想匹配‘python’和‘perl’,则可以用选择运算符管道符号‘|’,模式可写为‘python|perl’
如果不需要对整个模式使用选择运算符,而只需要一部分,可以用括号括起需要的部分,对于上例,表示为‘p(ython|erl)’。括号括起部分称为子模块(subpattren)。
1.5 可选项和重复子模块
在子模块后面加上问号,就变成了可选项。
(pattern)?:允许模式出现0次或者1次。
(pattern)+:允许模式出现1次或者多次。
(pattern)*:允许模式出现0次或者多次。
(pattern){m,n}:允许模式出现m~n次。
1.6 字符串的开始和结尾
举例说明,‘www.python.org’和‘python.www.org’中的子字符串‘www’能匹配模式‘w+’,但是只希望‘www.python.org’能匹配,则模式可用‘^w+’表示,如果希望‘python.org.www’中的子字符串‘www’能匹配‘w+’,则模式需写为‘$w+’。
2. re模块的函数
2.1 .compile
将正则表达式转换为模式对象,实现更有效率的匹配。
import re pattern = re.compile('(^w+)\.python\.org')
2.2 .search(重要)
在给定字符串中寻找第一个匹配给定正则表达式的子字符串,如果找到会返回一个MatchObject对象,这个对象中的元素可以.group()得到(之后将会介绍group的概念),如果没找到就会返回None。
可以先判断是否找到再取元素,假设例子中的pattern有两个组,返回第一个组。
have_character = re.search(pattern,text) if not have_character: return have_character.group(1)
2.3 .match
在给定字符串的开始处匹配正则表达式,例如re.match(‘p’,‘python’)返回为对象MatchObject,即匹配成功,如果要匹配整个字符串,则可以在模式最后加上‘$’符号(代表结尾也匹配)。
2.4 .split
根据模式匹配项来分割字符串。类似于字符串的split方法,但是可用正则表达式来带起固定的分隔符字符串,例如允许用任意长度的逗号和空格序列来分割字符串。
text = 'a, b,,,,c d' re.split('[, ]+', text) #['a', 'b', 'c', 'd']
参数maxsplit可以设定最多的分割次数。
text = 'a, b,,,,c d' re.split('[, ]+', text, maxsplit=2) #['a', 'b', 'c d']
2.5 .findall(重要)
该方法以列表的形式返回所有的匹配项。
pattern = 'a(b+?)c(d+?)e' items = re.findall(pattern, 'abbcddeabbbcddde') print items #items = [('bb', ‘dd’), ('bbb', 'ddd')]
2.6 .sub(pattern, repl, string[, count=0]) (重要)
将字符串中所有pattern的匹配项用repl代替。
pattern = re.compile(r'\*([^\*]+)\*') re.sub(pattern, r'<em>\1</em>', 'Hello, *world*!') #'Hello, <em>world</em>!'
在sub函数三个参数中,pattern代表模式,repl代表目标形式,string代表待匹配替换字符串。
替换步骤:
a. 用模式pattern套待匹配替换字符串string。
b. 按照目标形式repl对字符串进行重建(即用目标形式去代替string中与pattern匹配的子字符串)
sub函数强大功能最重要的体现在于可以在替代字符串中使用组号。(具体内容参考链接:http://stackoverflow.com/questions/5984633/python-re-sub-group-number-after-number, http://www.crifan.com/python_re_sub_detailed_introduction/)
re.sub(r'(foo)', r'\g<1>123', 'foobar') #'foo123bar'
2.7 .escape
如果一个字符串很长且包含很多特殊字符,而不想输入一大堆反斜杠来转义,可以用这个函数对字符串中所有可能被解释为正则运算符的字符进行转义为普通文本字符。
3. 匹配对象和组
re模块的search,match函数在找到匹配项时都会返回一个MatchObject对象,对于这样一个对象m,可以用m.group()来取某组的信息,如果.group()默认组号为0,则返回整个字符串,.group(1)返回与第一个子模式匹配的单个字符串,.group(2)等等以此类推。
.start()方法得到对应组的开始索引,.end()得到对应组的结束索引,.span()以元组形式给出对应组的开始和结束位置,括号中填入组号,不填入组号时默认为0。
4. 贪婪和非贪婪模式
重复运算符在默认条件下是贪婪的。
pattern = r'\*(.+)\*' re.sub(pattern, r'<em>\1</em>', '*This* is *it*!') #'<em>This* is *it</em>'
可见贪婪模式匹配了开始星号到结束星号间的全部内容,包括中间两个星号。
用(.+?)代替(.+)得到非贪婪模式,它会匹配尽可能少的内容。
pattern = r'\*(.+?)\*' re.sub(pattern, r'<em>\1</em>', '*This* is *it*!') #'<em>This</em> is <em>it</em>'
re.match()
函数原型:
match(pattern, string, flags=0)
Try to apply the pattern at the start of the string,
returning a match object, or None if no match was found.
函数作用:
re.match函数尝试从字符串的开头开始匹配一个模式,如果匹配成功,返回一个匹配成功的对象,否则返回None。
参数说明:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
我们可以使用group()或groups()匹配对象函数来获取匹配后的结果。
group()
group(...)
group([group1, ...]) -> str or tuple.
Return subgroup(s) of the match by indices or names.
For 0 returns the entire match.
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表匹配的整个子串;默认返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
groups()
groups(...)
groups([default=None]) -> tuple.
Return a tuple containing all the subgroups of the match, from 1.
The default argument is used for groups
that did not participate in the match
以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。没有截获字符串的组以默认值None代替。
实例
1
2
3
4
5
6
7
8
9
10
|
impor
re
line
=
"This is the last one"
res
=
re.match( r
'(.*) is (.*?) .*'
, line, re.M|re.I)
if
res:
print
"res.group() : "
, res.group()
print
"res.group(1) : "
, res.group(
1
)
print
"res.group(2) : "
, res.group(
2
)
print
"res.groups() : "
, res.groups()
else
:
print
"No match!!"
|
re.M|re.I:这两参数表示多行匹配|不区分大小写,同时生效。
细节实例:
1
2
|
>>> re.match(r
'.*'
,
'.*g3jl\nok'
).group()
'.*g3jl'
|
.(点)表示除换行符以外的任意一个字符,*(星号)表示匹配前面一个字符0次1次或多次,这两联合起来使用表示匹配除换行符意外的任意多个字符,所以出现以上的结果。
1
2
3
4
5
6
7
8
9
10
11
|
1
、
re.match(r
'.*..'
,
'..'
).group()
'..'
2
、
>>> re.match(r
'.*g.'
,
'.*g3jlok'
).group()
'.*g3'
3
、
>>> re.match(r
'.*...'
,
'..'
).group()
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
AttributeError:
'NoneType'
object
has no attribute
'group'
|
上面两例子为什么有结果呢?这是因为第一个例子.*..中的.*匹配了0次,后面的..匹配字符串中..,而第二个例子中的 .* 匹配了一次,匹配字符串中的 .*,g匹配了后面的g字符,最后一个.号匹配了。
为什么第三个例子没有匹配到结果呢?这是因为就算正则表达式中的 .* 匹配0次,后面的三个点也不能完全匹配原字符串中的两个点,所以匹配失败了。
从上面几个例子可以看出,只有当正则表达式中要匹配的字符数小于等于原字符串中的字符数,才能匹配出结果。并且 “.*” 在匹配的过程中会回溯,先匹配0次,如果整个表达式能匹配成功,再匹配一次,如果还是能匹配,那就匹配两次,这样一次下去,直到不能匹配成功时,返回最近一次匹配成功的结果,这就是”.*”的贪婪性。
匹配Python中的标识符:
1
2
3
4
5
6
7
8
9
10
|
>>> re.match(r
'^[a-zA-Z|_][\w_]*'
,
'_1name1'
).group()
'_1name1'
>>> re.match(r
'^[a-zA-Z|_][\w_]*'
,
'_name1'
).group()
'_name1'
>>> re.match(r
'^[a-zA-Z|_][\w_]*'
,
'num'
).group()
'num'
>>> re.match(r
'^[a-zA-Z|_][\w_]*'
,
'1num'
).group()
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
AttributeError:
'NoneType'
object
has no attribute
'group'
|
re.search()
函数原型:
search(pattern, string, flags=0)
Scan through string looking for a match to the pattern,
returning a match object, or None if no match was found.
函数作用:
扫描整个字符串并返回第一次成功的匹配对象,如果匹配失败,则返回None。
参数说明:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
跟re.match函数一样,使用group()和groups()方法来获取匹配后的结果。
1
2
|
>>> re.search(r
'[abc]\*\d{2}'
,
'12a*23Gb*12ad'
).group()
'a*23'
|
从匹配结果看出,re.search返回了第一次匹配成功的结果'a*23',如果尽可能多的匹配的话,还可以匹配后面的'b*12'。
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配,否则也返回None。
1
2
3
4
|
>>> re.match(r
'(.*)(are)'
,
"Cats are smarter than dogs"
).group(
2
)
'are'
>>> re.search(r
'(are)+'
,
"Cats are smarter than dogs"
).group()
'are'
|
上面两个例子是等价的。
re.sub()
Python的re模块中提供了re.sub()函数用于替换字符串中的匹配项,如果没有匹配的项则字符串将没有匹配的返回。
函数原型:
sub(pattern, repl, string, count=0, flags=0)
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
参数说明:
pattern:匹配的正则表达式
repl:用于替换的字符串
string:要被替换的字符串
count:替换的次数,如果为0表示替换所有匹配到的字串,如果是1表示替换1次等,该参数必须是非负整数,默认为0。
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
实例
将手机号的后4位替换成0
1
2
|
>>> re.sub(
'\d{4}$'
,
'0000'
,
'13549876489'
)
'13549870000'
|
将代码后面的注释信息去掉
1
2
|
>>> re.sub(
'#.*$'
,'
', '
num
=
0
#a number')
'num = 0 '
|
re.split()
函数原型:
split(pattern, string, maxsplit=0, flags=0)
Split the source string by the occurrences of the pattern,
returning a list containing the resulting substrings.
函数作用:
分割字符串,将字符串用给定的正则表达式匹配的字符串进行分割,分割后返回结果list。
参数说明:
pattern:匹配的正则表达式
string:被分割的字符串
maxsplit:最大的分割次数
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
re.findall()
函数原型:
findall(pattern, string, flags=0)
Return a list of all non-overlapping matches in the string.
If one or more groups are present in the pattern, return a
list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result.
函数的作用:
获取字符串中所有匹配的字符串,并以列表的形式返回。列表中的元素有如下几种情况:
当正则表达式中含有多个圆括号()时,列表的元素为多个字符串组成的元组,而且元组中字符串个数与括号对数相同,并且字符串排放顺序跟括号出现的顺序一致(一般看左括号'(‘就行),字符串内容与每个括号内的正则表达式想对应。
当正则表达式中只带有一个圆括号时,列表中的元素为字符串,并且该字符串的内容与括号中的正则表达式相对应。(注意:列表中的字符串只是圆括号中的内容,不是整个正则表达式所匹配的内容。)
当正则表达式中没有圆括号时,列表中的字符串表示整个正则表达式匹配的内容。
参数说明:
pattern:匹配的正则表达式
string:被分割的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
实例:
1、匹配字符串中所有含有'oo'字符的单词
1
2
3
|
#正则表达式中没有括号
>>> re.findall(r
'\w*oo\w*'
,
'woo this foo is too'
)
[
'woo'
,
'foo'
,
'too'
]
|
从结果可以看出,当正则表达式中没有圆括号时,列表中的字符串表示整个正则表达式匹配的内容
2、获取字符串中所有的数字字符串
1
2
3
|
#正则表达式中只有1个括号
>>> re.findall(r
'.*?(\d+).*?'
,
'adsd12343.jl34d5645fd789'
)
[
'12343'
,
'34'
,
'5645'
,
'789'
]
|
从上面结果可以看出,当正则表达式中只带有一个圆括号时,列表中的元素为字符串,并且该字符串的内容与括号中的正则表达式相对应。
3、提取字符串中所有的有效的域名地址
1
2
3
4
|
#正则表达式中有多个括号时
>>> re.findall(r
'((w{3}\.)(\w+\.)+(com|edu|cn|net))'
,add)
[(
'www.net.com.edu'
,
'www.'
,
'com.'
,
'edu'
), (
'www.baidu.com'
,
'www.'
,
'baidu.'
,
'com'
)]
|
从执行结果可以看出,正则表达式中有多个圆括号时,返回匹配成功的列表中的每一个元素都是由一次匹配成功后,正则表达式中所有括号中匹配的内容组成的元组。
re.finditer()
函数原型:
finditer(pattern, string, flags=0)
Return an iterator over all non-overlapping matches in the string. For each match, the iterator
returns a match object.
Empty matches are included in the result.
函数作用:
跟re.findall()函数一样,匹配字符串中所有满足的字串,只是返回的是一个迭代器,而不是一个像findall函数那样存有所有结果的list,这个迭代器里面存的是每一个结果的一个匹配对象,这样可以节省空间,一般用在需要匹配大量的结果时,类似于range和xrange的区别。
参数说明:
pattern:匹配的正则表达式
string:被分割的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
如:匹配字符串中所有的数字字串
1
2
3
4
|
>>>
for
i
in
re.finditer(r
'\d+'
,
'one12two34three56four'
) :
...
print
i.group(),
...
12
34
56
|
start()
返回匹配的起始位置。如:
1
|
>>> re.search(r
'\d+'
,
'asdf13df234'
).start()
|
注意,索引位置是从0开始计数的。
end()
返回匹配结束的下一个位置。如:
1
|
>>> re.search(r
'\d+'
,
'asdf13df234'
).end()
|
span()
返回匹配的区间,左闭右开。如:
1
2
|
>>> re.search(r
'\d+'
,
'asdf13df234'
).span()
(
4
,
6
)
|
re.compile()
函数原型:
compile(pattern, flags=0)
Compile a regular expression pattern, returning a pattern object.
函数作用:
编译一个正则表达式语句,并返回编译后的正则表达式对象。
这样我们就可以将那些经常使用的正则表达式编译成正则表达式对象,可以提高一定的效率。如:
一句话包含五个英文单词,长度不一定,用空格分割,请把五个单词匹配出来
1
2
3
4
5
|
>>> s
=
"this is a python test"
>>> p
=
re.
compile
(
'\w+'
)
#编译正则表达式,获得其对象
>>> res
=
p.findall(s)
#用正则表达式对象去匹配内容
>>>
print
res
[
'this'
,
'is'
,
'a'
,
'python'
,
'test'
]
|