栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python基础必掌握的正则表达式功能标志用法详解

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python基础必掌握的正则表达式功能标志用法详解

学Python数据科学,玩游戏、学日语、搞编程一条龙。

整套学习自学教程中应用的数据都是《三國志》、《真·三國無雙》系列游戏中的内容。

对于新手来说正则表达式其实很头疼的,竟让让你怀疑认证怎么能发明出来这么奇怪的东西,其实正则表达式是一个特殊的字符序列,它定义了复杂字符串匹配功能的模式,正则表达式语法需要一点时间来适应。

但是一旦习惯了它,会发现正则表达式在数据处理中几乎是必不可少的。

文章目录
  • Python 中的正则表达式及其用途
  • re 模块功能
    • 搜索功能
    • 替换函数
    • 实用功能
  • 正则表达式的标志匹配
    • 匹配不区分大小写模式
    • 字符串开头和结尾锚点匹配嵌入的换行符
    • 使点元字符匹配换行符
    • 允许在正则表达式中包含空格和注释
    • 显示调试信息
    • 字符编码解析
    • 正则表达式的组合标志
  • 编译的正则表达式对象
  • 匹配对象方法和属性

Python 中的正则表达式及其用途

1951 年数学家 Stephen Cole Kleene 描述了正则语言的概念,这是一种可以被有限自动机识别并可以使用正则表达式形式表达的语言。在 1960 年代中期,计算机科学先驱 Ken Thompson 是 Unix 的原始设计者之一,他使用 Kleene 的符号在 QED 文本编辑器中实现了模式匹配。

经常我们会遇见需要进行字符串进行查找的业务。

s = 'Dynasty123Warriors'

'123' in s
True

以及字符串查找是否包含和索引位置。

s = 'Dynasty123Warriors'

s.find('123')
3

s.index('123')
3

假设字符串 ‘san123Warriors’、‘Dynasty46san’ 是这样的,为了增加查找效率就会使用到正则表达式。

re 模块功能

re 是 Python 正则表达式功能包,其中包含许多有用的函数和方法。

re模块中可用的正则表达式函数分三类:搜索功能、替换函数、实用功能。

搜索功能

查找指定正则表达式的一个或多个匹配项。

功能描述
re.search()扫描字符串以查找正则表达式匹配
re.match()在字符串的开头查找正则表达式匹配
re.fullmatch()查找整个字符串的正则表达式匹配
re.findall()返回字符串中所有正则表达式匹配的列表
re.finditer()返回从字符串产生正则表达式匹配的迭代器

re.search(, , flags=0) ,扫描字符串以查找正则表达式匹配。这里的模式匹配仍然只是逐个字符的比较,与前面显示的 in 运算符和 .find() 示例几乎相同。

re.search(r'(d+)', 'Dynasty123Warriors')
<_sre.SRE_Match object; span=(3, 6), match='123'>

re.search(r'[a-z]+', '123Dynasty456', flags=re.IGNORECASE)
<_sre.SRE_Match object; span=(3, 6), match='Dynasty'>

print(re.search(r'd+', 'Dynasty.Warriors'))
None

re.match(, , flags=0),在字符串的开头查找正则表达式匹配。

re.search(r'd+', '123DynastyWarriors')
<_sre.SRE_Match object; span=(0, 3), match='123'>

re.search(r'd+', 'Dynasty123Warriors')
<_sre.SRE_Match object; span=(3, 6), match='123'>

re.match(r'd+', '123DynastyWarriors')
<_sre.SRE_Match object; span=(0, 3), match='123'>

print(re.match(r'd+', 'Dynasty123Warriors'))
None

re.fullmatch(, , flags=0),在整个字符串上查找正则表达式匹配。

print(re.fullmatch(r'd+', '123Dynasty'))
None

print(re.fullmatch(r'd+', 'Dynasty123'))
None

print(re.fullmatch(r'd+', 'Dynasty123Warriors'))
None

re.fullmatch(r'd+', '123')
<_sre.SRE_Match object; span=(0, 3), match='123'>

re.search(r'^d+$', '123')
<_sre.SRE_Match object; span=(0, 3), match='123'>

re.findall(, , flags=0),返回字符串中正则表达式的所有匹配项的列表。

re.findall(r'w+', '...Dynasty,,,,Warriors:%$dynasty//|')
['Dynasty', 'Warriors', 'dynasty']

re.findall(r'#(w+)#', '#Dynasty#.#Warriors#.#dynasty#')
['Dynasty', 'Warriors', 'dynasty']

