【问题标题】:Why doesn't Python's `re.split()` split on zero-length matches?为什么 Python 的 `re.split()` 不会在零长度匹配上拆分?
【发布时间】:2010-04-26 11:34:24
【问题描述】:

Python 中 re 模块的一个特殊怪癖(否则非常强大)是 re.split() will never split a string on a zero-length match,例如,如果我想沿单词边界拆分字符串:

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

而不是

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

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

【问题讨论】:

  • re-module 从 3.7 开始支持零长度匹配。

标签: python regex


【解决方案1】:

这是一个设计决定,可以采取任何一种方式。 Tim Peters 发this post 解释:

例如,如果你用 x* 模式分割“abc”,你会怎么做? 预计?模式在 4 个位置匹配(长度为 0), 但我敢打赌大多数人会惊讶地得到

['', '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' 可以替换为任何未使用的字符。

【讨论】:

  • 感谢您的链接和解决方法。我真的认为他们应该接受 BDFL 的建议并为此添加一个标志。
  • 这真是一个蹩脚的设计决定。 RE 是一个设计决策不应该由人们“期望”驱动的东西,因为关于 RE 的许多事情都不符合人们的“期望”,不管这意味着什么。 x* 应该匹配 'abc' 因为这就是 RE 所说的:“匹配一个 x,零次或多次”。这就是您使用 * 时得到的结果。
  • 在尝试拆分帕斯卡大小写变量名称 (re.split('(?<=[a-z])(?=[A-Z])', name)) 时也遇到了这个问题。太糟糕了。
【解决方案2】:

要解决此问题,您可以使用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', '!']

【讨论】:

    【解决方案3】:

    Python 从 3.7 开始支持此功能:

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

    【讨论】:

      【解决方案4】:

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

      一开始好像是这样的

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

      但事实并非如此,正如您所展示的那样。 医生说:

      [...] 如果 sep 未指定或为无,则任何空白字符串 是一个分隔符,并从结果中删除空字符串。 [...]

      即使添加 'remove_empty' 参数,它的行为仍然很奇怪,因为 'remove_empty' 的默认值取决于存在的 'sep' 参数。

      【讨论】:

      • 我认为你搞错了.split() - 我指的是re.split(),而不是字符串方法。
      猜你喜欢
      • 1970-01-01
      • 2014-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-15
      • 1970-01-01
      • 2018-03-11
      相关资源
      最近更新 更多