【问题标题】:re.sub() with replacement function that has side effectsre.sub() 具有副作用的替换函数
【发布时间】:2019-09-10 17:40:45
【问题描述】:

今天我遇到了以下构造:

import re
l = list('1234')
print(re.sub('.', lambda _: l.pop(0), 'abcd'))

基本上,它使用sub 和具有副作用的repl 函数。

抛开有争议的风格问题不谈,这个定义是否明确?

例如,我在文档中找不到任何地方可以保证repl 会在匹配项上被调用以任何特定顺序(实际上也没有恰好一次,尽管官方措辞在某种程度上可以解释)。此代码是否存在任何其他问题(实际问题或潜在问题)?

【问题讨论】:

  • AFAICT,你是对的,而且这个库函数的行为定义不够明确,无法保证相关代码的安全。
  • repl 在找到模式时被调用,据我所知,正则表达式从左到右进行匹配,所以我看不出有任何理由随机调用 repl,在 Docs 上似乎也差不多 re.sub
  • @CodeManiac:一方面,我们可以很容易地想象出一个并行匹配的正则表达式引擎。 (ieeexplore.ieee.org/document/7023656)
  • @NPE 哦,以前不知道,不过谢谢你的链接 :)
  • AFAIK 现实世界中没有可以开始并行匹配的正则表达式引擎,更不用说仅通过使用几个特定模块来利用并行编程的 Python。此外,如果您阅读链接到的那篇论文,所提出的算法接受非常有限的正则表达式子集,这不允许几乎任何现有的正则表达式引擎在其实现中以某种方式考虑它。因此 CodeManiac 的评论适用。

标签: python regex replace side-effects


【解决方案1】:

根据re.subdocumentation

返回替换最左端不重叠得到的字符串 在string 中出现pattern 被替换为repl

和:

如果repl 是一个函数,它会为每个不重叠的函数调用 模式的出现。

因此很明显re.sub 从左到右搜索并将给定pattern 的每次出现替换为repl 函数的返回值。所以是的,你的代码的行为是明确定义的。但是,它效率不高,因为您正在迭代地弹出列表的第一项,每次迭代需要 O(n) 的时间复杂度。您可以改为使用迭代器在 O(1) 时间内实现相同的副作用:

import re
i = iter('1234')
print(re.sub('.', lambda _: next(i), 'abcd'))

这也输出:

1234

【讨论】:

  • FWIW,我在引用中阅读“最左边”的方式是解决选择不重叠匹配项的歧义,而不是强制要求调用 repl 的任何特定顺序(尽管它当然,很可能被称为从左到右)。
  • 好点。现在我重读了这一段,我认为你是对的,“最左边”这个词只用来描述“不重叠”。那么认为这是一个非答案。我将把它留在这里,仅用于您问题的第二部分(此代码是否还有其他问题,实际的还是潜在的?)。
猜你喜欢
  • 2018-01-06
  • 2017-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 2016-10-13
相关资源
最近更新 更多