在正则表达式匹配中替换命名组

6

我有以下正则表达式:

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

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

6
你可以使用闭包和所选匹配组的起始/结束索引来完成所需操作:
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

这里提供一个在线实现,链接:http://ideone.com/hmPZMW


1
太棒了,这正是我所需要的。感谢您向我介绍functools.partial() - Jan Eglinger
2
@JanEglinger 不用谢!请注意,使用 partial 不是必须的(您可以根据文档中所述简单地定义一个等效的代码片段),但有助于保持代码的清洁。我还略微减少了正则表达式模式(主要是 [a-zA-Z0-9_] -> \w,只是外观上的改变而不是修复)。 - Giuseppe Ricupero

3

要获得所需的输出,只需捕获要保留的开始和结束部分。在其间插入---

查找^([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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接