我有一个文件,其中包括一堆字符串,如“大小=XXX;“.我第一次尝试Python的re
模块,对以下行为有点困惑:如果在正则表达式中使用管道表示“或”,则只能看到返回匹配位。例如:
>>> myfile = open('testfile.txt', 'r').read()
>>> re.findall('size=50;', myfile)
['size=50;', 'size=50;', 'size=50;', 'size=50;']
>>> re.findall('size=51;', myfile)
['size=51;', 'size=51;', 'size=51;']
>>> re.findall('size=(50|51);', myfile)
['51', '51', '51', '50', '50', '50', '50']
>>> re.findall(r'size=(50|51);', myfile)
['51', '51', '51', '50', '50', '50', '50']
匹配的“size=”部分已经消失了(但它肯定会在搜索中使用,否则会有更多的结果)。我做错了什么?
7条答案
按热度按时间xmq68pz91#
您遇到的问题是,如果
re.findall
试图匹配的正则表达式捕获了组(即,正则表达式中括在括号中的部分),则返回的是组,而不是匹配的字符串。解决此问题的一种方法是使用非捕获组(前缀为
?:
)。如果
re.findall
尝试匹配的正则表达式没有捕获任何内容,则返回整个匹配字符串。尽管在这种特殊情况下使用character classes可能是最简单的选择,但非捕获组提供了更通用的解决方案。
vaqhlq812#
当正则表达式包含括号时,它们会将其内容 * 捕获 * 到组中,将
findall()
的行为更改为仅返回这些组。以下是文档中的相关部分:(...)
匹配括号内的任何正则表达式,并指示组的开始和结束;在执行匹配之后,可以检索组的内容,并且稍后可以在字符串中与
\number
特殊序列进行匹配,如下所述。要匹配文字'('
或')'
,请使用\(
或\)
,或将它们包含在字符类中:[(] [)]
。为了避免这种行为,你可以使用一个 * 非捕获 * 组:
再一次,从docs:
(?:...)
一个非捕获版本的普通括号。匹配括号内的任何正则表达式,但在执行匹配或稍后在模式中引用后,无法检索该组匹配的子字符串。
kokeuurv3#
在某些情况下,非捕获组是不合适的,例如使用正则表达式检测重复的单词(来自python文档的示例)
在这种情况下,要获得整个比赛,可以使用
请注意,
\1
已更改为\2
。r6vfmomb4#
正如其他人提到的,
re.findall
的“问题”是它根据捕获组的使用返回字符串/字符串元组的列表。如果您不想更改正在使用的捕获组(不使用字符组[]
或非捕获组(?:)
),则可以使用finditer
而不是findall
。这给出了 *Match
对象 * 的 * 迭代器 *,而不仅仅是字符串。所以现在你可以获取完整的匹配,即使使用捕获组:将给予:
如果你需要一个列表,类似于
findall
,你可以使用一个list-comprehension:mfuanj7w5#
'size=(50|51);'
表示您正在查找size=50
或size=51
,但仅匹配50
或51
部分(请注意括号),因此它不会返回sign=
。如果你想返回
sign=
,你可以这样做:xiozqbni6#
我认为你想要的是使用
[]
而不是()
。[]
表示一组字符,而()
表示组匹配。试试这样的方法:bxfogqkk7#
您可以使用re.finditer,它也以Match对象iterrator的形式返回所有匹配的值。方法
.group()
返回整个字符串。因此,您的代码可能看起来像下一种方式,