为什么Python的`re.split()`不在零长度匹配处分割?
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
为了绕过这个问题,你可以使用regex
包的VERSION1
模式,这样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'
可以用任何未使用的字符替代。