【问题标题】:Replace named group in regex match替换正则表达式匹配中的命名组
【发布时间】:2016-02-11 13:56:31
【问题描述】:

我有以下正则表达式:

pattern = '^[a-zA-Z0-9-_]*_(?P<pos>[A-Z]\d\d)_T\d{4}(?P<fID>F\d{3})L\d{2}A\d{2}(?P<zID>Z\d{2})(?P<cID>C\d{2})\.tif$'

匹配如下文件名:

filename = '151006_655866_Z01_T0001F015L01A02Z01C03.tif'

与组:

m = re.match(pattern, filename)
print m.group("pos")  # Z01
print m.group("fID")  # F015
print m.group("zID")  # Z01

如何在 Python 中只用给定的字符串替换指定的组?

我尝试在函数调用中使用re.sub,但不知道这个函数应该是什么样子:

def replace_function(matchobj):
    # how to replace only a given match group?
    # (the following replaces *all* occurrences of "Z01" in this example)
    return matchobj.group(0).replace(matchobj.group("slice"), "---")

print re.sub(pattern, replace_function, filename)

我想要的结果是:

151006_655866_Z01_T0001F015L01A02---C03.tif

【问题讨论】:

  • re.sub 的 repl 参数(如果可调用)应采用单个匹配对象并返回一个字符串以替换原始匹配项。您的匹配项包含同一字符串的多个部分,因此并不适合这种用法 - 尝试仅捕获您要替换的部分。
  • @jonrsharpe 是的,我想到了,但我的想法是让模式可配置(即只需要包含几个命名组的输入),所以我希望有一种方法来替换该特定组,或至少检索其在目标字符串中的位置。但正如您所建议的,我想我需要解析模式以修改它以仅捕获所需的部分。
  • @JanEglinger 如果建议的解决方案按预期工作,请接受答案。如果不是,请解释原因或更好地提供失败的测试,我也会尝试修复代码。

标签: python regex replace


【解决方案1】:

您可以使用闭包和所选匹配组的开始/结束索引来做您需要的事情:

import re
from functools import partial

pattern = '^[\w-]*_(?P<pos>[A-Z]\d{2})_T\d{4}(?P<fID>F\d{3})L\d{2}A\d{2}(?P<zID>Z\d{2})(?P<cID>C\d{2})\.tif$'
filename = '151006_655866_Z01_T0001F015L01A02Z01C03.tif'


def replace_closure(subgroup, replacement, m):
    if m.group(subgroup) not in [None, '']:
        start = m.start(subgroup)
        end = m.end(subgroup)
        return m.group()[:start] + replacement + m.group()[end:]

subgroup_list = ['pos', 'fID', 'zID', 'cID']
replacement = '---'

for subgroup in subgroup_list:
    print re.sub(pattern, partial(replace_closure, subgroup, replacement), filename)

输出:

151006_655866_---_T0001F015L01A02Z01C03.tif
151006_655866_Z01_T0001---L01A02Z01C03.tif
151006_655866_Z01_T0001F015L01A02---C03.tif
151006_655866_Z01_T0001F015L01A02Z01---.tif

在线实现可用here

【讨论】:

  • 太棒了,这正是我所需要的。感谢您向我介绍functools.partial()
  • @JanEglinger 不客气!请注意,partial 的使用不是强制性的(您可以按照文档中的说明简单地定义一段等效的代码),但有助于保持代码更简洁。我还略微减少了正则表达式模式(主要是 [a-zA-Z0-9_] -&gt; \w,只是修饰而不是修复)
【解决方案2】:

要获得所需的输出,只需捕获要开始和结束的内容
保存。在它之间插入---。

查找^([a-zA-Z0-9_-]*_[A-Z]\d\d_T\d{4}F\d{3}L\d{2}A\d{2})Z\d{2}(C\d{2}\.tif)$
替换:$1---$2

【讨论】:

    猜你喜欢
    • 2015-09-08
    • 2012-05-16
    • 2016-02-11
    • 1970-01-01
    • 2012-11-23
    • 2022-08-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    相关资源
    最近更新 更多