Python正则表达式:如何使用正则表达式

本文详细介绍了Python中如何使用正则表达式,包括正则表达式的简述、匹配和处理重复字符串的方法,以及编译、执行匹配的步骤。还讨论了正则表达式的更多特性,如元字符、分组和预测先行断言,并讲述了如何修改和替换字符串。最后,解答了一些常见问题,对比了match()和search()的区别,解释了贪婪与非贪婪匹配的概念,并推荐使用re.VERBOSE提高代码可读性。
摘要由CSDN通过智能技术生成
正则表达式(简称RE)本质上可以看作一个小的、高度专业化的编程语言,在Python中可以通过re模块使用它。使用正则表达式,你需要为想要匹配的字符串集合指定一套规则,字符串集合可以包含英文句子、e-mail地址、TeX命令或者其它任何你希望的字符串。然后您能提这样的问题:“这个字符串匹配这个模式吗?”,或者“在这个字符串中存在这个模式的匹配吗?”。你也能使用正则表达式修改一个字符串或者分离它。
正则表达式被编译到一系列的字节码,然后被C语言实现的匹配引擎执行。在一些高级应用场景,必须关注引擎怎么执行一个RE,以根据引擎的特征编写RE提高字节码的处理效率。这篇文章不包含优化,优化需要对匹配引擎的内部实现有好的理解。

正则表达式相对小并且存在限制,所以不是所有的字符串处理任务都能用正则表达式解决。也存在有些任务可以用正则表达式做,但表达式非常复杂。在这些情况下,更好的选择是使用Python代码处理,但Python代码相对正则表达式会更慢,但却可能更好理解。

正则表达式简述

我们将从最简单的正则表达式开始,由于正则表达式被用于字符串的操作,我们将从最常用的任务开始:匹配字符。

匹配字符串

