【问题标题】:How to loop over regex matches and do replacement, without using a separate replacement function?如何在不使用单独的替换函数的情况下循环正则表达式匹配并进行替换?
【发布时间】:2020-04-13 13:32:25
【问题描述】:

我需要替换每个模式,例如:{foo} 替换为 FOO + 一个不断增加的数字,并且还需要为每个匹配替换 do_something_else(...)。示例:

'hell{o} this {is} a t{est}' => hellO1 this IS2 a tEST3

如何不使用替换函数,而只使用匹配循环?我正在寻找类似的东西:

import re

def do_something_else(x, y):  # dummy function
    return None, None

def main(s):
    i = 0
    a, b = 0, 0
    for m in re.findall(r"{([^{}]+)}", s):  # loop over matches, can we
        i += 1                              # do the replacement DIRECTLY IN THIS LOOP?
        new = m.upper() + str(i)
        print(new)
        s = s.replace('{' + m + '}', new)    # BAD here because: 1) s.replace is not ok! bug if "m" is here mutliple times   
                                             #                   2) modifying s while looping on f(.., s) is probably not good
        a, b = do_something_else(a, b)
    return s

main('hell{o} this {is} a t{est}')    # hellO1 this IS2 a tEST3

下面的代码(with 一个替换函数)可以工作,但是这里使用全局变量是一个大问题,因为实际上do_something_else() 可能需要几毫秒,而且这个过程可能会混合与main() 的另一个并发运行:

import re

def replace(m):
    global i, a, b
    a, b = do_something_else(a, b)
    i += 1
    return m.group(1).upper() + str(i)

def main(s):
    global i, a, b
    i = 0
    a, b = 0, 0
    return re.sub(r"{([^{}]+)}", replace, s)

main('hell{o} this {is} a t{est}')

【问题讨论】:

  • 您要匹配的确切目标文本是什么,替换的内容是什么?
  • re.findall 用于提取匹配项,而不是修改它们。至于str.replace,它经常在循环中使用,仅替换第一次出现的s = s.replace('{' + m + '}', new, 1)
  • 字符串在 Python 中是不可变的。所以重新分配s 并不重要。 findall 仍在对原始字符串进行迭代。

标签: python regex python-re


【解决方案1】:

使用finditer。示例:

import re
s = 'hell{o} this {is} a t{est}'
counter = 1
newstring = ''
start = 0
for m in re.finditer(r"{([^{}]+)}", s):
    end, newstart = m.span()
    newstring += s[start:end]
    rep = m.group(1).upper() + str(counter)
    newstring += rep
    start = newstart
    counter += 1
newstring += s[start:]
print(newstring)  # hellO1 this IS2 a tEST3

【讨论】:

  • 谢谢!所以作为一个经验法则,findall 只给出一个字符串列表(匹配),而finditer 给出一个Match 对象的迭代器,它提供了更大的灵活性,对吗?
  • @Basj 基本上,是的。
  • 我从 iPython 控制台输出转换为标准 python,为了更容易重现,我希望你没问题@RolandSmith。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
  • 1970-01-01
  • 2011-01-27
相关资源
最近更新 更多