为什么Python的`re.split()`不在零长度匹配处分割?

16 投票
4 回答
2771 浏览
提问于 2025-04-15 22:01

Python中的re模块虽然功能强大,但有一个特别的地方就是re.split()这个函数在遇到零长度匹配时不会分割字符串。举个例子,如果我想在单词的边界上分割一个字符串:

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

而不是

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

为什么会有这样的限制呢?这是故意设计成这样的吗?其他的正则表达式工具也是这样吗?

4 个回答

1

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

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

为了绕过这个问题,你可以使用regexVERSION1模式,这样split()就会产生零长度的匹配

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

这是一个设计上的决定,可以有不同的选择。Tim Peters 发了 这篇帖子 来解释:

比如说,如果你用模式 x* 来拆分 "abc",你期待得到什么结果?这个模式在 4 个地方匹配(长度为 0),但我敢打赌大多数人会对得到

['', 'a', 'b', 'c', '']

感到惊讶,而不是(他们实际上得到的)

['abc']

不过,也有一些人不同意他的看法。Guido van Rossum 不想改变这个,因为这会影响到之前的兼容性。他确实 说过

我可以接受添加一个标志来启用这种行为。

编辑

Jan Burgy 提供了一个 解决方法

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

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

撰写回答