lesson 038 —— re 模块
关于 re 模块的简单介绍。就其本质而言,正则表达式(Regular Expression 或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
普通字符
大多数字符和字母都会和自身匹配。
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
['alvin']
元字符
元字符:. ^ $ * + ? { } [ ] | ( ) \
。
1. 元字符之 .
.
是通配符,除了换行符(\n
)之外,其它字符全部可以匹配到。注意:一个 .
只能代替一个字符串,不能代表多个。
>>> import re
>>> ret = re.findall('a..in', 'alinjjssalvinsssainmmmallinsxlimaa\-inxxna\r\inllxal\ninnn')
>>> print(ret)
['alvin', 'allin', 'a\\-in', 'a\r\\in']
2. 元字符之 ^
^
是通配符,表示开头,即以之后的字符开头才匹配。
>>> ret = re.findall('^a..in', 'addinxxalinjjssalvinsssainmmmallinsxlimaa\-inxxna\r\inllxal\ninnn')
>>> print(ret)
['addin']
3. 元字符之 `#####
$
是通配符,表示结尾,即以之前的字符结尾才匹配。
>>> ret = re.findall('a..in$', 'addinxxalinjjssalvinsssainmmmallinsxlimaa\-inxxna\r\inllxal\ninnaedin')
>>> print(ret)
['aedin']
4. 元字符之 *
*
表示重复的字符,即匹配紧挨着它的前面的字符 0 次 或无穷次 [0, +∞]。并且,它是贪婪匹配(即尽可能多的匹配字符)。
>>> ret = re.findall('abc*e', 'abccccccddef')
>>> print(ret)
[]
>>> ret = re.findall('abc*d', 'abccccccddef')
>>> print(ret)
['abccccccd']
>>> ret = re.findall('abc*d', 'abddef')
>>> print(ret)
['abd']
>>> ret = re.findall('abc*', 'abccccccddef') # 贪婪匹配
>>> print(ret)
['abcccccc']
5. 元字符之 +
+
同样表示重复的字符,它也是贪婪匹配,但是,它匹配的是它前面的字符 1 次或无穷次 [1, +∞]。
>>> ret = re.findall('abc+d', 'abccccccddef')
>>> print(ret)
['abccccccd']
>>> ret = re.findall('abc+d', 'abddef')
>>> print(ret)
[]
>>> ret = re.findall('abc+', 'abccccccddef') # 贪婪匹配
>>> print(ret)
['abcccccc']
6. 元字符之 ?
?
表示匹配它紧挨的前面的字符 0 次或 1 次 [0, 1]。它也是贪婪匹配。
>>> ret = re.findall('abc?d', 'abccccccddef')
>>> print(ret)
[]
>>> ret = re.findall('abc?d', 'abcddef')
>>> print(ret)
['abcd']
>>> ret = re.findall('abc?d', 'abddef')
>>> print(ret)
['abd']
>>> ret = re.findall('abc?d', 'acddef') # 只作用于和它紧挨的那个字符
>>> print(ret)
[]
>>> ret = re.findall('abc?', 'abcccddef') # 表示贪婪匹配
>>> print(ret)
['abc']
7. 元字符之 {}
{}
表示自己定义字符重复的次数。例:{4}
表示重复 4 次;{1,6}
表示重复 1 次到 6 次;{0,}
表示重复 0 次 到无穷次,相当于 *
;{1,}
表示重复 1 次到无穷次,相当于 +
;{0,1}
表示重复 0 次或 1 次,相当于 ?
。它的次数也是贪婪匹配。
>>> ret = re.findall('abc{4}', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['abcccc', 'abcccc', 'abcccc']
>>> ret = re.findall('abc{1,6}', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['abc', 'abcc', 'abccc', 'abcccc', 'abcccccc', 'abcccccc']
>>> ret = re.findall('abc{0,}', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['ab', 'abc', 'abcc', 'abccc', 'abcccc', 'abcccccc', 'abcccccccc']
>>> ret = re.findall('abc{1,}', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['abc', 'abcc', 'abccc', 'abcccc', 'abcccccc', 'abcccccccc']
>>> ret = re.findall('abc{0,1}', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['ab', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc']
8. 前面的 *, +, ?, {}
等都是贪婪匹配
也就是尽可能的匹配,后面加 ?
可以使其变成惰性匹配。
>>> ret = re.findall('abc*?', 'abccccccddef')
>>> print(ret)
['ab']
>>> ret = re.findall('abc+?', 'abccccccddef')
>>> print(ret)
['abc']
>>> ret = re.findall('abc??', 'abccccccddef')
>>> print(ret)
['ab']
>>> ret = re.findall('abc{1,6}?', 'abdxxabcdxxabccdxxabcccdxxabccccdxxabccccccdxxabccccccccdxxx')
>>> print(ret)
['abc', 'abc', 'abc', 'abc', 'abc', 'abc']
9. 元字符之字符集 []
[]
表示匹配其中的任意一个字符,即或的关系。并且只能匹配到其中的一个字符。在字符集中有功能的符号有 -, ^, \
。-
表示一个范围,如 [0-9], [a-z]
;^
表示 取非,如 [^xy], [^a-z]
;\
表示转义。
>>> ret = re.findall('x[y,z]m', 'xymxxxzmxxx,mxxxmmmxx')
>>> print(ret)
['xym', 'xzm', 'x,m']
>>> ret = re.findall('x[y*z]m', 'xymxxxzmxxx*mxxxyymxx') # * 只是一个字符
>>> print(ret)
['xym', 'xzm', 'x*m']
# -: 表示范围
>>> ret = re.findall('q[a-z]', 'q7xxqyzxx') # 只能匹配其中一个字符
>>> print(ret)
['qy']
>>> ret = re.findall('q[a-z]*', 'qmannux') # 与 * 搭配使用
>>> print(ret)
['qmannux']
>>> ret = re.findall('q[a-z]*', 'qnfnakff4jfq4xxqmsd') # 与 * 搭配使用可以匹配到字符集中的 0 次
>>> print(ret)
['qnfnakff', 'q', 'qmsd']
# ^: 表示取非
>>> ret = re.findall('q[^xy]m', 'qxmssq^mssqymssqdmssq9mss')
>>> print(ret)
['q^m', 'qdm', 'q9m']
>>> ret = re.findall('q[^a-z]*', 'qsjfkdj666q876xx') # 搭配 *, ^ 使用
>>> print(ret)
['q', 'q876']
# \: 表示转义
>>> ret = re.findall('[\d]', '45abchx3') # \d: 表示取数字
>>> print(ret)
['4', '5', '3']
>>> ret = re.findall('\([^()]*\)', '12+(34*56-54+2*(2-1))') # 转义圆括号()
>>> print(ret)
['(2-1)']
10. 元字符之转义符 \
反斜杠( \
)后跟元字符去除特殊功能,如 \., \^, \\, \*, \(, \+, \?
等;
反斜杠( \
)后跟普通字符实现特殊的功能,如 \d
等。
-
\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]
-
\b
匹配一个特殊字符边界,比如空格,&
,#
等
>>> ret = re.findall('I\b','I am LIST')
>>> print(ret)
[]
>>> ret = re.findall('I\\b', 'hello I am LIST')
>>> print(ret)
['I']
>>> ret = re.findall(r'I\b','I am LIST')
>>> print(ret)
['I']
# 匹配字符 \b
>>> ret = re.findall('I\b','I am LISTI\bhello')
>>> print(ret)
['I\x08']
>>> ret = re.findall('I\\b','I am LISTI\bhello')
>>> print(ret)
['I', 'I']
>>> ret = re.findall('I\b',r'I am LISTI\bhello')
>>> print(ret)
[]
>>> ret = re.findall('I\\b',r'I am LISTI\bhello')
>>> print(ret)
['I', 'I']
>>> ret = re.findall('I\\\\b',r'I am LISTI\bhello')
>>> print(ret)
['I\\b']
\b
在 ASCII 码中有一定有含义,表示退格符,所以,python 中字符串中若含有类似的字符,python 解释器就会把这个字符解释成 ASCII 码中的值,不会是我们输入的字符 \
和 b
。而在字符串前面加上 r
,则表示这个字符串我们看到的是什么样子,它就是这个样子,不会把还有特殊含义的字符进行解释,即 python 解释器会将 \b
转化为 \\b
这样存储。所以,对于上面,我们输入 \b
,其实传入正则表达式函数的参数是 ASCII 码中的退格符,当我们输入 \\b
,python 解释器传给正则表达式的才是正确的 \b
,即字符 \
与 b
。而在 re 模块中,\b
具有特别的含义,不会转化为对应的 ASCII 码,\f, \\
等则会转化为对应的 ASCII 码。若传给 re 模块的是 \\b
,则经过 re 处理,最后匹配的是字符 \
和 b
。
![](https://img.haomeiwen.com/i7019158/78e148ad43ec1144.jpg)
11. 元字符之分组 ()
()
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \(
和 \)
。
>>> ret = re.findall(r'(ab)+', 'abbb')
>>> print(ret)
['ab']
>>> ret = re.findall('(ab)+', 'ababababbb')
>>> print(ret)
['ab']
# 这里之所以出现的只有一个 `ab`,是因为 re 模块优先显示的是组内的匹配字符串,取消使用 ?:
# 实际它已经是贪婪匹配(如果不是,结果应该是四个 ab)
>>> ret = re.findall('(?:ab)+', 'ababababbb')
>>> print(ret)
['abababab']
# (?P<name>\w+) 模式
>>> ret = re.search('(?P<id>\d{2})/(?P<name>\w{3})', '23/com45/ddd66/xxxx78jishao')
>>> print(ret)
<_sre.SRE_Match object; span=(0, 6), match='23/com'>
>>> print(ret.group())
23/com
>>> print(ret.group('id'))
23
>>> print(ret.group('name'))
com
>>> ret = re.findall('(?P<id>\d{2})/(?P<name>\w{3})', '23/com45/ddd66/xxxx78jishao')
>>> print(ret)
[('23', 'com'), ('45', 'ddd'), ('66', 'xxx')]
12. 元字符之 |
|
表示两项之间的一个选择。要匹配 |
,请使用 \|
。
>>> ret = re.findall('ab|\d', 'rabhdg8sdauubuu888xdd')
>>> print(ret)
['ab', '8', '8', '8', '8']
>>> ret = re.search('ab|\d', 'rabhdg8sdauubuu888xdd')
>>> print(ret.group())
ab
13. 运算符优先级
运算符 | 描述 |
---|---|
\ |
转义符 |
(), (?:), (?=), [] |
圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} |
限定符 |
^, $, \ 任何元字符、任何字符 |
定位点和序列(即:位置和顺序) |
| |
替换,"或"操作 字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。 |
方法
-
re.findall('a', 'alvin yuan')
: 返回所有满足匹配条件的结果,放在列表里 -
re.search('a', 'alvin yuan')
: 函数会在字符串内查找模糊匹配,只找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()
方法得到匹配的字符串,如果字符串没有匹配,则返回None
。 -
re.match('a', 'abc').group()
: 同search
,不过尽在字符串开头处进行匹配。 -
re.split('[ab]', 'abcd')
: 会按a
分割得到和
bcd
,再按b
分别分割得到和
cd
。所以结果是['', '', 'cd']
。 -
re.sub('\d', 'A', 'abcde4566fghim777xfsd', 4)
: 表示将匹配到的字符串替换成另一个字符串,最后的参数表示替换的次数。这个是将数字替换成字母A
,替换四次。不写次数的话默认全部替换。结果是'abcdeAAAAfghim777xfsd'
。 -
re.subn('\d', 'A', 'abcde4566fghim777xfsd')
: 与sub
相同,只是它返回的是一个元组,第一个是替换之后的结果,第二个是**替换 **的次数,不是总的可以匹配到的次数。结果是('abcdeAAAAfghimAAAxfsd', 7)
。re.subn('\d', 'A', 'abcde4566fghim777xfsd', 4)
的结果是('abcdeAAAAfghim777xfsd', 4)
。 -
obj = re.compile('\d{3}')
: 参数只有一个,是匹配规则。函数作用是将规则进行编译,然后可以用得到的对象匹配字符串。例如:obj.findall('abc1234566ef')
,结果是['123', '456']
。对于匹配多次的规则而言,它具有更高的效率。 -
ret = re.finditer('\d','abc345ujf789dxx')
: 将匹配到的结果用一个迭代器返回。查看方法:next(ret)
结果是<_sre.SRE_Match object; span=(3, 4), match='3'>
,查看内容使用next(ret).group()
,结果是'3'
。可以使用for
查看。
注意:
对于分组的规则匹配,默认优先返回组内的内容,若要取消,可以使用 ?:
。
>>> ret = re.findall('www\.(baidu|sina)\.com', 'www.baidu.comxxxxdddwww.sina.comddwwwxbaidu.commm')
>>> print(ret)
['baidu', 'sina']
>>> ret = re.findall('www\.(?:baidu|sina)\.com', 'www.baidu.comxxxxdddwww.sina.comddwwwxbaidu.commm')
>>> print(ret)
['www.baidu.com', 'www.sina.com']
网友评论