正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
在 Python 中,使用 re 模块来处理正则表达式。re 模块提供了一组函数,允许你在字符串中进行模式匹配、搜索和替换操作。re 模块使 Python 语言拥有完整的正则表达式功能。
本文主要介绍 Python 中常用的正则表达式处理函数。
1 返回一个匹配对象
1.1 re.match函数
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 None。
匹配成功 re.match 方法返回一个匹配的对象,否则返回 None。我们可以使用 group(num) 或 groups() 匹配对象函数来获取匹配表达式。
函数语法:re.match(pattern,string,flags=0)
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
实例一:
import re
pattern = 'www'
string = 'www.baidu.com'
match = re.match(pattern, string, flags=0)
print(match) # 输出:<re.Match object; span=(0, 3), match='www'>
这段代码使用Python的 re
模块来尝试在字符串string
中匹配模式pattern
。
- 我们可以使用
re.match()
函数尝试从字符串 www.baidu.com 的起始位置匹配一个模式 www,如果不是起始位置匹配成功的话,match()
会返回None
。 - 在这个例子中,模式 www 确实出现在字符串www.baidu.com 的起始位置,所以
re.match()
函数返回了一个匹配对象<re.Match object; span=(0, 3), match='www'>,表明它在字符串中找到了模式www。 span=(0, 3)
表示匹配的范围是从字符串的第0个索引开始,到第3个索引之前结束(Python的切片语法是左闭右开的)。也就是说,它匹配了字符串中的'www'
部分。
如果您想要从匹配对象中提取匹配的字符串,您可以使用group()
方法:
print(match.group()) # 输出:'www'
group()
方法返回re.Match
对象表示的匹配字符串。因为没有使用括号在模式中创建任何捕获组,所以group()
返回整个匹配的字符串。如果您使用了捕获组,group()
方法可以用来提取捕获组的内容。
import re
pattern = '(www)\.(baidu)\.com'
string = 'www.baidu.com'
match = re.match(pattern, string, flags=0)
if match:
print(match.group()) # 输出:'www.baidu.com'
print(match.group(1)) # 输出:'www'
print(match.group(2)) # 输出:'baidu'
else:
print("No match found.")
在这个例子中,pattern
包含了两个捕获组:(www)
和(baidu)
,它们分别匹配了'www'
和'baidu'
。group(1)
返回第一个捕获组的内容,group(2)
返回第二个捕获组的内容。
实例二:
import re
pattern = 'com'
string = 'www.baidu.com'
match = re.match(pattern,string,flags=0)
print(match) # 结果:None
这个例子没有在起始位置匹配成功,match()
返回None
。
实例三:
import re
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
# (.*?) 表示"非贪婪"模式,只保存第一个匹配到的子串
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group(1))
print("matchObj.group(2) : ", matchObj.group(2))
else:
print("No match!!")
这段代码使用Python的 re
模块来匹配字符串 line
中的模式。
下面,逐步解释代码的每一部分。
- 你有一个字符串
line
,内容为:"Cats are smarter than dogs"。 - 使用
re.match()
函数来尝试匹配这个字符串。你提供的正则表达式是:r'(.*) are (.*?) .*' - 这个正则表达式的含义如下:
(.*)
: 是一个捕获组。.
表示匹配任何字符(除了换行符),*
表示匹配前面的字符0次或多次。因此,(.*)
可以匹配任意长度的字符串,直到遇到下一个模式。在这里,它会匹配"Cats"。are
: 是字面量匹配,意味着它会匹配字符串中的"are"这个词。(.*?)
: 是另一个捕获组,但使用了?
来使其变为非贪婪模式。非贪婪模式会尽可能少地匹配字符。在这里,它会匹配到"are"后面的第一个空格,因此它会匹配"smarter"。.*
: 这会匹配从上一个捕获组后的任何字符,直到字符串的末尾。 re.M | re.I
是正则表达式的标志:re.M
:多行模式,但在这种情况下,由于line
只是一个单行字符串,所以这个标志没有实际效果。re.I
:忽略大小写模式,这意味着匹配时不区分大小写。- 匹配成功,
matchObj
将包含匹配的结果。你可以使用matchObj.group()
来获取整个匹配的字符串,matchObj.group(1)
来获取第一个捕获组的内容,matchObj.group(2)
来获取第二个捕获组的内容。
1.2 re.search方法
re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法:re.search(pattern, string, flags=0)
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
实例一:
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
# 返回结果:
# (0,3)
# (11,14)
实例二:
import re
line = "Cats are smarter than dogs"
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print ("Nothing found!!")
1.3 re.match 与 re.search的区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
print("match --> matchObj.group() : ", matchObj.group())
else:
print("No match!!")
matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
print("search --> matchObj.group() : ", matchObj.group())
else:
print("No match!!")
# 返回结果:
# No match!!
# search --> matchObj.group() : dogs
2 替换字符串中的匹配项
2.1 re.sub()函数
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
函数语法:re.sub(pattern, repl, string, count=0, flags=0)
参数说明:
- pattern : 正则中的模式字符串。
- repl : 替换的字符串,也可为一个函数。
- string : 要被查找替换的原始字符串。
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
- flags : 编译时用的匹配模式,数字形式。
- 前三个为必选参数,后两个为可选参数。
实例一:前三个为必选参数,后两个为可选参数
import re
phone = '139-6598-9685 # 这是一个电话号码'
# 删除注释
num = re.sub(r'#.*$', '', phone)
print('电话号码 :' , num)
# 移除非数字的内容
num = re.sub(r'\D', '', phone)
print('电话号码 :' , num)
# 返回结果:
# 电话号码 : 139-6598-9685
# 电话号码 : 13965989685
这段Python代码使用了正则表达式来处理一个包含电话号码的字符串。正则表达式是一种强大的文本处理工具,可以用来搜索、匹配和替换文本中的模式。
代码解释如下:
phone = "139-6598-9685 # 这是一个电话号码"
:定义一个字符串变量phone
,其中包含一个电话号码和一个注释。num = re.sub(r'#.*$', "", phone)
:使用re.sub()
函数来替换字符串中的模式。这里,正则表达式#.*$
匹配从#
字符开始到字符串末尾的所有字符。re.sub()
函数将这些匹配到的字符替换为空字符串(即删除它们)。结果存储在变量num
中。print ("电话号码 : ", num)
:打印处理后的字符串。这行代码将输出“电话号码 : 139-6598-985”,因为注释已被删除。num = re.sub(r'\D', "", phone)
:再次使用re.sub()
函数,但这次使用正则表达式\D
来匹配所有非数字字符。这个正则表达式将匹配任何不是数字的字符,并将它们替换为空字符串。结果再次存储在变量num
中。print ("电话号码 : ", num)
:打印处理后的字符串。这行代码将输出“电话号码 : 13965989685”,因为所有非数字字符(包括连字符和注释)都已被删除。
总结:这段代码演示了如何使用正则表达式来删除字符串中的注释和非数字字符,从而提取出纯数字的电话号码。
实例二:repl参数是一个函数
import re
# 将匹配的数字乘以 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
这段Python代码使用了正则表达式来查找字符串 s
中的所有数字,并将这些数字乘以2。然后,它使用re.sub()
函数将这些数字替换为它们乘以2后的结果。
让我们逐行解释这段代码:
-
定义一个名为
double
的函数,该函数接受一个匹配对象作为参数。 -
value = int(matched.group('value'))
:从匹配对象中提取名为'value'的捕获组的值,并将其转换为整数。 -
return str(value * 2)
:将整数值乘以2,然后将其转换回字符串并返回。 -
s = 'A23G4HFD567'
:定义一个字符串s
,其中包含字母和数字。 -
print(re.sub('(?P<value>\d+)', double, s))
:使用re.sub()
函数来查找s
中的所有数字(由\d+
表示,其中\d
匹配任何数字,+
表示一个或多个)。对于每个匹配的数字,它调用double
函数,并将结果替换原始匹配的数字。最后,它打印出替换后的字符串。
在这个例子中,正则表达式(?P<value>\d+)
是一个命名捕获组。?P<value>
命名了捕获组为"value",这样我们就可以在double
函数中通过matched.group('value')
来访问它。\d+
匹配一个或多个数字。
re.sub()
函数的第一个参数是正则表达式模式,第二个参数是要用于替换的函数(在这里是double
函数),第三个参数是要搜索和替换的字符串(在这里是s
)。
最终,这段代码将输出'A46G8HFD1134'
,这是将原始字符串s
中的每个数字乘以2后得到的结果。
3 返回所有匹配项
3.1 re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次, findall 匹配所有。
函数语法:re.findall(pattern, string, flags=0)
参数说明:
- pattern 匹配模式。
- string 待匹配的字符串。
- flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写、多行匹配等。
实例一:返回一个列表
import re
result1 = re.findall(r'\d+','runoob 123 google 456')
print(result1)
# 返回一个列表['123', '456']
实例二:返回元组列表
import re
result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
print(result)
# 返回一个元组列表
# [('width', '20'), ('height', '10')]
3.2 finditer()
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
函数语法:re.finditer(pattern, string, flags=0)
参数说明:
- pattern 匹配的正则表达式。
- string 要匹配的字符串。
- flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
实例一:
import re
it = re.finditer(r"\d+", "12a32bc43jf3")
print(it)
# 返回结果:<callable_iterator object at 0x000001A93EE25FC8>
for match in it:
print(match.group())
# 返回结果:
# 12
# 32
# 43
# 3
这段Python代码使用了re
模块,它是Python的标准库之一,用于正则表达式操作。这段代码的目的是查找字符串"12a32bc43jf3"中所有的数字序列,并打印这些数字序列。
代码分析:
re.finditer(pattern, string)
: 这个函数返回一个迭代器,其中包含字符串中所有与正则表达式模式匹配的非重叠匹配项。pattern = r"\d+"
: 这是一个正则表达式模式,其中\d
代表任何数字(0-9),+
表示匹配一个或多个前面的元素。因此,这个模式匹配一个或多个连续的数字。it = re.finditer(r"\d+","12a32bc43jf3")
: 这行代码调用finditer
函数,并将结果(一个迭代器)存储在变量it
中。print(it)
: 这行代码打印迭代器对象本身,而不是迭代器的内容。它通常不是很有用,除非你想检查对象的类型或状态。for match in it: print (match.group() )
: 这是一个循环,遍历迭代器it
中的所有匹配项。对于每个匹配项,match.group()
返回匹配的字符串,然后这个字符串被打印出来。
4 将匹配的字符串分割
4.1 split()
split 方法按照能够匹配的子串将字符串分割后返回列表。
语法:re.split(pattern, string[, maxsplit=0, flags=0])
参数:
- pattern 匹配的正则表达式
- string 要匹配的字符串
- maxsplit 分割次数,maxsplit=1 分割一次,默认为0,不限制次数
- flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写、多行匹配等。
实例1:使用多个字符作为分割符
import re
# 使用空格、逗号或句号作为分隔符
pattern = r'[,.\s]+'
text = "apple, banana orange. grape"
result = pattern.split(text)
print(result)
# 输出: ['apple', 'banana', 'orange', 'grape']
实例2:保留分割符
import re
# 使用空格作为分隔符,但保留它
text = "apple banana orange"
result = re.split(r'(\s+)', text)
print(result) # 输出: ['apple', ' ', 'banana', ' ', 'orange']
实例3:使用正则表达式的特殊字符作为分隔符
import re
# 使用数字作为分隔符
text = "1apple2banana3orange4"
result = re.split(r'\d+', text)
print(result) # 输出: ['', 'apple', 'banana', 'orange', '']
实例4:
import re
# 使用贪婪匹配来分割字符串,并且保留分隔符
text = "aaa-bbb-ccc-ddd"
result = re.split(r'(?=-)', text)
print(result) # 输出: ['aaa', '-', 'bbb', '-', 'ccc', '-', 'ddd']
在这个例子中,正则表达式 r'(?=-)'
是一个前瞻断言,它匹配一个位置,这个位置后面紧跟着一个短横线 -
。由于这是一个位置而不是一个字符,所以 -
本身不会被消费掉,而是保留在结果列表中。
实例5:忽略空匹配项
import re
# 分割字符串,但忽略空匹配项
text = "a,b,,d"
result = re.split(r',+', text)
print(result) # 输出: ['a', 'b', 'd']
实例6:使用捕获组获来保留分割符
import re
# 使用捕获组来保留分隔符
text = "aaa-bbb,ccc.ddd"
result = re.split(r'([-,.])', text)
print(result) # 输出: ['aaa', '-', 'bbb', ',', 'ccc', '.', 'ddd']
5 正则表达式对象
3.1 re.compile() 函数
在Python中,正则表达式对象是通过re.compile()
函数创建的,这个函数将一个字符串形式的正则表达式编译成一个Pattern对象,供后续使用。一旦你有了这个Pattern对象,你就可以使用它的各种方法来对文本进行匹配、查找、替换等操作。
函数语法:re.compile(pattern[,flags])
参数说明:
- pattern : 一个字符串形式的正则表达式
- flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
返回值:
- 返回一个 Pattern 对象,这个对象包含了编译好的正则表达式,并提供了各种用于匹配、查找、替换等操作的方法。
3.2 正则表达式对象pattern
的方法
3.2.1 findall(string, pos=0, endpos=len(string))
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,包含所有的匹配项。
import re
result1 = re.findall(r'\d+','runoob 123 google 456')
print(result1)
pattern = re.compile(r'\d+')
result2 = pattern.findall('runoob 123 google 456')
print(result2)
result3 = pattern.findall('run88oob123google456', 0, 10)
print(result3)
# 返回结果:是一个列表
# ['123', '456']
# ['123', '456']
# ['88', '12']
3.2.2 search(string, pos=0, endpos=len(string))
在字符串中搜索匹配正则表达式的第一个位置,并返回一个Match对象。如果没有找到匹配项,则返回None。
import re
# 编译一个正则表达式
pattern = re.compile(r'\d+') # 匹配一个或多个数字
# 使用编译后的 Pattern 对象进行匹配
match = pattern.search('The price is 123')
if match:
print(match.group()) # 输出:123
# 使用 flags 参数
pattern_ignore_case = re.compile(r'hello', re.IGNORECASE)
match = pattern_ignore_case.search('Hello, World!')
if match:
print(match.group()) # 输出:Hello
在上面的例子中,我们首先使用 re.compile
编译了一个正则表达式 \d+
,用于匹配一个或多个数字。然后,我们使用 search
方法在字符串中搜索匹配的子串,并使用 group
方法获取匹配的内容。在第二个例子中,我们使用了 re.IGNORECASE
标志位来忽略大小写进行匹配。
3.2.3 match(string, pos=0, endpos=len(string))
从字符串的开始位置匹配正则表达式,并返回一个Match对象。如果没有找到匹配项,则返回None。
import re
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
m = pattern.match('one12twothree34four') # 查找头部,没有匹配
print( m )
# 结果:None
m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
print( m )
# 结果:None
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
print( m ) # 返回一个 Match 对象
# 结果:<re.Match object; span=(3, 5), match='12'>
print(m.group(0)) # 可省略 0
# 结果:12
print(m.start(0)) # 可省略 0
# 结果:3
print(m.end(0)) # 可省略 0
# 结果:5
print(m.span(0)) # 可省略 0
# 结果:(3, 5)
3.2.4 sub(repl, string, count=0)
sub(repl, string, count=0)
使用
repl
替换字符串中所有正则表达式的匹配项,并返回替换后的字符串。如果count
不是0,则只替换前count
个匹配项。
import re
# 编译一个正则表达式,匹配所有的小写字母 a
pattern = re.compile(r'a')
# 使用 sub 方法进行替换操作,将所有的小写字母 a 替换为大写字母 A
result = pattern.sub('A', 'banana')
print(result) # 输出:BAnAnA
3.2.5 subn(repl, string, count=0)
与sub
方法类似,但返回一个元组,包含替换后的字符串和替换的次数。
import re
# 编译一个正则表达式,匹配所有的小写字母 a
pattern = re.compile(r'a')
# 使用 sub 方法进行替换操作,将所有的小写字母 a 替换为大写字母 A
result = pattern.subn('A', 'banana')
print(result) # 输出:('bAnAnA', 3)
6 正则表达式修饰符 - 可选标志
这些标志可以单独使用,也可以通过按位或(|)组合使用。例如,re.IGNORECASE | re.MULTILINE 表示同时启用忽略大小写和多行模式。
7 正则表达式模式
字符串使用特殊的语法来表示一个正则表达式。
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。