我正在研究一个CS50问题,你必须找到连续重复的字符串模式(DNA序列中的核苷酸)。我想我会使用re
,因为它是Python3的分配,我已经用一点之前,并认为我可以弄清楚…但是不。
所以我搜索了如何才能完成这个任务,并找到了一个用户建议使用re.findall("(?:<pattern>)+", <string>)
的主题,这正是我需要解决的问题。
所以我对?:
表达感到好奇,并查阅了文档,但无法理解non-capturing group
意味着什么,并且再次,当我发现使用由网址组成的字符串解释时,不得不四处寻找答案。
在这个特定的例子中,用户使用的是re.match
:
"(?:https?|ftp)://(stackoverflow.com)"
output:
group1: (stackoverflow.com)
vs
"(https?|ftp)://(stackoverflow.com)"
output:
group1: (https)
group2: (stackoverflow.com)
在这一点上,我明白了什么是非捕获的意思…但是现在我不明白为什么?:
对re.match
和re.findall
的行为不同,其中匹配对象,如官方文档中所述,不捕获指示组,而从re.findall
方法返回的列表似乎捕获匹配子字符串和分组连续重复为一个。
我最好的猜测是,因为它是非捕获的方法继续寻找匹配的子字符串连续,一旦它结束它"关闭";组,这就是为什么重复的子字符串被分组为一个。但我仍然不知道为什么re.findall
返回不应该被捕获的东西,如果有人能指出我在正确的方向,我真的很感激。
regex中的'捕获组'通常用括号表示。在像这样的正则表达式中:
<before>(<capture>)<after>
"捕获组"是(<capture>)
,这意味着这是我们实际想要的字符串的部分-正则表达式的其余部分是针对它的。我们需要它来捕获,例如,"数字后面跟着单词'美元'":
(d+)s*dollar
re.match()
返回一个Match
对象,它有几个"组",你可以用.group(n)
方法访问。
- Group 0总是包含整个匹配字符串,无论其中是否有任何'match groups'。在上面的例子中,与字符串
"35 dollar item"
匹配,它将是' "35美元" - 组
n > 0
包含正则表达式中的第n个捕获组。在上面的例子中,与字符串"35 dollar item"
匹配,它将是"35"
。
re.findall()
的行为根据regex中捕获组的数量而不同:
- 如果没有捕获组,返回匹配整个正则表达式的所有字符串的列表(例如
.group(0)
) - 如果只有一个捕获组,返回与捕获组匹配的所有字符串的列表(例如
.group(1)
) - 如果有多个捕获组,返回
(.group(1), .group(2), ..., .group(n))
的元组列表。
无组织的想法是,有时我们想使用需要括号的表达式来消除歧义。最常见的是|
。例如,如果我想要捕捉以"先生"称呼的某人的姓氏(而不是头衔);或者"Ms.",我可以这样写一个正则表达式:
(?:Mr|Ms).s*(w+)
(?:Mr|Ms)
是一个非捕获组,因此它不会被视为它自己的组(例如.group(1)
)。同时,(w+)
捕获组,所以将视为自己的集团。从这里,我们可以观察到re.match()
和re.findall()
的行为,并看到它们与它们的文档一致:
>>> regex = r'(?:Mr|Ms).s*(w+)'
>>> mo = re.match(regex, 'Mr. Big and Ms. Small')
>>> mo.group(0)
'Mr. Big'
>>> mo.group(1)
'Big'
>>> re.findall(regex, 'Mr. Big and Ms. Small')
['Big', 'Small']
因为只有一个捕获组,re.findall()
忽略组0。
对比以下行为,将Mr
和Ms
注册为捕获组,从而产生不同的输出(因为现在有多个捕获组,所以re.findall()
更改了其输出格式:
>>> regex2 = r'(Mr|Ms).s*(w+)' # omitting the ?:
>>> re.findall(regex2, 'Mr. Big and Ms. Small')
[('Mr', 'Big'), ('Ms', 'Small')]