re.findall(r'(w+),(w+)', 'Dynasty,Warriors,dynasty,warriors,sanguo,wushuang')
[('Dynasty', 'Warriors'), ('dynasty', 'warriors'), ('sanguo', 'wushuang')]

re.findall(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty,warriors,sanguo,wushuang')
[('Dynasty', 'Warriors', 'dynasty'), ('warriors', 'sanguo', 'wushuang')]

re.finditer(, , flags=0),返回产生正则表达式匹配的迭代器。

it = re.finditer(r'w+', '...Dynasty,,,,Warriors:%$dynasty//|')

next(it)
<_sre.SRE_Match object; span=(3, 6), match='Dynasty'>

next(it)
<_sre.SRE_Match object; span=(10, 13), match='Warriors'>

next(it)
<_sre.SRE_Match object; span=(16, 19), match='dynasty'>

next(it)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration

for i in re.finditer(r'w+', '...Dynasty,,,,Warriors:%$dynasty//|'):
    print(i)
<_sre.SRE_Match object; span=(3, 6), match='Dynasty'>
<_sre.SRE_Match object; span=(10, 13), match='Warriors'>
<_sre.SRE_Match object; span=(16, 19), match='dynasty'>
替换函数
功能描述
re.sub()扫描字符串以查找正则表达式匹配,用指定的替换字符串替换字符串的匹配部分,并返回结果
re.subn()行为类似re.sub(),但也返回有关替换次数的信息

re.sub(, , , count=0, flags=0),返回对搜索字符串执行替换而产生的新字符串。

# 字符串替换
s = 'Dynasty.123.Warriors.789.dynasty'

re.sub(r'd+', '#', s)
'Dynasty.#.Warriors.#.dynasty'

re.sub('[a-z]+', '(*)', s)
'(*).123.(*).789.(*)'

# 用相应捕获组的文本替换编号的反向引用 g
re.sub(r'(w+),Warriors,dynasty,(w+)',
       r'2,Warriors,dynasty,1',
       'Dynasty,Warriors,dynasty,warriors')
'warriors,Warriors,dynasty,Dynasty'

# 通过在尖括号内指定组号来引用编号反向引用
re.sub(r'Dynasty,(w+),(w+),warriors',
       r'Dynasty,g<2>,g<1>,warriors',
       'Dynasty,Warriors,dynasty,warriors')
'Dynasty,dynasty,Warriors,warriors'

# 指定零长度匹配,re.sub()则将替换到字符串中的每个字符位置
re.sub('x*', '-', 'Dynasty')
'-D-y-n-a-s-t-y-'

# 函数替换
def f(match_obj):
    s = match_obj.group(0)  # 匹配字符串
    # s.isdigit() 如果 s 中的所有字符都是数字,则返回 True
    if s.isdigit():
        return str(int(s) * 10)
    else:
        return s.upper()
re.sub(r'w+', f, 'Dynasty.10.Warriors.20.dynasty.30')
'Dynasty.100.Warriors.200.dynasty.300'

# 限制更换次数
re.sub(r'w+', 'xxx', 'Dynasty.Warriors.dynasty.warriors')
'xxx.xxx.xxx.xxx'

re.sub(r'w+', 'xxx', 'Dynasty.Warriors.dynasty.warriors', count=2)
'xxx.xxx.dynasty.warriors'

re.subn(, , , count=0, flags=0),返回对搜索字符串执行替换而产生的新字符串,还返回进行的替换次数。

re.subn(r'w+', 'xxx', 'Dynasty.Warriors.dynasty.warriors')
('xxx.xxx.xxx.xxx', 4)

re.subn(r'w+', 'xxx', 'Dynasty.Warriors.dynasty.warriors', count=2)
('xxx.xxx.dynasty.warriors', 2)

def f(match_obj):
    m = match_obj.group(0)
    if m.isdigit():
        return str(int(m) * 10)
    else:
        return m.upper()
        
re.subn(r'w+', f, 'Dynasty.10.Warriors.20.dynasty.30')
('Dynasty.100.Warriors.200.dynasty.300', 6)
实用功能
功能描述
re.split()使用正则表达式作为分隔符将字符串拆分为子字符串
re.escape()转义正则表达式中的字符

re.split(, , maxsplit=0, flags=0),将字符串拆分为子字符串。

# 指定的字符串拆分为由逗号 ( ,)、分号 ( ;) 或斜线 ( /) 字符分隔的子字符串
re.split('s*[,;/]s*', 'Dynasty,Warriors  ;  dynasty / warriors')
['Dynasty', 'Warriors', 'dynasty', 'warriors']

string = 'Dynasty,Warriors  ;  dynasty / warriors'

regex = r'(?:s*[,;/]s*)'

re.split(regex, string)
['Dynasty', 'Warriors', 'dynasty', 'warriors']

re.escape(),转义正则表达式中的字符。

print(re.match('Dynasty^Warriors(dynasty)|warriors', 'Dynasty^Warriors(dynasty)|warriors'))
None

re.match('Dynasty^Warriors(dynasty)|warriors', 'Dynasty^Warriors(dynasty)|warriors')
<_sre.SRE_Match object; span=(0, 16), match='Dynasty^Warriors(dynasty)|warriors'>

re.escape('Dynasty^Warriors(dynasty)|warriors') == 'Dynasty^Warriors(dynasty)|warriors'
True

re.match(re.escape('Dynasty^Warriors(dynasty)|warriors'), 'Dynasty^Warriors(dynasty)|warriors')
<_sre.SRE_Match object; span=(0, 16), match='Dynasty^Warriors(dynasty)|warriors'>
正则表达式的标志匹配

标志修改正则表达式解析行为可以进一步细化模式匹配。

支持的正则表达式标志

简称原名作用
re.Ire.IGNORECASE使字母字符的匹配不区分大小写
re.Mre.MULTILINE导致字符串开头和结尾锚点匹配嵌入的换行符
re.Sre.DOTALL使点元字符匹配换行符
re.Xre.VERBOSE允许在正则表达式中包含空格和注释
----re.DEBUG使正则表达式解析器向控制台显示调试信息
re.Are.ASCII为字符分类指定 ASCII 编码
re.Ure.UNICODE为字符分类指定 Unicode 编码
re.Lre.LOCALE根据当前语言环境指定字符分类的编码
匹配不区分大小写模式

re.I 和 re.IGNORECASE

re.search('a+', 'aaaAAA')
<_sre.SRE_Match object; span=(0, 3), match='aaa'>

re.search('A+', 'aaaAAA')
<_sre.SRE_Match object; span=(3, 6), match='AAA'>

re.search('a+', 'aaaAAA', re.I)
<_sre.SRE_Match object; span=(0, 6), match='aaaAAA'>

re.search('A+', 'aaaAAA', re.IGNORECASE)
<_sre.SRE_Match object; span=(0, 6), match='aaaAAA'>
字符串开头和结尾锚点匹配嵌入的换行符

re.M 和 re.MULTILINE

s = 'DynastynWarriorsndynasty'

re.search('^Dynasty', s)
<_sre.SRE_Match object; span=(0, 3), match='Dynasty'>

print(re.search('^Warriors', s))
None

print(re.search('^dynasty', s))
None

print(re.search('Dynasty$', s))
None

print(re.search('Warriors$', s))
None

re.search('dynasty$', s)
<_sre.SRE_Match object; span=(8, 11), match='dynasty'>

re.search('Dynasty$', s, re.M)
<_sre.SRE_Match object; span=(0, 3), match='Dynasty'>

re.search('Warriors$', s, re.M)
<_sre.SRE_Match object; span=(4, 7), match='Warriors'>

re.search('dynasty$', s, re.M)
<_sre.SRE_Match object; span=(8, 11), match='dynasty'>
使点元字符匹配换行符

re.S 和 re.DOTALL

print(re.search('Dynasty.Warriors', 'DynastynWarriors'))
None

re.search('Dynasty.Warriors', 'DynastynWarriors', re.DOTALL)
<_sre.SRE_Match object; span=(0, 7), match='DynastynWarriors'>

re.search('Dynasty.Warriors', 'DynastynWarriors', re.S)
<_sre.SRE_Match object; span=(0, 7), match='DynastynWarriors'>
允许在正则表达式中包含空格和注释

re.X 和 re.VERBOSE

# 正则表达式包含一个#非转义字符的会忽略右侧全部字符包含自身。
# 电话号码提取的例子
regex = r'^((d{3}))?s*d{4}[-.]d{4}$'

re.search(regex, '8449.1234')
<_sre.SRE_Match object; span=(0, 9), match='8449.1234'>

re.search(regex, '8449-1234')
<_sre.SRE_Match object; span=(0, 9), match='8449-1234'>

re.search(regex, '(022)8449-1234')
<_sre.SRE_Match object; span=(0, 14), match='(022)8449-1234'>

re.search(regex, '(022) 8449-1234')
<_sre.SRE_Match object; span=(0, 15), match='(022)8449-1234'>
显示调试信息

re.DEBUG

re.search('Dynasty.Warriors', 'DynastyxWarriors', re.DEBUG)
LITERAL 68
LITERAL 121
LITERAL 110
LITERAL 97
LITERAL 115
LITERAL 116
LITERAL 121
ANY None
LITERAL 87
LITERAL 97
LITERAL 114
LITERAL 114
LITERAL 105
LITERAL 111
LITERAL 114
LITERAL 115
<_sre.SRE_Match object; span=(0, 7), match='DynastyxWarriors'>
字符编码解析

指定用于解析特殊正则表达式字符类的字符编码。

"""
re.A / re.ASCII 强制基于 ASCII 编码进行转换。
re.U / re.UNICODE 指定 Unicode 编码。
re.L / re.LOCALE 根据当前语言环境做出判断。

Unicode 联盟创建了 Unicode 来处理这个问题。
Unicode 是一种字符编码标准,旨在代表世界上所有的书写系统。
Python3 中的所有字符串,包括正则表达式,默认都是 Unicode。
"""
# 梵文字符串
s = 'u0967u096au096c'
s
'१४६'

re.search('d+', s)
<_sre.SRE_Match object; span=(0, 3), match='१४६'>
# 德文字符串
s = 'schu00f6n'

s
'schön'

re.search('w+', s, re.ASCII)
<_sre.SRE_Match object; span=(0, 3), match='sch'>
正则表达式的组合标志

在函数调用中组合参数,按位 OR ( | ) 运算符组合

re.search('^Warriors', 'DynastynWarriorsndynasty', re.I|re.M)
<_sre.SRE_Match object; span=(4, 7), match='Warriors'>

在正则表达式中设置和清除标志,(?),在正则表达式的持续时间内设置标志值,a, i, L, m, s, u, 和的一个或多个字母x。

字母标志
are.A、re.ASCII
ire.I、re.IGNORECASE
Lre.L、re.LOCALE
mre.M、re.MULTILINE
sre.S、re.DOTALL
ure.U、re.UNICODE
xre.X、re.VERBOSE

设置IGNORECASE和MULTILINE标志的等效方法

re.search('^Warriors', 'DynastynWarriorsndynastyn', re.I|re.M)
<_sre.SRE_Match object; span=(4, 7), match='Warriors'>

re.search('(?im)^Warriors', 'DynastynWarriorsndynastyn')
<_sre.SRE_Match object; span=(4, 7), match='Warriors'>
编译的正则表达式对象

re.compile(, flags=0),将正则表达式编译为正则表达式对象。

# 正则表达式编译的两种方式
re_obj = re.compile(, )
result = re.search(re_obj, )

# 正则表达式编译后调用的方法
re_obj = re.compile(, )
result = re_obj.search()

编译正则表达式的好处

# 一个重复操作繁琐的例子
s1, s2, s3, s4 = 'Dynasty.Warriors', 'Dynasty123Warriors', 'dynasty99', 'warriors & grault'

import re
re.search('d+', s1)

re.search('d+', s2)
<_sre.SRE_Match object; span=(3, 6), match='123'>

re.search('d+', s3)

<_sre.SRE_Match object; span=(3, 5), match='99'>
re.search('d+', s4)


# 简化编译例1
s1, s2, s3, s4 = 'Dynasty.Warriors', 'Dynasty123Warriors', 'dynasty99', 'warriors & grault'
re_obj = re.compile('d+')

re_obj.search(s1)

re_obj.search(s2)

<_sre.SRE_Match object; span=(3, 6), match='123'>
re_obj.search(s3)

<_sre.SRE_Match object; span=(3, 5), match='99'>
re_obj.search(s4)


# 简化编译例2
s1, s2, s3, s4 = 'Dynasty.Warriors', 'Dynasty123Warriors', 'dynasty99', 'warriors & grault'
regex = 'd+'

re.search(regex, s1)

re.search(regex, s2)
<_sre.SRE_Match object; span=(3, 6), match='123'>

re.search(regex, s3)
<_sre.SRE_Match object; span=(3, 5), match='99'>

re.search(regex, s4)

正则表达式对象方法

"""
re_obj支持的方法
re_obj.search([, [, ]])
re_obj.match([, [, ]])
re_obj.fullmatch([, [, ]])
re_obj.findall([, [, ]])
re_obj.finditer([, [, ]])
re_obj.split(, maxsplit=0)
re_obj.sub(, , count=0)
re_obj.subn(, , count=0)
"""

# 例1
re_obj = re.compile(r'd+')
s = 'Dynasty123Warriorsdynasty'
re_obj.search(s)
<_sre.SRE_Match object; span=(3, 6), match='123'>

s[6:9]
'Warriors'

print(re_obj.search(s, 6, 9))
None

# 例2
re_obj = re.compile('^Warriors')
s = 'DynastyWarriorsdynasty'
s[3:]
'Warriorsdynasty'

print(re_obj.search(s, 3))
None

正则表达式对象属性

属性意义
re_obj.flags任何对正则表达式有效的
re_obj.groups正则表达式中的捕获组数
re_obj.groupindex将构造定义的每个符号组名称(?P)映射到相应组号的字典
re_obj.pattern产生这个对象的模式

在 re.compile() 调用中指定为

re_obj = re.compile(r'(?m)(w+),(w+)', re.I)

re_obj.flags
42

# 这样表述成 re.I 等价于 42
re_obj = re.compile(r'(?m)(w+),(w+)', 42)

re_obj.groups
2

# 正则表示匹配模式
re_obj.pattern
'(?m)(\w+),(\w+)'

# 匹配的索引
re_obj = re.compile(r'(?P),(?P)')

re_obj.groupindex
mappingproxy({'w1': 1, 'w2': 2})

re_obj.groupindex['w1']
1

re_obj.groupindex['w2']
2
匹配对象方法和属性

re模块中的大多数函数和方法都会返回一个匹配对象。

m = re.search('Warriors', 'Dynasty.Warriors.dynasty')

m
<_sre.SRE_Match object; span=(4, 7), match='Warriors'>

bool(m)
True

if re.search('Warriors', 'Dynasty.Warriors.dynasty'):
	# <_sre.SRE_Match object; span=(8, 16), match='Warriors'>
	print('有匹配项')
有匹配项

匹配对象方法

属性返回说明
match.group()指定的捕获组或组来自match
match.__getitem__()捕获的组来自match
match.groups()所有捕获的组来自match
match.groupdict()命名捕获组的字典来自match
match.expand()执行反向引用替换的结果match
match.start()的起始索引match
match.end()结束索引match
match.span()match作为元组的开始和结束索引

match.group([, …]),从匹配中返回指定的捕获组。

m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')

m.group(1)
'Dynasty'

m.group(3)
'dynasty'

# 使用 捕获组(?P)
m = re.match(r'(?Pw+),(?Pw+),(?Pw+)','sanguo,wushuang,grault')

m.group('w1')
'sanguo'

m.group('w3')
'grault'

# 捕获组顺序可以指定
m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')

m.group(1, 3)
('Dynasty', 'dynasty')

m.group(3, 3, 1, 1, 2, 2)
('dynasty', 'dynasty', 'Dynasty', 'Dynasty', 'Warriors', 'Warriors')

m = re.match(r'(?Pw+),(?Pw+),(?Pw+)', 'sanguo,wushuang,grault')

m.group('w3', 'w1', 'w1', 'w2')
('grault', 'sanguo', 'sanguo', 'wushuang')

# 超出范围引发异常
m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')

m.group(4)
Traceback (most recent call last):
  File "", line 1, in 
IndexError: no such group

match.__getitem__(),从匹配中返回捕获的组。

m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')

m.group(2)
'Warriors'

m.__getitem__(2)
'Warriors'

# 返回匹配对象
m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')
m.group(2)
'Warriors'

m.__getitem__(2)
'Warriors'

m[2]
'Warriors'

match.groups(default=None),从匹配中返回所有捕获的组。

# 从匹配中返回所有捕获的组
m = re.search(r'(w+),(w+),(w+)', 'Dynasty,Warriors,dynasty')

m.groups()
('Dynasty', 'Warriors', 'dynasty')

# None可以使用default关键字参数
m = re.search(r'(w+),(w+),(w+)?', 'Dynasty,Warriors,')
m
<_sre.SRE_Match object; span=(0, 8), match='Dynasty,Warriors,'>

print(m.group(3))
None

m.groups()
('Dynasty', 'Warriors', None)

m.groups(default='---')
('Dynasty', 'Warriors', '---')

match.groupdict(default=None),返回命名捕获组的字典。

m = re.match(
	r'Dynasty,(?Pw+),(?Pw+),warriors',
	'Dynasty,Warriors,dynasty,warriors')
	
m.groupdict()
{'w1': 'Warriors', 'w2': 'dynasty'}

m.groupdict()['w2']
'dynasty'

# None可以使用default关键字参数
m = re.match(
	r'Dynasty,(?Pw+),(?Pw+)?,warriors',
	'Dynasty,Warriors,,warriors')
m.groupdict()
{'w1': 'Warriors', 'w2': None}

m.groupdict(default='---')
{'w1': 'Warriors', 'w2': '---'}

match.expand(