2013-08-25 75 views
5

我有一个文件,其中包括一堆像“size = XXX;”的字符串。我第一次尝试python的re模块,并被以下行为迷惑了一下:如果我在正则表达式中使用'or'管道,我只能看到匹配的那一点返回。例如:re.findall没有返回完全匹配?

>>> 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 =”部分消失了。 (但它肯定用于搜索,否则会有更多结果)。我究竟做错了什么?

回答

19

你的问题是,如果re.findall尝试匹配正则表达式捕获组(即包含在括号中的正则表达式的部分),那么它是返回的组,而不是匹配的字符串。

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

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

如果re.findall尝试匹配正则表达式不捕获任何东西,它返回整个匹配字符串。

尽管在此特定情况下使用character classes可能是最简单的选项,但非捕获组提供了更一般的解决方案。

2

'size=(50|51);'意味着你正在寻找size=50size=51但只有符合5051部分(注意括号),因此它不会返回sign=

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

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

'(...)'定义了一个匹配组。你也可以使用'(size =(50 | 51))',你可以有两个匹配组,第一个是全尺寸= 5X,第二个只是5X部分。 – korylprince

1

我想你想要的是使用[]而不是()。 []指示字符集while()指示组匹配。尝试是这样的:

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

是刚刚编辑,thx – marcadian

+0

有帮助,虽然我构建到更复杂的正则表达式,我将需要() –

5

当正则表达式包含括号,他们捕捉其内容到组,改变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;'] 

再次,从文档:

(?:...)

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