大部分字母和字符将匹配他们自身,例如,正则表达式test将匹配字符串test(你可以开始大小写不敏感模式,这样RE可以匹配Test或者TEST)。
这个规则存在例外,一些字符是特殊元字符,不匹配他们自身。他们暗示一些不寻常的事将被匹配,或者他们影响RE的其它部分,例如重复他们或者改变他们的含义。文章的其余部分都主要讨论各种元字符和他们的含义。
下面是元字符的列表,后面将介绍他们的含义:
. ^ $ * + ? { } [ ] \ | ( )
首先我们看[和],他们被用于指定一个字符类,表示你希望匹配的一套字符集。字符能被单独列出,或者使用'-'来指示字符的范围,例如:[abc]将匹配字符a、b或c的任意一个;[a-c]也是匹配a、b或c中的任意一个。如果你想匹配仅小写字母,那么RE应该为[a-z]。
在类中([ ]内)的元字符不是激活的,例如:[akm$]将匹配'a'、'k'、'm'或'$'中的任意一个,'$'是一个元字符,但是在字符类中它作为普通字符使用。
你也能排除类中列出的字符集,通过将'^'作为类的第一个字符,注意在类之外的'^'将仅仅匹配'^'字符,例如:[^5]将匹配除了5之外的任何字符。
或许最重要的元字符是反斜杠\。在Python中,反斜杠能被各种字符跟随作为各种特殊序列使用。它也能被用于取出元字符的特殊性将其作为本身匹配,例如:如果你需要匹配一个[或者\,你能在它们之前带上一个反斜杠移除它们的特殊含义,即\[或者\\。
以'\'开始的特殊序列中的一些表示了经常被使用的预定义字符集,例如数字集合、字符集合、或者非空白的任意字符集合。
让我们看一个例子:\w匹配任何字母数字。如果正则表达式模式以字节为单位,这等价于类[a-zA-Z0-9_]。如果正则表达式模式是字符串,则\w将匹配所有被unicodedata模块提供的在Unicode数据库总的字符。当编译正则表达式时,你能添加re.ASCII标志给\w更严格的限制。
下面提供了部分特殊序列供参考:
\d:匹配任意数字,等价于[0-9];
\D:匹配任意非数据字符,等价于[^0-9];
\s:匹配任意空白字符,等价于[ \t\n\r\f\v];
\S:匹配任意非空白字符,等价于[^ \t\n\r\f\v];
\w:匹配任意字母数字,等价于[a-zA-Z0-9_];
\W:匹配任意非字母和数字,等价于[^a-zA-Z0-9_]。
这些序列可以被包含到字符类中,例如:[\s,.]是一个字符类,将匹配任意的空白字符,或者',',或者'.'。
在这节中最后的元字符是'.',它匹配除了新行字符之外的任何字符,使用交替模式(re.DOTALL)它将匹配包括新行的所有字符,'.'通常被用于需要匹配“任意字符”的场景。

处理重复

正则表达式的首要功能是匹配字符集,而正则表达式的另一个能力则是指定RE中特定部分必须被重复多少次。
处理重复的第一个元字符是'*','*'不会匹配字符'*',它表示先前的字符能被匹配0次或者多次。
例如:ca*t将匹配ct(0个a)、cat(1个a)、caaat(3个a)、等等。RE引擎内部会限制a的匹配的数量,但通常足够了。
重复(例如*)算法是贪婪的,对于重复的RE,匹配引擎将尝试尽可能多的重复次数,如果模式的后面部分不匹配,则匹配引擎将回退并再次尝试更少的重复次数。
例如,考虑表达式a[bcd]*b,这匹配单词'a',0个或者多个来自类[bcd]的字母,最后以'b'结束。下面是RE匹配abcbd的过程:
1、匹配a:RE匹配a成功;
2、匹配abcbd:引擎匹配[bcd]*,由于尽可能的匹配更多,所以匹配了整个字符串;
3、匹配失败:引擎试着匹配b,但是已经到达字符串结尾,因此失败;
4、匹配abcb:回退,[bcd]*匹配减少一个字符;
5、匹配失败:再次尝试b,但当前位置的字符为d;
6、匹配abc:继续回退,以至于[bcd]*仅匹配bc;
7、匹配abcb:再次尝试b,这次当前位置的字符为b,匹配成功,结束。
RE最终匹配abcb,整个过程演示了匹配引擎的匹配过程,首先匹配尽可能多的字符,如果不匹配,则不断回退再次尝试。它将回退直到[bcd]*匹配0个字符,如果任然失败,则引擎得出结论“字符串不匹配RE”。
另一个重复的元字符是+,匹配一次或者多次。小心*和+之间的不同,*匹配0次或者多次,即可以匹配空;+则需要至少出现一次。例如:ca+t将匹配cat(1个a),caaat(3个a),但不匹配ct。
另外还有两个重复限定符,其一是问号'?',表示匹配一次或者0次,例如:home-?brew匹配homebrew或者home-brew。
最复杂的重复限定符是{m,n},其中m和n都是正整数,表示至少匹配m次,最多匹配n次。例如:a/{1,3}b将匹配a/b,a//b,和a///b,它将不匹配ab,或者ab。
你能忽略m或者n,忽略m表示最小值为0,而忽略n表示无限制。
你可能已经注意到,使用最后一个限定符可以取代前面3个限定符:{0,}等价于*;{1,}等价于+;{0,1}等价于?。为什么使用*、+或者?呢?主要在于,更简短的表达式更利于阅读和理解。

使用正则表达式

现在我们已经了解了正则表达式的基本语法,下面看在Python中怎么使用正则表达式。re模块提供了使用正则表达式的接口,允许你编译RE到对象,然后使用它们。

编译正则表达式

正则表达式被编译到模式对象,提供了各种操作的方法,例如模式匹配或者替换。
>>> import re
>>> p = re.compile('ab*')
>>> p
re.compile('ab*')
re.compile()也提供了一个可选的flags参数,用于激活各种特征,后面将详细介绍,下面是一个简单的例子:
>>> p = re.compile('ab*', re.IGNORECASE)
RE作为一个字符串传给re.compile()。RE被作为字符串处理是因为正则表达式不是Python语言核心的一部分,没有特定的语言用于创建它们。re模块仅仅是Python包含的一个C语言扩展模块,就像socket和zlib模块一样。
将RE作为字符串保持了Python语言的简单,但也存在不利,例如下一节将讲述的内容。

反斜杠问题

如前所述,正则表达式使用反斜杠来表示一些特殊组合或者允许特殊字符作为普通字符使用。这一点和Python对于发斜杠的使用冲突。
你如果想写一个RE匹配字符串\section,我们看看怎么构造一个正则表达式对象:首先,我们使用整个字符串作为正则表达式;其次,找出反斜杠和其它元字符,在它们前面添加反斜杠,变为\\section;最后,字符串被传入到re.compile(),由于传入的必须为\\section,结合Python语法,每个\的前面必须再次添加一个\,因此,最终在Python中传入的字符串为"\\\\section"。
简而言之,为了匹配一个反斜杠,在Python中你需要写'\\\\'作为RE字符串。这导致了很多重复的反斜杠,使语法很难于理解。
解决方案是为正则表达式使用Python的原生字符串注释。当字符串带有前缀'r'时,反斜杠将不以特殊字符处理,于是r"\n"是包含'\'和'n'的两个字符的字符串,而"\n"是包含换行符的一个字符的字符串。在Python中正则表达式将经常采用这种方式编写。

执行匹配

一旦你有一个已编译的正则表达式对象,你就可以使用该对象的方法和属性,下面做一个简单的介绍。
1)match()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值