re.findall 不返回完整匹配?

Posted

技术标签:

【中文标题】re.findall 不返回完整匹配?【英文标题】:re.findall not returning full match? 【发布时间】:2013-08-27 20:04:36 【问题描述】:

我有一个文件,其中包含一堆字符串,例如“size=XXX;”。我第一次尝试 python 的 re 模块并且对以下行为有点迷惑:如果我在正则表达式中使用管道表示“或”,我只会看到返回的那部分匹配。例如:

>>> myfile = open('testfile.txt','r').read()
>>> print re.findall('size=50;',myfile)
['size=50;', 'size=50;', 'size=50;', 'size=50;']
>>> print re.findall('size=51;',myfile)
['size=51;', 'size=51;', 'size=51;']
>>> print re.findall('size=(50|51);',myfile)
['51', '51', '51', '50', '50', '50', '50']
>>> print re.findall(r'size=(50|51);',myfile)
['51', '51', '51', '50', '50', '50', '50']

匹配的“size=”部分消失了。 (但它肯定在搜索中使用,否则会有更多结果)。我做错了什么?

【问题讨论】:

这能回答你的问题吗? Why does findall not return the whole match when matching with a group? 【参考方案1】:

您遇到的问题是,如果re.findall 尝试匹配的正则表达式捕获组(即括号中的正则表达式部分),则返回的是组,而不是匹配的字符串。

解决此问题的一种方法是使用非捕获组(以?: 为前缀)。

>>> import re
>>> s = 'size=50;size=51;'
>>> re.findall('size=(?:50|51);', s)
['size=50;', 'size=51;']

如果re.findall 尝试匹配的正则表达式没有捕获任何内容,它会返回整个匹配的字符串。

虽然在这种特殊情况下使用character classes 可能是最简单的选择,但非捕获组提供了更通用的解决方案。

【讨论】:

【参考方案2】:

当正则表达式包含括号时,它们捕获其内容到组,改变findall() 的行为以仅返回这些组。这是the docs的相关部分:

(...)

匹配括号内的任何正则表达式, 并指示组的开始和结束;组的内容 可以在执行匹配后检索,并且可以匹配 稍后在带有\number 特殊序列的字符串中,描述 以下。要匹配文字 '('')',请使用 \(\),或将它们括起来 在字符类中:[(] [)]

为避免这种行为,您可以使用非捕获组:

>>> print re.findall(r'size=(?:50|51);',myfile)
['size=51;', 'size=51;', 'size=51;', 'size=50;', 'size=50;', 'size=50;', 'size=50;']

再次,来自文档:

(?:...)

常规括号的非捕获版本。匹配括号内的任何正则表达式,但组匹配的子字符串在执行匹配后无法检索或稍后在模式中引用。

【讨论】:

【参考方案3】:

在某些情况下,非捕获组不合适,例如使用检测重复单词的正则表达式(来自python docs 的示例)

r'(\b\w+)\s+\1'

在这种情况下,可以使用整个匹配项

[groups[0] for groups in re.findall(r'((\b\w+)\s+\2)', text)]

请注意,\1 已更改为 \2

【讨论】:

【参考方案4】:

'size=(50|51);' 表示您正在寻找size=50size=51,但仅匹配5051 部分(注意括号),因此它不返回sign=

如果你想返回sign=,你可以这样做:

re.findall('(size=50|size=51);',myfile)

【讨论】:

(...) 定义了一个匹配组。您也可以使用(size=(50|51)),其中有两个匹配组,第一个是完整的size=5X,第二个是5X 部分。【参考方案5】:

我认为你想要的是使用 [] 而不是 ()。 [] 表示字符集,而 () 表示组匹配。试试这样的:

print re.findall('size=5[01];', myfile)

【讨论】:

有帮助,虽然我正在构建更复杂的正则表达式,我需要 ()【参考方案6】:

这是一个干净的解决方案:https://www.ocpsoft.org/tutorials/regular-expressions/or-in-regex/ 如果网站死在这里是示例(在 regex101.com 上尝试):

正则表达式: ^I like (dogs|penguins), but not (lions|tigers).$ 尝试: 我喜欢狗,但不喜欢狮子。 我喜欢狗,但不喜欢老虎。 我喜欢企鹅,但不喜欢狮子。 我喜欢企鹅,但不喜欢老虎。

第 1 场比赛 全场比赛 2-29 我喜欢狗,但不喜欢狮子。 第 1 组。9-13 只狗 第 2 组。23-28 只狮子 ...

但使用正则表达式: ^I like (?:dogs|penguins), but not (?:lions|tigers).$ 第一场比赛 全场比赛 2-29 我喜欢狗,但不喜欢狮子。 第 2 场比赛 全场比赛 30-58 我喜欢狗,但不喜欢老虎。 ...

【讨论】:

以上是关于re.findall 不返回完整匹配?的主要内容,如果未能解决你的问题,请参考以下文章

re.match re.search re.findall区别

re模块

网络爬虫re模块的findall()函数

模块-re模块

模块-re模块

python 正则(re.compile()/re.findall())