为什么re.findall在模式中只有一个组时返回元组列表?

16 投票
6 回答
29649 浏览
提问于 2025-04-18 12:15

假设我有一个字符串 s,里面有字母和两个分隔符 12。我想按照以下方式来拆分这个字符串:

  • 如果一个子字符串 t12 之间,就返回 t
  • 否则,就返回每个字符

比如说,如果 s = 'ab1cd2efg1hij2k',那么我希望得到的结果是 ['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']

我尝试使用正则表达式:

import re
s = 'ab1cd2efg1hij2k'
re.findall( r'(1([a-z]+)2|[a-z])', s )

[('a', ''),
 ('b', ''),
 ('1cd2', 'cd'),
 ('e', ''),
 ('f', ''),
 ('g', ''),
 ('1hij2', 'hij'),
 ('k', '')]

从这里我可以用 [ x[x[-1]!=''] for x in re.findall( r'(1([a-z]+)2|[a-z])', s ) ] 来得到我的答案,但我还是不太明白输出的结果。文档说 findall 如果模式有多个组,就会返回一个元组的列表。然而,我的模式只有一个组。欢迎任何解释。

6 个回答

1

看看这个回答,它是针对类似问题的: https://bugs.python.org/issue6663 如果你在使用findall的时候,可以直接去掉括号。

import re
s = 'ab1cd2efg1hij2k'
re.findall( r'(?<=1)[a-z]+(?=2)|[a-z]', s )
4

如果你想要在匹配中使用“或”这个功能,但又不想把结果分成不同的匹配组,只需要在“或”匹配的开头加上“?:”就可以了。

没有“?:”的情况

re.findall('(test (word1|word2))', 'test word1')

Output:
[('test word1', 'word1')]

有“?:”的情况

re.findall('(test (?:word1|word2))', 'test word1')

Output:
['test word1']

进一步的解释:https://www.ocpsoft.org/tutorials/regular-expressions/or-in-regex/

4

你的正则表达式里有两个组,看看你用了多少个括号就知道了 :)一个组是 ([a-z]+),另一个是 (1([a-z]+)2|[a-z])。关键是你可以在一个组里面再放一个组。所以,如果可以的话,你应该尽量写一个只有一个组的正则表达式,这样就不用在结果出来后再处理了。

一个只有一个组的正则表达式的例子是:

>>> import re
>>> s = 'ab1cd2efg1hij2k'
>>> re.findall('((?<=1)[a-z]+(?=2)|[a-z])', s)
['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']
8

我虽然晚了5年才来参加这个讨论,但我觉得我可能找到了一个优雅的解决办法,可以处理re.findall()输出中那些难看的包含多个元组的结果。

一般来说,如果你得到的输出看起来像这样:

[('pattern_1', '', ''), ('', 'pattern_2', ''), ('pattern_1', '', ''), ('', '', 'pattern_3')]

那么你可以用这个小技巧把它变成一个扁平的列表:

["".join(x) for x in re.findall(all_patterns, iterable)]

最终的输出会像这样:

['pattern_1', 'pattern_2', 'pattern_1', 'pattern_3']

这个方法是在Python 3.7上测试过的。希望对你有帮助!

8

你的模式有两个部分,较大的部分:

(1([a-z]+)2|[a-z])

还有第二个较小的部分,它是第一个部分的一个子集

([a-z]+)

这里有一个解决方案,可以让你得到想要的结果,不过要注意,这个方法真的很复杂,可能还有更好的办法。我就是想不出来:

import re
s = 'ab1cd2efg1hij2k'
a = re.findall( r'((?:1)([a-z]+)(?:2)|([a-z]))', s )
a = [tuple(j for j in i if j)[-1] for i in a]

>>> print a
['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']

撰写回答