re 正则表达式
python re正则表达式语法
- 匹配字符
语法 | 解释 | 表达式 | 匹配实例 |
. | 匹配任意除“\n”以外的任何字符 | a.c | abc |
\ | 转义符,改变原来符号含义 如果字符串中有字符 * 需要匹配,可以使用 \* 或者字符集[*] | a.c a\c | abe ace ade |
[] | 字符集。对应的位置可以是字符集中任意字符。 字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。第一个字符如果是^则表示取反,如[^abc]表示不是abc的其他字符 | a[bcd]e | abc ace ade |
- 预定义字符集(可以写在字符集[...]中)
语法 | 解释 | 表达式 | 匹配实例 |
\d | 数字:[0-9] | a\dc | a1c a9c |
\D | 非数字: [^\d] [^0-9\] | a\Dc | abc azc |
\s | 空白字符:[\t\r\n\f\v] | a\sc | a c a\tc a\nc |
\S | 非空白字符:[^\s] | a\Sc | abc a1c |
\w | 单词字符:[A-Za-z0-9] | a\wc | abc |
\W | 非单词字符:[^\w] | a\Wc | a c |
- 数量词(用在字符或(...)之后)
语法 | 解释 | 表达式 | 匹配实例 |
* | 匹配前一个字符0或无限次 | abc* | ab abccc |
+ | 匹配前一个字符1次或无限次 | abc+ | abc abccc |
? | 匹配前一个字符0次或1次 | abc? | ab abc |
{m} | 匹配前一个字符m次 | ab{2}c | abbc |
{m,n} | 匹配前一个字符m至n次 m和n可以省略:若省略m,则匹配0至n次 若省略n,则匹配m至无限次 | ab{1,2}c | abc abbc |
*? +? ?? {m,n}? | 使 * + ? {m,n}变成非贪婪模式 |
- 边界匹配(不消耗待匹配字符串中的字符)
语法 | 解释 | 表达式 |
^ | 匹配字符串开头 在多行模式中匹配每一行的开头 | ^abc |
$ | 匹配字符串末尾 在多行模式中匹配每一行的末尾 | abc$ |
\A | 仅匹配字符串开头 | \Aabc |
\Z | 仅匹配字符串末尾 | abc\Z |
\b | 匹配\w和\W之间 | a\b!bc |
\B | [^\b] | a\Bbc |
- 逻辑、分组
语法 | 解释 | 表达式 | 匹配实例 |
| | |代表左右表达式任意匹配一个 它总是先尝试匹配左边的表达式,一旦成功匹配则跳过匹配走遍的表达式 如果|表达式没有被包含在()中,则它的范围是整个正则表达式 | abc|def | abc def |
(...) | 被阔气来的表达式将作为分组,从表达式左边开始没遇到一个分组的左括号"(",编号+1. 另外,分组表达式作为一个整体,可以后接数量词。 表达式中的|仅在该组中有效。 | (abc){2} a(123 | 456) |
(?P...) | 分组,除了原有的编号外在指定一个额外的字符串 | (?Pabc){2} | abcabc |
<number> | 引用编号为的分组匹配到的字符串 | (\d)abc\1 | 1abc1 5abc5 |
(?P=name) | 引用别名为的分组匹配到的字符串 | (?P\d)abc(?p=id) | 1abc1 5abc5 |
+++ 数量词的贪婪模式和非贪婪模式
正则表达式通常用于文本中查找匹配的字符串。Python 里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找“abbbc”,将找到“abbb”。而如果使用非贪婪的数量词"ab*?",将找到"a".
re 模块
- re.complie([pattern[,flags]])
把一个正则表达式 pattern 编译成正则对象,以便可以用正则对象的 match和search 方法。第二个参数flag是匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。
可选值有:
- re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
- M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
- S(DOTALL): 点任意匹配模式,改变'.'的行为
- L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
- U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
- X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的:
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
表达式前面之所以有一个 r ,是表示 后面为原字符,如一些特殊符号需要转义比较麻烦,前面加一个 r,就可以一劳永逸了。
一下两段内容在语法上是等效的:
prog = re.compile(pattern)
result = prog.match(string)
result = re.match(pattern, string)
prog = re.compile(pattern)
result = prog.match(string)
result = re.match(pattern, string)
区别是,用了 re.compile 以后,正则对象会得到保留,这样在需要多次运用这个正则对象的时候,效率会有较大的提升。如下面的例子:
In [1]: import timeit
In [2]: timeit.timeit(
...: ... setup='''import re; reg = re.compile('<(?P<tagnam
...: e>\w*)>.*</(?P=tagname)>')''',
...: ... stmt='''reg.match('<h1>xxx</h1>')''',
...: ... number=1000000)
Out[2]: 0.5159049034118652
In [3]: timeit.timeit(
...: ... setup='''import re''',
...: ... stmt='''re.match('<(?P<tagname>\w*)>.*</(?P=tagna
...: me)>', '<h1>xxx</h1>')''',
...: ... number=1000000)
Out[3]: 1.5837020874023438
In [1]: import timeit
In [2]: timeit.timeit(
...: ... setup='''import re; reg = re.compile('<(?P<tagnam
...: e>\w*)>.*</(?P=tagname)>')''',
...: ... stmt='''reg.match('<h1>xxx</h1>')''',
...: ... number=1000000)
Out[2]: 0.5159049034118652
In [3]: timeit.timeit(
...: ... setup='''import re''',
...: ... stmt='''re.match('<(?P<tagname>\w*)>.*</(?P=tagna
...: me)>', '<h1>xxx</h1>')''',
...: ... number=1000000)
Out[3]: 1.5837020874023438
可以看到速度提升了3倍。
- match()
格式:re.match(pattern,string,flags=0)
如果匹配成功将返回一个 match() 对象,否则返回 None;
match()对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用 match() 提供的可读属性或方法来获取这些信息。
In [30]: s1 = "hello world"
In [31]: p = re.compile(r"(he)")
In [32]: result = re.match(p,s1)
In [33]: print result
<_sre.SRE_Match object at 0x7f6a8c48bf30>
In [35]: print result.string
hello world
In [37]: print result.group()
he
In [30]: s1 = "hello world"
In [31]: p = re.compile(r"(he)")
In [32]: result = re.match(p,s1)
In [33]: print result
<_sre.SRE_Match object at 0x7f6a8c48bf30>
In [35]: print result.string
hello world
In [37]: print result.group()
he
- search()
格式:re.search(pattern,string,flags=0)
re.search()函数会在字符串内查找模式匹配,只要找到第一个匹配然后返回,如果字符串没有匹配,则返回 None
print(re.search('\dcom','www.4comrunoob.5com').group())
执行结果如下:
4com
注:match和search一旦匹配成功,就是一个match object对象,而match object对象有以下方法:
- group() 返回被 RE 匹配的字符串
- start() 返回匹配开始的位置
- end() 返回匹配结束的位置
- span() 返回一个元组包含匹配 (开始,结束) 的位置
- group() 返回re整体匹配的字符串,可以一次输入多个组号,对应组号匹配的字符串。
- a.group() 返回 re 整体匹配的字符串
- b.group(n,m)返回组号为n,m所匹配的字符串,如果组号不存在,则返回indexError异常
- c.groups() groups()方法返回一个包含正则表达式中所有小组字符串的元组,从1到所含的小组号,通常groups()不需要参数,返回一个元组,元组中的元就是正则表达式中定义的组
import re
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)) #123abc456,返回整体
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)) #456
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1,2)) #('123', 'abc')
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).groups()) #('123', 'abc', '456')
import re
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)) #123abc456,返回整体
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)) #456
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1,2)) #('123', 'abc')
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).groups()) #('123', 'abc', '456')
需要注意一点的是,search()的效率要比match()的效率低。因为 search() 会对整个字符串进行扫描,而 match() 只会从头开始匹配,如果开头匹配失败,则 return None。所以 search() 匹配需要花费的时间很多。推荐使用 match().
findall()
re.findall()遍历匹配,可以获得字符串中所有匹配的字符串,返回一个列表。
格式:
re.findall(pattern,string,flags=0)
p = re.compile(r"\d+")
print p.findall("one1two2three3four4")
执行结果如下:
['1', '2', '3', '4']
p = re.compile(r"\d+")
print p.findall("one1two2three3four4")
执行结果如下:
['1', '2', '3', '4']
import re
tt = "Tina is a good girl, she is cool, clever, and so on..."
rr = re.compile(r'\w*oo\w*')
print re.findall(rr,tt)
['good', 'cool']
print re.findall(r'(\w)*oo(\w)',tt)
[('g', 'd'), ('c', 'l')]
import re
tt = "Tina is a good girl, she is cool, clever, and so on..."
rr = re.compile(r'\w*oo\w*')
print re.findall(rr,tt)
['good', 'cool']
print re.findall(r'(\w)*oo(\w)',tt)
[('g', 'd'), ('c', 'l')]
finditer()
搜索string,返回一个顺序访问每一个匹配结果(match对象)的迭代器,找到 re 匹配的所有字符串,并把它们作为一个迭代器返回
格式:
re.finditer(pattern, string, flags=0)
iter = re.finditer(r'\d+','12 drumm44ers drumming, 11 ... 10 ...')
for i in iter:
print(i)
print(i.group())
print(i.span())
执行结果如下:
<_sre.SRE_Match object; span=(0, 2), match='12'>
12
(0, 2)
<_sre.SRE_Match object; span=(8, 10), match='44'>
44
(8, 10)
<_sre.SRE_Match object; span=(24, 26), match='11'>
11
(24, 26)
<_sre.SRE_Match object; span=(31, 33), match='10'>
10
(31, 33)
iter = re.finditer(r'\d+','12 drumm44ers drumming, 11 ... 10 ...')
for i in iter:
print(i)
print(i.group())
print(i.span())
执行结果如下:
<_sre.SRE_Match object; span=(0, 2), match='12'>
12
(0, 2)
<_sre.SRE_Match object; span=(8, 10), match='44'>
44
(8, 10)
<_sre.SRE_Match object; span=(24, 26), match='11'>
11
(24, 26)
<_sre.SRE_Match object; span=(31, 33), match='10'>
10
(31, 33)
split()
能够按照匹配的字符串将 string 分割后返回列表
格式:
re.split(pattern,string[,maxsplit])
maxsplit 用于指定最大分割次数,不指定将全部分割
print re.spilt(r'\d+','one1two2three3four4five5')
执行结果如下:
['one', 'two', 'three', 'four', 'five', '']