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=50
或size=51
,但仅匹配50
或51
部分(注意括号),因此它不返回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 不返回完整匹配?的主要内容,如果未能解决你的问题,请参考以下文章