如何在Python的正则表达式中使用?和?:及:?

3 投票
4 回答
1521 浏览
提问于 2025-04-15 15:07

我明白了

* = "zero or more"
? = "zero or more" ...what's the difference?

另外,?: 这个符号在我的书里有提到,它说这是一个“细微之处”,但我不太清楚它到底是干什么的!

4 个回答

2

? 表示零个或一个

你可以用 (?:) 来进行分组,但它不会像 () 那样把分组的内容保存到一个临时变量里

4

?: << 我的书里提到这个,它说这是一个“细微之处”,但我不知道这些到底是干嘛的!

如果你的书真是这么说的,那我建议你换一本更好的书。

在括号里面(更准确地说,是在开括号后面),?有另一种意思。它开始一个选项的组,这些选项只在括号的范围内有效。?:是这些选项的一种特殊情况。要理解这个特殊情况,你首先得知道括号是用来创建捕获组的:

a(.)c

这是一个正则表达式,它可以匹配任何以a开头、以c结尾的三字母字符串。中间的字符是(或多或少)随意的。因为你把它放在了括号里,所以你可以捕获它:

m = re.search('a(.)c', 'abcdef')
print m.group(1)

这将打印出b,因为m.group(1)捕获了第一个括号里的内容(group(0)捕获的是整个匹配的结果,这里是abc)。

现在,考虑这个正则表达式:

a(?:.)c

这里没有进行捕获——这就是在开括号后面加?:的意思。也就是说,下面的代码会失败:

print m.group(1)

因为没有组1!

6

正如Manu所说,?的意思是“零次或一次”。这和{0,1}是一样的。

而你提到的?:,可能是指(?:X),这里的X是其他的字符串。这被称为“非捕获组”。

通常,当你用括号把某些东西包起来时,你是在把这些括号匹配到的内容分组。例如,正则表达式.(.).(.)可以匹配任何四个字符(除了换行符),并把第二个字符存储在组1中,把第四个字符存储在组2中。但是,当你写.(?:.).(.)时,只有第四个字符会被存储在组1中,括号(?:.)之间的内容会被匹配,但不会被“记住”。

这里有个小演示:

import re
m = re.search('.(.).(.)', '1234')
print m.group(1)
print m.group(2)
# output:
# 2
# 4

m = re.search('.(?:.).(.)', '1234')
print m.group(1)
# output:
# 4

你可能会问:“为什么要使用这个非捕获组呢?”其实,有时候你想在两个字符串之间做一个“或”的匹配,比如你想匹配字符串“www.google.com”或“www.yahoo.com”,你可以写成www\.google\.com|www\.yahoo\.com,但更简洁的写法是www\.(google|yahoo)\.com。不过,如果你不打算对这个组捕获到的内容(比如“google”或“yahoo”)做什么有用的事情,那你就可以使用非捕获组:www\.(?:google|yahoo)\.com。当正则引擎不需要“记住”子串“google”或“yahoo”时,你的应用程序或脚本运行会更快。当然,对于相对较小的字符串,这种差别不大,但当你的正则表达式和字符串变得更大时,可能就会有明显的差别。

想要更好地理解非捕获组的例子,可以看看Chris Lutz在下面的评论。

撰写回答