Python re模块正则表达式使用指南:匹配、修改与高级技巧
本文深入解析Python中re模块的核心用法,涵盖findall、match、search、finditer等匹配类方法,以及sub和split等修改类方法。详细讲解编译优化、大小写忽略、非贪婪匹配及括号分组机制,通过具体代码示例展示如何处理版本字符串、文本分割及复杂模式匹配,帮助开发者高效利用正则表达式进行文本处理。
正则表达式特殊字符详解
正则表达式中,特殊字符具有特定的匹配含义。^符号用于匹配行首,$符号用于匹配行尾,.符号代表任意单个字符。中括号[]用于匹配包含在其中的任意字符,而[^]则匹配不在中括号内的字符。[-]用于匹配指定范围内的任意单个字符。问号?匹配前一项出现1次或0次,加号+匹配前一项出现1次或多次,星号*匹配前一项出现0次或多次。花括号{n}精确匹配前一项n次,{m,n}匹配前一项最小m次、最大n次,{n,}则匹配前一项至少n次。
正则表达式
^ 匹配行首
$ 匹配行尾
. 任意单个字符
[] 匹配包含在中括号中的任意字符
[^] 匹配包含在中括号中的字符之外的字符
[-] 匹配指定范围的任意单个字符
? 匹配之前项的1次或者0次
+ 匹配之前项的1次或者多次
* 匹配之前项的0次或者多次
{n} 匹配之前项的n次
{m,n} 匹配之前项最大n次,最小m次
{n,} 配置之前项至少n次
re模块方法概述
re模块提供了多种方法用于正则表达式的处理,主要分为匹配类和修改类两大类。理解这些方法的功能差异及适用场景,是高效使用正则表达式的关键。
匹配类方法应用
匹配类方法主要用于从文本中提取符合特定模式的内容,包括findall、match、search和finditer等。
findall方法用于在字符串中查找所有符合模式匹配的子串,并以列表形式返回。如果文本中没有匹配项,则返回空列表;如果有一个子字符串匹配,则返回包含该元素的列表。无论匹配结果如何,直接遍历findall的返回值都不会出错,这简化了异常处理逻辑,使代码更加简洁。
# findall方法,该方法在字符串中查找模式匹配,将所有的匹配字符串以列表的形式返回,如果文本中没有任何字符串匹配模式,则返回一个空的列表,
# 如果有一个子字符串匹配模式,则返回包含一个元素的列表,所以,无论怎么匹配,我们都可以直接遍历findall返回的结果而不会出错,这对工程师
# 编写程序来说,减少了异常情况的处理,代码逻辑更加简洁
# re.findall() 用来输出所有符合模式匹配的子串
re_str = "hello this is python 2.7.13 and python 3.4.5"
pattern = "python [0-9]\.[0-9]\.[0-9]"
res = re.findall(pattern=pattern,string=re_str)
print(res)
# ['python 2.7.1', 'python 3.4.5']
pattern = "python [0-9]\.[0-9]\.[0-9]{2,}"
res = re.findall(pattern=pattern,string=re_str)
print(res)
# ['python 2.7.13']
pattern = "python[0-9]\.[0-9]\.[0-9]{2,}"
res = re.findall(pattern=pattern,string=re_str)
print(res)
# []
# re.findall() 方法,返回一个列表,如果匹配到的话,列表中的元素为匹配到的子字符串,如果没有匹配到,则返回一个空的列表
re_str = "hello this is python 2.7.13 and Python 3.4.5"
pattern = "python [0-9]\.[0-9]\.[0-9]"
res = re.findall(pattern=pattern,string=re_str,flags=re.IGNORECASE)
print(res)
# ['python 2.7.1', 'Python 3.4.5']
# 设置标志flags=re.IGNORECASE,意思为忽略大小写
在大量数据处理场景中,采用编译方式使用正则表达式可以显著提升性能。通过re.compile预先编译正则对象,后续调用findall等方法时可直接复用该对象,避免重复编译开销。
# 我们一般采用编译的方式使用python的正则模块,如果在大量的数据量中,编译的方式使用正则性能会提高很多,具体读者们可以可以实际测试
re_str = "hello this is python 2.7.13 and Python 3.4.5"
re_obj = re.compile(pattern = "python [0-9]\.[0-9]\.[0-9]",flags=re.IGNORECASE)
res = re_obj.findall(re_str)
print(res)
match方法类似于字符串的startswith方法,但功能更强大且更具表现力。它用于匹配字符串的开头部分,如果模式匹配成功,返回一个SRE_Match类型的对象;如果匹配失败,则返回None。对于普通前缀匹配,其用法与startswith类似,例如判断字符串是否以特定内容或数字开头。
# match方法,类似于字符串中的startwith方法,只是match应用在正则表达式中更加强大,更富有表现力,match函数用以匹配字符串的开始部分,如果模式
# 匹配成功,返回一个SRE_Match类型的对象,如果模式匹配失败,则返回一个None,因此对于普通的前缀匹配,他的用法几乎和startwith一模一样,例如我
# 们要判断data字符串是否以what和是否以数字开头
s_true = "what is a boy"
s_false = "What is a boy"
re_obj = re.compile("what")
print(re_obj.match(string=s_true))
# <_sre.SRE_Match object; span=(0, 4), match='what'
print(re_obj.match(string=s_false))
# None
s_true = "123what is a boy"
s_false = "what is a boy"
re_obj = re.compile("\d+")
print(re_obj.match(s_true))
# <_sre.SRE_Match object; span=(0, 3), match='123'>
print(re_obj.match(s_true).start())
# 0
print(re_obj.match(s_true).end())
# 3
print(re_obj.match(s_true).string)
# 123what is a boy
print(re_obj.match(s_true).group())
# 123
print(re_obj.match(s_false))
# None
search方法在模式匹配成功后同样返回SRE_Match对象。与match不同,search可以从字符串的任意位置开始匹配,而match只能从头开始。两者的共同点是成功时返回SRE_Match对象,失败时返回None。需要注意的是,search仅查找第一次匹配结果,若需返回所有结果,建议使用findall或finditer方法。
# search方法,模式匹配成功后,也会返回一个SRE_Match对象,search方法和match的方法区别在于match只能从头开始匹配,而search可以从
# 字符串的任意位置开始匹配,他们的共同点是,如果匹配成功,返回一个SRE_Match对象,如果匹配失败,返回一个None,这里还要注意,
# search仅仅查找第一次匹配,也就是说一个字符串中包含多个模式的匹配,也只会返回第一个匹配的结果,如果要返回所有的结果,最简单
# 的方法就是findall方法,也可以使用finditer方法
finditer方法返回一个迭代器,遍历该迭代器可获得SRE_Match对象。这种方式适用于需要逐个处理匹配结果且希望节省内存的场景,例如遍历字符串中所有符合特定格式的版本号。
# finditer返回一个迭代器,遍历迭代器可以得到一个SRE_Match对象,比如下面的例子
re_str = "what is a different between python 2.7.14 and python 3.5.4"
re_obj = re.compile("\d{1,}\.\d{1,}\.\d{1,}")
for i in re_obj.finditer(re_str):
print(i)
# <_sre.SRE_Match object; span=(35, 41), match='2.7.14'>
# <_sre.SRE_Match object; span=(53, 58), match='3.5.4'>
修改类方法应用
修改类方法主要用于对文本进行替换或分割操作,包括sub和split等方法。
sub方法类似于字符串的replace方法,但支持使用正则表达式,因此应用场景更为广泛。通过指定替换模式和替换字符串,可以灵活地对文本进行批量修改。
# re模块sub方法类似于字符串中的replace方法,只是sub方法支持使用正则表达式,所以,re模块的sub方法使用场景更加广泛
re_str = "what is a different between python 2.7.14 and python 3.5.4"
re_obj = re.compile("\d{1,}\.\d{1,}\.\d{1,}")
print(re_obj.sub("a.b.c",re_str,count=1))
# what is a different between python a.b.c and python 3.5.4
print(re_obj.sub("a.b.c",re_str,count=2))
# what is a different between python a.b.c and python a.b.c
print(re_obj.sub("a.b.c",re_str))
# what is a different between python a.b.c and python a.b.c
split方法与Python字符串的split功能类似,用于将字符串拆分为子字符串列表。区别在于,re模块的split方法可以使用正则表达式作为分隔符,从而处理更复杂的分割逻辑,例如使用多个特殊字符(如点号、空格、冒号、感叹号)同时分割字符串。
# re模块的split方法和python字符串中的split方法功能是一样的,都是将一个字符串拆分成子字符串的列表,区别在于re模块的split方法能够
# 使用正则表达式
# 比如下面的例子,使用. 空格 : !分割字符串,返回的是一个列表
re_str = "what is a different between python 2.7.14 and python 3.5.4 USA:NewYork!Zidan.FRA"
re_obj = re.compile("[. :!]")
print(re_obj.split(re_str))
# ['what', 'is', 'a', 'different', 'between', 'python', '2', '7', '14', 'and', 'python', '3', '5', '4', 'USA', 'NewYork', 'Zidan', 'FRA']
在正则表达式中,可以通过设置flags=re.IGNORECASE来实现大小写不敏感匹配。这使得在匹配文本时忽略字母的大小写差异,提高匹配的灵活性。
# 3、大小写不敏感
# re.compile(flags=re.IGNORECASE)
贪婪匹配总是尝试匹配最长的字符串,而非贪婪匹配则匹配最短的字符串。实现非贪婪匹配只需在匹配字符串后添加问号?。例如,使用.*?可以匹配到第一个句号为止的内容,而.*则会匹配到最后一个句号。
# 4、非贪婪匹配,贪婪匹配总是匹配到最长的那个字符串,相应的,非贪婪匹配是匹配到最小的那个字符串,只需要在匹配字符串的时候加一个?即可
# 下面的例子,注意两个.
s = "Beautiful is better than ugly.Explicit is better than impliciy."
re_obj = re.compile("Beautiful.*y\.")
print(re_obj.findall(s))
# ['Beautiful is better than ugly.Explicit is better than implicit.']
re_obj = re.compile("Beautiful.*?\.")
print(re_obj.findall(s))
# ['Beautiful is better than ugly.']
分组匹配与括号处理
在正则表达式中使用小括号会创建分组,影响匹配结果的返回方式。需要区分转义小括号与分组小括号的不同效果。
若需匹配真正的括号字符,必须使用转义符\(和\)。此时,search方法返回的对象调用group(1)会报错,因为未定义分组。例如,匹配字符串中的()符号时,直接搜索即可,无需分组。
import re
s = "=aa1239d&&& 0a ()--"
# obj = re.compile("\(\)")
# search
# rep = obj.search(s)
# print(rep)
# <_sre.SRE_Match object; span=(15, 17), match='()'>
# print(rep.group(1))
# IndexError: no such group
# print(rep.group())
# ()
# findall
rep = obj.findall(s)
print(rep)
# ['()']
若需返回括号中匹配的子字符串,则小括号无需转义,此时它表示分组。findall方法返回括号内匹配到的字符串列表;search.group()返回整个模式匹配的字符串;search.group(1)返回第一个小括号中匹配的内容;search.group(2)返回第二个小括号中匹配的内容,以此类推。
s = "=aa1239d&&& 0a ()--"
rep = re.compile("\w+(&+)")
print(rep.findall(s))
# ['&&&']
print(rep.search(s).group())
# aa1239d&&&
print(rep.search(s).group(1))
# &&&
本文介绍了Python re模块的主要使用方法,包括匹配、修改及高级技巧。希望这些内容能对读者学习正则表达式有所帮助,欢迎继续支持相关技术分享。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









