1. 正则表达式分组概述
在正则表达式中,分组是一种重要的操作。简单来说,分组是将正则表达式中的多个元素看做一个整体,从而使得每个元素都可以被独立处理。分组可以用来进行捕获、非捕获、零宽断言等操作。
在正则表达式中,分组通常使用一对圆括号来表示。比如,(\d+) 表示一个至少包含一个数字的分组,可以匹配诸如「123」、「4567」等字符串。
2. 普通捕获分组
普通捕获分组可以用来捕获正则表达式中的一部分内容,它的语法形式是 (pattern)。当进行正则匹配时,匹配到的分组内容会被记录下来。
2.1 示例
比如,我们要匹配以「abc」开头、以「def」结尾的字符串,并捕获中间的部分。可以使用以下正则表达式:
(abc)(.*)(def)
在这个表达式中,我们用一对圆括号将「.*」这个部分包裹起来,表示将这部分捕获下来。
接下来,假设我们要匹配的字符串是「abcdefg」,可以使用以下代码进行匹配:
import re
text = 'abcdefg'
pattern = '(abc)(.*)(def)'
match = re.match(pattern, text)
if match:
print(match.groups())
运行上述代码,会输出如下结果:
('abc', 'deg', 'def')
注意,这里的结果中包含了三个元素,分别对应着表达式中每个捕获分组的内容。
3. 命名捕获分组
命名捕获分组是指给捕获分组起一个名字,方便在匹配结果中直接通过名字获取对应的内容。命名捕获分组的语法形式是 (?P<name>pattern)。
3.1 示例
比如,我们要匹配一个格式为「name: Tom, age: 20」的字符串,并捕获其中的 name 和 age 两个字段。可以使用以下正则表达式:
(?P<name>\w+).*age: (?P<age>\d+)
在这个表达式中,我们使用了两个命名捕获分组,分别捕获了 name 和 age 两个字段。
接下来,假设我们要匹配的字符串是「name: Tom, age: 20」,可以使用以下代码进行匹配:
import re
text = 'name: Tom, age: 20'
pattern = '(?P<name>\w+).*age: (?P<age>\d+)'
match = re.match(pattern, text)
if match:
print(match.group('name'))
print(match.group('age'))
运行上述代码,会输出如下结果:
Tom
20
注意,在这里我们需要使用 group 函数获取命名捕获分组的内容,参数是捕获分组的名字。
4. 非捕获分组
非捕获分组是指使用 (?:pattern) 的形式来进行分组,但不记录匹配到的内容。非捕获分组通常用来进行分组匹配,但不需要将匹配结果记录下来。
4.1 示例
假设我们要匹配一个字符串,该字符串中有多个连续的数字,且这些数字都用逗号隔开。我们要求这些数字之间的逗号可以是英文逗号「,」,也可以是中文逗号「,」。可以使用以下正则表达式:
\d+(?:,|,)\d+
在这个表达式中,我们使用了一个非捕获分组 (?:,|,),它表示匹配英文逗号「,」或者中文逗号「,」,但不记录匹配内容。
5. 零宽度断言
零宽度断言是指只匹配位置,不匹配字符的正则表达式操作。它可以用来限制匹配位置的前后关系,让我们只匹配符合条件的字符串。分为正向零宽度断言和负向零宽度断言。
5.1 正向零宽度断言
正向零宽度断言是使用 (?=pattern) 的形式来进行分组。它表示只有在匹配到 pattern 后面的位置,才能继续向下匹配。
5.1.1 示例
假设我们要匹配一个字符串中的数字,并且这些数字前面必须是「$」符号。可以使用以下正则表达式:
\$(?=\d+)
在这个表达式中,我们使用了一个正向零宽度断言 (?=\d+),它表示只有在匹配到数字后面的位置,才能继续向下匹配。
接下来,假设我们要匹配的字符串是「$100.00」,可以使用以下代码进行匹配:
import re
text = '$100.00'
pattern = '\$(?=\d+)'
match = re.search(pattern, text)
if match:
print(match.group())
运行上述代码,会输出如下结果:
$
注意,在这里我们需要使用 search 函数进行匹配,因为正向零宽度断言需要从字符串中某个位置开始匹配,而不是从字符串的开头开始。
5.2 负向零宽度断言
负向零宽度断言是使用 (?!pattern) 的形式来进行分组。它表示只有在匹配到不是 pattern 后面的位置,才能继续向下匹配。
5.2.1 示例
假设我们要匹配一个字符串中的数字,并且这些数字后面不能跟着「元」字符。可以使用以下正则表达式:
\d+(?![元\d])
在这个表达式中,我们使用了一个负向零宽度断言 (?![元\d]),它表示只有在匹配到不是元字符或者数字的位置,才能继续向下匹配。
接下来,假设我们要匹配的字符串是「100.00元」,可以使用以下代码进行匹配:
import re
text = '100.00元'
pattern = '\d+(?![元\d])'
match = re.search(pattern, text)
if match:
print(match.group())
运行上述代码,会输出如下结果:
00
注意,在这里只匹配到了「00」,而没有匹配到「100」。这是因为正则表达式中的 \d+ 默认会匹配尽可能多的数字,而我们使用了负向零宽度断言后,只有不满足条件的部分才能被匹配上。