资讯动态

python-字符串全解(六):正则表达式-分组

发布时间:2026/10/13 9:51:04 来源:尧图企业网站定制
这一章我们讲分组分组在正则表达式中是一个很有用的工具。它主要有以下的作用重复缩小逻辑运算的范围内容提取反向引用通过命名读取内容等。如果你之前没有学习过分组这么一看这些作用说明肯定没法做到顾名思义甚至会觉得有点迷茫。放心就像我之前说过很多东西你只要一旦明白就会觉得非常的简单如果你读过我之前正则表达式的其他章节你肯定深有体会分组也一样接下来我们会详细的谈论分组。6.分组分组主要是用圆括号包裹起来的语法里面可以包含正则匹配的语法同时还有一些分组特有的语法。主要有捕获组可用于提取内容(...)非捕获组不提取内容(?:...)命名捕获组(?Pname...)引用命名组(?Pname)引用组通过序号例如/1/2。6.1重复以及内容提取((...))在前面讲的语法的时候我们提到了重复我们可以通过*?{m,n}这样的语法来重复前面的字符但是我们需要重复的字符不是一个而是多个呢这时候就需要用到分组双括号()比如(abc)这个代表abc可以重复一次或者多次从而可以匹配abcabcabc这样的字符串。如果在()中开始位置加入?:表示不提取内容。看一下下面的例子import re a abcabc23abcabc12ac1123abc31123abc b re.findall(r(abc)\d, a) b1 re.findall(r(?:abc)\d, a) c re.search(r(abc)\d, a) c1 re.search(r((abc)(\d)), a) print(a {}, b {}, b1 {}, c {}, c.group() {}, c.group(1) {} \ c1.group(0) {}, c1.group(1) {}, c1.group(2) {}, c1.group(3) {}. format(a, b, b1, c, c.group(), c.group(1), c1.group(0), c1.group(1), c1.group(2), c1.group(3))) # 输出结果a abcabc23abcabc12ac1123abc31123abc, # b [abc, abc, abc], b1 [abcabc23, abcabc12, abc31123], # c re.Match object; span(0, 8), matchabcabc23, # c.group() abcabc23, c.group(1) abc c1.group(0) abcabc23, # c1.group(1) abcabc23, c1.group(2) abc, c1.group(3) 23b中我们用圆括号包裹了abc然后在括号后面跟了一个表示abc至少重复一次后面跟了\d,表示数字至少出现一次。我们看b的结果有点奇怪怎么都是abc这是因为findall这个函数只是提取了括号里面的内容。对比一下b1结果就是比较符合预期。b1在原括号中开始位置加入了?:表示不提取括号内容。b1结果的第一个成员abcabc23其中abc至少出现了两次我们看b的结果中都是abc原因是()只提取重复的最后一次所以只有abc这个abc指的是abcabc23中的第二个abc。c我们用了一个全新的函数search这个函数在字符串中找到一个匹配就停止了。打印c发现c是一个Match对象这个对象最常用的函数就是group默认group()返回匹配整个正则的串其实和group(0)效果是一样的。这个正则表达式中有多少个分组()后面就可以跟最大数字是这个分组的个数。c1有三个分组那么group(1)代表第一个分组group(2)代表第二个分组group(3)代表第三个分组。分组是从左到右计算第一个左括号(算第一个第二个左括号(算第二个就算括号之间嵌套也没关系。c1的group(0)和group(1)结果是一样的原因是1把整个正则表达式都包含进来了所以结果也是匹配整个正则的值group(1)和group(2)分别是包含了字母和数字。6.2限制逻辑运算作用域逻辑运算我们还没有讲到我们用|表示或我们看一下下面的代码import re a abc2342adc1123abc31123abc b re.findall(rabc\d{1,9}|adc\d{1,9}|abc3abc\d{1,9},a) c re.findall(r(?:abc|adc|abc)\d{1,9}, a) print(a {}, b {}, c {}. format(a, b, c)) # 输出结果a abc2342adc1123abc31123abc, # b [abc2342, adc1123, abc31123], # c [abc2342, adc1123, abc31123]b是用我们之前的方式我们为了用逻辑或需要将每种可能就完整的写下来这样显得繁琐因为每个或的正则都有共通的\d{1,9}我们可以全部提取到外面这就需要用到分组圆括号这样这个或的逻辑运算只是被限制在圆括号内不会影响括号外的正则如c1所示。因为findall只捕获圆括号中的内容所以可以看到我们用?:来阻止捕获内容这样findall可以得到完整的结果。6.3命名捕获组((?Pname...))可以(?Pname...)这样的形式来给捕获组命名注意P是大些的P这样我们可以在group参数里面通过名字来引用这样做的好处是比没有意义的数字好记。看一下下面的代码import re a abcabc23abcabc12ac1123abc31123abc b re.search(r(?Pword(?Pletterabc)(?Pnumber\d)), a) print(b {}, b.group(1) {}, b.group(2) {}, b.group(3) {} \ b.group(word) {}, b.group(letter) {}, b.group(number) {}. format(b, b.group(1), b.group(2), b.group(3), b.group(word), b.group(letter), b.group(number))) # 输出结果b re.Match object; span(0, 8), matchabcabc23, # b.group(1) abcabc23, b.group(2) abc, b.group(3) 23 # b.group(word) abcabc23, b.group(letter) abc, b.group(number) 23b中我们将三个分组都做了命名最外层的分组命名为word这包含了剩下的两个分组。另外两个分组分别命名为letter和number。打印的结果来看group中输入名字和输入分组的位置都可以得到相同的结果只是命名之后更清晰明白增加了可读性。6.4分组引用((?Pname), \number, number是分组的位置)上一节我们讲了分组我们可以在正则表达式中引用这个分组可以通过命名引用?Pname)也可以通过分组位置引用用\加上分组位置。看一下下面的代码import re a abc12abcabc123abc b re.search(r(?Pletterabc)\d(?Pletter), a) b1 re.search(r(abc)\d\1, a) print(b {}, b.group() {}, b.group(1) {} \ b1.group() {}, b1.group(1) {}. format(b, b.group(), b.group(1), b1.group(), b1.group(1))) # 输出结果b re.Match object; span(0, 8), matchabc12abc, # b.group() abc12abc, b.group(1) abc # b1.group() abc12abc, b1.group(1) abcb首先命名了一个分组为letter这个分组包含了字母abc然后跟了\d表示至少有一个数字然后后引用了这个分组b1是用\1实现了同样的作用。我们可以看到结果是一样的。这里有一点要注意(?Pletter)这只是引用分组但是它本身并不是分组也就是说b的正则表达式中只有一个分组所以如果你b.group(2)会提示没有这个分组。如果你要把它当作一个分组需要再加一对圆括号如下面的代码所示import re a abc12abcabc123abc b re.search(r(?Pletterabc)\d((?Pletter)), a) b1 re.search(r(abc)\d(\1), a) print(b {}, b.group() {}, b.group(1) {}, b.group(2) {} \ b1.group() {}, b1.group(1) {}, b.group(2) {}. format(b, b.group(), b.group(1), b.group(2), b1.group(), b1.group(1), b1.group(2))) # 输出结果b re.Match object; span(0, 8), matchabc12abc, # b.group() abc12abc, b.group(1) abc, b.group(2) abc # b1.group() abc12abc, b1.group(1) abc, b.group(2) abcb和b1都多加了一个括号都有了两个分组这样就可以通过group(2)来获取分组的内容了。讲到这里我们的分组就讲完了。分组在重复多个字符还是很有用的另外分组还可以命名并且被引用这增加了程序的可读性下一章我们会介绍修饰符包含全局和分组修饰符。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