python初步学习-Python模块之 re

时间:2021-06-10 22:38:29

re 正则表达式

python正则表达式在线检验网站

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 ...) 分组,除了原有的编号外在指定一个额外的字符串 (?P abc){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*")

表达式前面之所以有一个 r ,是表示 后面为原字符,如一些特殊符号需要转义比较麻烦,前面加一个 r,就可以一劳永逸了。

一下两段内容在语法上是等效的:

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

可以看到速度提升了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
  • 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')

需要注意一点的是,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']
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)

split()

能够按照匹配的字符串将 string 分割后返回列表
格式:
re.split(pattern,string[,maxsplit])
maxsplit 用于指定最大分割次数,不指定将全部分割

print re.spilt(r'\d+','one1two2three3four4five5')

执行结果如下:
['one', 'two', 'three', 'four', 'five', '']