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', '']