regex 为什么Python的`re.split()`不对零长度匹配进行拆分?

voj3qocg  于 2023-06-07  发布在  Python
关注(0)|答案(4)|浏览(186)

Python中的re模块(在其他方面非常强大)的一个特殊之处是,re.split()永远不会在零长度匹配时拆分字符串,例如,如果我想沿着单词边界拆分字符串:

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

而不是

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

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

bq3bfh9z

bq3bfh9z1#

这是一个已经做出的设计决定,而且可能会出现任何一种情况。Tim Peters写了这篇文章来解释:
例如,如果你用模式x* 分割“abc”,你会期望什么?模式匹配(长度为)在4个地方,但我敢打赌,大多数人会感到惊讶,得到
['','a',' b','c','']
而不是(因为他们得到)
['abc']
然而,其他一些人不同意他的观点。Guido货车Rossum不希望由于向后兼容性问题而对其进行更改。他确实说过:
不过,我可以添加一个标志来启用此行为。

编辑

Jan Burgy发布了一个解决方法:

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

其中'\f'可以由任何未使用的字符替换。

dhxwm5r4

dhxwm5r42#

为了解决这个问题,你可以使用regex packageVERSION1模式,这使得split() * 也产生零长度匹配 *:

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

e5nszbig3#

Python从3.7开始支持这种模式,但仅限于固定宽度的模式。

>>> s = "You! Are you Tom? I am Danny."
>>> re.split(r'(?<=[.!\?])', s)
['You!', ' Are you Tom?', ' I am Danny.', '']
bmvo0sr5

bmvo0sr54#

基本上,split()是两个不同的函数合二为一。如果您提供了参数,它的行为与在没有参数的情况下调用时非常不同。
一开始,似乎

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

但事实并非如此,正如你所展示的。医生说:
[...]如果未指定sep或sep为None,则任何空白字符串都是分隔符,并从结果中删除空字符串。[...]
即使添加一个'remove_empty'参数,它仍然会表现得很奇怪,因为'remove_empty'的默认值取决于'sep'参数的存在。

相关问题