2010-04-26 47 views
16

一个在Python(否则很强大)re模块的特殊怪癖是re.split()will never split a string on a zero-length match,例如,如果我想分割沿字边界的字符串:为什么Python的`re.split()`在零长度匹配上分裂?

>>> re.split(r"\s+|\b", "Split along words, preserve punctuation!") 
['Split', 'along', 'words,', 'preserve', 'punctuation!'] 

,而不是

['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!'] 

为什么它有这个限制?它是否由设计?其他正则表达式的风格是这样吗?

回答

22

这是一个设计决定,而且可能无论如何。蒂姆·彼得斯提出this post解释:

例如,如果你在模式X *拆分“ABC”,你有什么期待 ?该模式匹配(长度为0)4处, 但我敢打赌,大多数人会惊讶地获得

[ '', 'A', 'B', 'C', '']

背部,而不是(因为他们得到)

[ 'ABC']

有些人他虽然不同意。由于向后兼容性问题,Guido van Rossum doesn't want it changed。他没有say

我很好,添加一个标志来启用此行为。

编辑

有张贴由Jan Burgy一个workaround

>>> s = "Split along words, preserve punctuation!" 
>>> re.sub(r"\s+|\b", '\f', s).split('\f') 
['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!'] 

'\f'可以通过任何未使用的字符来代替。

+0

感谢您的链接和解决方法。我真的认为他们应该接受BDFL的建议并为此添加一个标志。 – 2010-04-26 12:25:58

+0

这是一个真正蹩脚的设计决定。 RE是一个设计决策不应该被人们“期望”驱动的事情,因为很多关于RE的事情都不符合人们的“期望”,无论如何这意味着什么。 'x *'应该与''abc'匹配,因为这就是RE所说的:“匹配x,零次或多次”。这就是你使用'*'时得到的结果。 – 2013-02-22 21:01:11

+0

当试图分割一个pascal大小写变量名('re.split('(?<= [a-z])(?= [A-Z])',name)')时,也碰到过这个问题。太糟糕了。 – Blixt 2015-05-05 14:53:59

0

基本上,split()是两个不同的函数合成一个。如果您提供参数,它的行为与没有参数时的行为非常不同。

起初,它会似乎

s.split() == s.split(' \t\n') 

但这种情况并非如此,因为你表现出来了。 的医生说:

[...] 如果不指定SEP是或无,任何空白字符串 是一个分离器和空字符串从结果中删除。 [...]

即使添加'remove_empty'参数,它仍会表现怪异,因为'remove_empty'的默认取决于'sep'参数的存在。

+0

我想你错了'.split()' - 我指的是're.split()',而不是字符串方法。 – 2010-04-30 16:29:05

+0

啊,当然:-) – 2010-04-30 17:42:43

1

要解决这个问题,你可以使用regex package这使得该VERSION1模式split()产生零长度匹配以及

>>> import regex as re 
>>> re.split(r"\s+|\b", "Split along words, preserve punctuation!", flags=re.V1) 
['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!']