本模块提供了与 Perl 语言类似的正则表达式匹配操作。
模式和被搜索的字符串既可以是 Unicode 字符串 () ,也可以是8位字节串 ()。 但是,Unicode 字符串与 8 位字节串不能混用:也就是说,不能用字节串模式匹配 Unicode 字符串,反之亦然;同理,替换操作时,替换字符串的类型也必须与所用的模式和搜索字符串的类型一致。
正则表达式用反斜杠字符 ('\'
) 表示特殊形式,或是允许在使用特殊字符时,不引发它们的特殊含义。 这与 Python 的字符串字面值中对相同字符出于相同目的的用法产生冲突;例如,要匹配一个反斜杠字面值,用户可能必须写成 '\\\\'
来作为模式字符串,因为正则表达式必须为
\\
,而每个反斜杠在普通 Python 字符串字面值中又必须表示为 \\
。 而且还要注意,在 Python 的字符串字面值中使用的反斜杠如果有任何无效的转义序列,现在会触发 ,但以后会改为 。 此行为即使对于正则表达式来说有效的转义字符同样会发生。
解决办法是对于正则表达式模式(patterns)使用 Python 的原始字符串表示法;在带有 'r'
前缀的字符串字面值中,反斜杠不必做任何特殊处理。 因此 r"\n"
表示包含 '\'
和
'n'
两个字符的字符串,而 "\n"
则表示只包含一个换行符的字符串。 模式在 Python 代码中通常都使用原始字符串表示法。
绝大多数正则表达式操作都提供为模块函数和方法,在 . 这些函数是一个捷径,不需要先编译正则对象,但是损失了一些优化参数。
第三方模块 , 提供了与标准库 模块兼容的 API 接口,同时,还提供了更多功能和更全面的 Unicode 支持。
正则表达式(或 RE)指定了一组与之匹配的字符串;模块内的函数可以检查某个字符串是否与给定的正则表达式匹配(或者正则表达式是否匹配到字符串,这两种说法含义相同)。
正则表达式可以拼接;如果 A 和 B 都是正则表达式,则 AB 也是正则表达式。通常,如果字符串 p 匹配 A,并且另一个字符串 q 匹配 B,那么 pq 可以匹配 AB。除非 A 或者 B 包含低优先级操作,A 和 B 存在边界条件;或者命名组引用。所以,复杂表达式可以很容易的从这里描述的简单源语表达式构建。更多正则表达式理论和实现,详见 the Friedl book ,或者其他构建编译器的书籍。
以下是正则表达式格式的简要说明。更详细的信息和演示,参考 。
正则表达式可以包含普通或者特殊字符。绝大部分普通字符,比如 'A'
, 'a'
, 或者 '0'
,都是最简单的正则表达式。它们就匹配自身。你可以拼接普通字符,所以 last
匹配字符串 'last'
. (在这一节的其他部分,我们将用 this special style
这种方式表示正则表达式,通常不带引号,要匹配的字符串用 'in
有些字符,比如
'|'
或者 '('
,属于特殊字符。 特殊字符既可以表示它的普通含义, 也可以影响它旁边的正则表达式的解释。
重复修饰符 (*
, +
, ?
, {m,n}
, 等) 不能直接嵌套。这样避免了非贪婪后缀 ?
修饰符,和其他实现中的修饰符产生的多义性。要应用一个内层重复嵌套,可以使用括号。 比如,表达式 (?:a{6})*
匹配6个 'a'
字符重复任意次数。
(点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 ,它将匹配包括换行符的任意字符。
(插入符号) 匹配字符串的开头, 并且在 模式也匹配换行后的首个符号。
匹配字符串尾或者在字符串尾的换行符的前一个字符,在 模式下也会匹配换行符之前的文本。 foo
匹配 'foo' 和 'foobar',但正则表达式
。group 默认为0,就是整个匹配。
pos 的值,会传递给 或 的方法 a 。这个是正则引擎开始在字符串搜索一个匹配的索引位置。
endpos 的值,会传递给 或 的方法 a 。这个是正则引擎停止在字符串搜索一个匹配的索引位置。
捕获组的最后一个匹配的整数索引值,或者 None
如果没有匹配产生的话。比如,对于字符串 'ab'
,表达式 (a)b
, ((a)(b))
, 和
最后一个匹配的命名组名字,或者 None
如果没有产生匹配的话。
返回产生这个实例的 , 这个实例是由 正则对象的 或 方法产生的。
传递到 或 的字符串。
在这个例子里,我们使用以下辅助函数来更好地显示匹配对象:
要看给定的字符串是否有效,我们可以按照以下步骤
最后一手牌,"727ak"
,包含了一个对子,或者两张同样数值的牌。要用正则表达式匹配它,应该使用向后引用如下
要找出对子由什么牌组成,开发者可以按照下面的方式来使用匹配对象的 方法:
Python 目前没有一个类似c函数 scanf()
的替代品。正则表达式通常比 scanf()
格式字符串要更强大一些,但也带来更多复杂性。下面的表格提供了 scanf()
格式符和正则表达式大致相同的映射。
从文件名和数字提取字符串
将字符串用参数传递的样式分隔开。这个方法对于转换文本数据到易读而且容易修改的数据结构,是很有用的,如下面的例子证明。
首先,这里是输入。 它通常来自一个文件,这里我们使用三重引号字符串语法
条目用一个或者多个换行符分开。现在我们将字符串转换为一个列表,每个非空行都有一个条目:
最终,将每个条目分割为一个由名字、姓氏、电话号码和地址组成的列表。我们为 使用了 maxsplit
形参,因为地址中包含有被我们作为分割模式的空格符:
:?
样式匹配姓后面的冒号,因此它不出现在结果列表中。如果 maxsplit
设置为 4
,我们还可以从地址中获取到房间号:
替换字符串中出现的样式的每一个实例。这个例子证明了使用 来整理文字,或者随机化每个字符的位置,除了首位和末尾字符
匹配样式 所有 的出现,不仅是像 中的第一个匹配。比如,如果一个作者希望找到文字中的所有副词,他可能会按照以下方法用
如果需要匹配样式的更多信息, 可以起到作用,它提供了 作为返回值,而不是字符串。继续上面的例子,如果一个作者希望找到所有副词和它的位置,可以按照下面方法使用
原始字符串记法 (r"text"
) 保持正则表达式正常。否则,每个正则式里的反斜杠('\'
) 都必须前缀一个反斜杠来转义。比如,下面两行代码功能就是完全一致的
当需要匹配一个字符反斜杠,它必须在正则表达式中转义。在原始字符串记法,就是 r"\\"
。否则就必须用 "\\\\"
,来表示同样的意思
一个 分析字符串,并分类成目录组。 这是写一个编译器或解释器的第一步。
文字目录是由正则表达式指定的。这个技术是通过将这些样式合并为一个主正则式,并且循环匹配来实现的
该词法器产生以下的输出
在了解正则表达式之前,我们先看几个非常常见的问题:
如何判断字符串是否是有效的电话号码?例如:010-1234567
,123ABC456
,等;
如何判断字符串是否是有效的电子邮件地址?例如:,test#example
等;
如何判断字符串是否是有效的时间?例如:12:34
,09:60
,99:99
等。
一种直观的想法是通过程序判断,这种方法需要为每种用例创建规则,然后用代码实现。下面是判断手机号的代码:
上述代码仅仅做了非常粗略的判断,并未考虑首位数字不能为0
等更详细的情况。
除了判断手机号,我们还需要判断电子邮件地址、电话、邮编等等:
为每一种判断逻辑编写代码实在是太繁琐了。有没有更简单的方法?
正则表达式可以用字符串来描述规则,并用来匹配字符串。例如,判断手机号,我们用正则表达式\d{11}
:
使用正则表达式的好处有哪些?一个正则表达式就是一个描述规则的字符串,所以,只需要编写正确的规则,我们就可以让正则表达式引擎去判断目标字符串是否符合规则。
正则表达式是一套标准,它可以用于任何语言。Java标准库的java.util.regex
包内置了正则表达式引擎,在Java程序中使用正则表达式非常简单。
举个例子:要判断用户输入的年份是否是20##
年,我们先写出规则如下:
一共有4个字符,分别是:2
,0
,0~9任意数字
,0~9任意数字
。
对应的正则表达式就是:20\d\d
,其中\d
表示任意一个数字。
把正则表达式转换为Java字符串就变成了20\\d\\d
,注意Java字符串用\\
表示\
。
最后,用正则表达式匹配一个字符串的代码如下:
可见,使用正则表达式,不必编写复杂的代码来判断,只需给出一个字符串表达的正则规则即可。
正则表达式是用字符串描述的一个匹配规则,使用正则表达式可以快速判断给定的字符串是否符合匹配规则。Java标准库java.util.regex
内建了正则表达式引擎。