当我的模式只包含一个组时,为什么re.findall会返回元组列表?

时间:2014-07-06 07:57:26

标签: python regex findall

假设我的字符串s包含字母和两个分隔符12。我想以下列方式拆分字符串:

  • 如果子字符串t介于12之间,请返回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 ) ]得到答案,但我仍然不理解输出。 documentation表示如果模式包含多个组,findall将返回元组列表。但是,我的模式只包含一个组。欢迎任何解释。

6 个答案:

答案 0 :(得分:5)

你的模式有两组,更大的组:

(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']

答案 1 :(得分:1)

你的正则表达式有两组,只看你正在使用的括号数:)。一组为([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']

答案 2 :(得分:1)

如果您想在不将其分成匹配组的情况下进行“或”匹配,只需在“或”匹配的开头添加“?:”。

没有'?:'

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/

答案 3 :(得分:0)

查看类似问题的答案:https://bugs.python.org/issue6663 如果您使用的是findall,请删除括号:

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

答案 4 :(得分:0)

我参加聚会已经晚了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上进行了测试。希望对您有帮助!

答案 5 :(得分:0)

只需要做一个简单的更改:将组更改为非捕获组

代码:

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

输出:

['a', 'b', '1cd2', 'e', 'f', 'g', '1hij2', 'k']