16.正则表达式

相关工具

  • 开源中国提供的正则表达式测试工具:http://tool.oschina.net/regex/

匹配规则

模式
描述

\w

匹配字母数字及下划线

\W

匹配非字母数字及下划线

\s

匹配任意空白字符,等价于 [\t\n\r\f].

\S

匹配任意非空字符

\d

匹配任意数字,等价于 [0-9]

\D

匹配任意非数字

\A

匹配字符串开始

\Z

匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串

\z

匹配字符串结束

\G

匹配最后匹配完成的位置

匹配一个换行符

匹配一个制表符

^

匹配字符串的开头

$

匹配字符串的末尾

.

匹配任意字符,除了换行符,当 re.DOTALL 标记被指定时,则可以匹配包括换行符的任意字符

[...]

用来表示一组字符,单独列出:[amk] 匹配 'a','m' 或 'k'

[^...]

不在 [] 中的字符:abc匹配除了 a,b,c 之外的字符。

*

匹配 0 个或多个的表达式。

+

匹配 1 个或多个的表达式。

?

匹配 0 个或 1 个由前面的正则表达式定义的片段,非贪婪方式

{n}

精确匹配 n 个前面表达式。

{n, m}

匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式

a|b

匹配a或b

( )

匹配括号内的表达式,也表示一个组

re库

Python 的 re 库提供了整个正则表达式的实现

import re

match()

语法:

match(pattern, string, flags=0)

match() 方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,就返回匹配成功的结果,如果不匹配,那就返回 None

import re

content = 'Hello 123 4567 World_This is a Regex Demo'

r = re.match("^Hello\s\d{3}\s\d{4}\s\w{10}",content)
print(r)
print(r.group())
print(r.span())

第一项参数为正则匹配规则,第二项为字符串内容。

运行结果:

41
<_sre.SRE_Match object; span=(0, 25), match='Hello 123 4567 World_This'>
Hello 123 4567 World_This
(0, 25)
  • group()方法:输出匹配到的内容

  • span()方法:输出匹配到的范围

匹配目标

match() 方法可以得到匹配到的字符串内容,如何从字符串中提取一部分内容

在这里可以使用 () 括号来将我们想提取的子字符串括起来,() 实际上就是标记了一个子表达式的开始和结束位置,被标记的每个子表达式会依次对应每一个分组,我们可以调用 group() 方法传入分组的索引即可获取提取的结果。

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

运行结果:

<_sre.SRE_Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
1234567
(0, 19)

group() 会输出完整的匹配结果,group(1) 会输出第一个被 () 包围的匹配结果,假如正则表达式后面还有 () 包括的内容,那么我们可以依次用 group(2)、group(3) 等来依次获取

通用匹配

.(星):匹配任意字符

实例:

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())

运行结果:

<_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

贪婪与非贪婪

贪婪匹配下,.* 会匹配尽可能多的字符

非贪婪匹配的写法是 .*?,尽可能匹配少的字符

import re

# 贪婪
content = 'Hello 123456789 World'
result = re.match('^Hello.*(\d+).*World$', content)
print(result)
print(result.group(1))

# 非贪婪
result = re.match('^Hello.*?(\d+).*World$', content)
print(result)
print(result.group(1))
运行结果:
<_sre.SRE_Match object; span=(0, 21), match='Hello 123456789 World'>
9
<_sre.SRE_Match object; span=(0, 21), match='Hello 123456789 World'>
123456789

修饰符

修饰符解释

修饰符
描述

re.I

使匹配对大小写不敏感

re.L

做本地化识别(locale-aware)匹配

re.M

多行匹配,影响 ^ 和 $

re.S

使 . 匹配包括换行在内的所有字符

re.U

根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.

re.X

该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

实例:

import re

content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo$', content,re.S)
print(result.group(1))

运行结果:

1234567

如果没有re.S的话,会报错,因为没有找到数据,不能进行分组

转义匹配

\将字符进行转义。

import re

content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com', content)
print(result)

match() 方法是从字符串的开头开始匹配,一旦开头不匹配,那么整个匹配就失败了

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.match('Hello.*?(\d+).*?Demo', content)
print(result)

运行结果:

None

这时应该使用search(),它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齐秦">往事随风</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

尝试需要提取歌手名以及歌名,写出正则表达式:

<li.*?a.*?singer="(.*?)">(.*?)</a>

代码如下:

pattern = '<a.*?singer="(.*?)">(.*?)</a>'
# re.S:能让.匹配转行
result = re.search(pattern,html,re.S)
if result:
    print(result.group(1),result.group(2))

findall()

search() 方法的用法,它可以返回匹配正则表达式的第一个内容

如果想要获取匹配正则表达式的所有内容的就需要借助于 findall() 方法

findall() 方法会搜索整个字符串然后返回匹配正则表达式的所有内容

pattern = '<a.*?singer="(.*?)">(.*?)</a>'
results = re.findall(pattern,html,re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0],result[1],result[2])

运行结果:

('任贤齐', '沧海一声笑')
任贤齐 沧海一声笑
('齐秦', '往事随风')
齐秦 往事随风
('beyond', '光辉岁月')
beyond 光辉岁月
('陈慧琳', '记事本')
陈慧琳 记事本
('邓丽君', '但愿人长久')
邓丽君 但愿人长久

sub()

sub()方法可以替换文本中内容,替换成想要替换的新的内容。

import re

content = 'Hello123World'
pattern = '\d+'
print("原内容:"+content)
content = re.sub(pattern,'',content)
print("新内容:"+content)

运行结果:

原内容:Hello123World
新内容:HelloWorld

第一个参数传入 \d+ 来匹配所有的数字,然后第二个参数是替换成的字符串,要去掉的话就可以赋值为空,第三个参数就是原字符串,得到的结果就是替换修改之后的内容

compile()

compile() 给正则表达式做了一层封装,以便于在后面的匹配中复用。

import re

content1 = '2018-7-15 12:00'
content2 = '2018-7-17 12:55'
content3 = '2018-7-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
content1 = re.sub(pattern,'',content1)
content2= re.sub(pattern,'',content2)
content3 = re.sub(pattern,'',content3)
print(content1,content2,content3,sep='\n')

运行结果:

2018-7-15 
2018-7-17 
2018-7-22

最后更新于

这有帮助吗?