如何使用re.sub替换python中基于模式字典的部分文本和替换值?

2024-06-16 14:56:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个用于文本替换的前缀列表。每当我用相应的值替换整个匹配文本时,我的程序都会工作,但如果我想保留部分匹配文本并使用分组替换其他部分,则程序不会工作:

prefixes = {
            r"http://www.w3.org/2002/07/owl#([a-z]+)": r"owl:\1",
            r"http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+)": r"rdf:\1",
            r"http://www.w3.org/2000/01/rdf-schema#([a-z]+)": r"rdfs:\1",
            r"http://schema.org/": "schema",
            r"http://www.w3.org/2001/XMLSchema#([a-z]+)": r"xsd:\1",
            r"http://purl.org/linked-data/sdmx#([a-z]+)": r"sdmx:\1",
            r"http://www.w3.org/XML/1998/namespace": r"xml"
            }
# test = "http://www.w3.org/XML/1998/namespace" # works for this
test = "http://www.w3.org/2000/01/rdf-schema#a" # Does not work!

regex = re.compile("|".join(map(re.escape, prefixes.keys())))

test = regex.sub(lambda match:prefixes[match.group(0)], test)

我想用“rdfs:a”来代替test,但它不是这样工作的。我应该如何更改代码以在这种情况下工作


Tags: orgtest文本程序httpschemawwwrdf
2条回答

有点框架挑战,但“为什么要为团队而烦恼”?任何正则表达式都不匹配行尾($),因此这里唯一的问题是确保#之后的所有内容都以单个a-z字符开头:

import re

prefixes = {
    r"http://www.w3.org/2002/07/owl#": r"owl:",
    r"http://www.w3.org/1999/02/22-rdf-syntax-ns#": r"rdf:",
    r"http://www.w3.org/2000/01/rdf-schema#": r"rdfs:",
    r"http://schema.org/": "schema",
    r"http://www.w3.org/2001/XMLSchema#": r"xsd:",
    r"http://purl.org/linked-data/sdmx#": r"sdmx:",
    r"http://www.w3.org/XML/1998/namespace": r"xml"
}
regex = re.compile("|".join(map(re.escape, prefixes.keys())))


test1 = "http://www.w3.org/XML/1998/namespace"
test2 = "http://www.w3.org/2000/01/rdf-schema#a"

assert regex.sub(lambda match:prefixes[match.group(0)], test1) == "xml"
assert regex.sub(lambda match:prefixes[match.group(0)], test2) == "rdfs:a"

你想做的事情非常复杂。实际上,正如另一个答案所建议的,您不需要使用组和反向引用来简单地用另一个字符串替换匹配的文本

但是,如果简单方法无法正确识别要替换的字符串以及组中的表达式对匹配很重要,那么下面的内容可以为您解决问题

>>> prefixes = {
...     1:  (r"http://www.w3.org/2002/07/owl#([a-z]+)", r"owl:\2"),
...     3:  (r"http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+)", r"rdf:\4"),
...     5:  (r"http://www.w3.org/2000/01/rdf-schema#([a-z]+)", r"rdfs:\6"),
...     7:  (r"http://schema.org/", "schema"),
...     8:  (r"http://www.w3.org/2001/XMLSchema#([a-z]+)", r"xsd:\9"),
...     10: (r"http://purl.org/linked-data/sdmx#([a-z]+)", r"sdmx:\11"),
...     12: (r"http://www.w3.org/XML/1998/namespace", r"xml")
...     }
...
>>> test_1 = "http://www.w3.org/XML/1998/namespace"
>>> test_2 = "http://www.w3.org/2000/01/rdf-schema#a"
>>>
>>> expr = '(' + ')|('.join(p[0] for p in prefixes.values()) + ')'
>>> 
>>> regex = re.compile(expr)
>>> 
>>> regex.findall(test_2)
[('', '', '', '', 'http://www.w3.org/2000/01/rdf-schema#a', 'a', '', '', 
  '', '', '', '')]

>>> regex.sub(lambda m: m.expand(prefixes[m.lastindex][1]), test_2)
'rdfs:a'

>>> regex.sub(lambda m: m.expand(prefixes[m.lastindex][1]), test_1)
'xml'

>>> 

那里

您以前所拥有的功能不起作用,因为匹配结果是动态确定的,并且与任何字典键都不匹配,因为字典键中包含目标文本所不具有的表达式

因此,问题是如何使一组表达式与一组替换字符串相关联,这些替换字符串中有对表达式中的组的反向引用

我所做的是利用match对象的组列表的结构来获取匹配表达式的索引。如果我使用括号将字典中的每个子表达式设为一个组,那么re.sub()会为每个匹配生成一个包含那么多组项的匹配对象(请参见带有regex.findall()的行-它显示了匹配组列表的结构)

匹配的子表达式在“匹配对象”列表中表示为括号中的子表达式位置处的非空字符串

>>> expr = '(' + ')|('.join(p[0] for p in prefixes.values()) + ')'
>>> expr
'(http://www.w3.org/2002/07/owl#([a-z]+))| 
 (http://www.w3.org/1999/02/22-rdf-syntax-ns#([a-z]+))| 
 (http://www.w3.org/2000/01/rdf-schema#([a-z]+))|
 (http://schema.org/)| 
 (http://www.w3.org/2001/XMLSchema#([a-z]+))|
 (http://purl.org/linked-data/sdmx#([a-z]+))|
 (http://www.w3.org/XML/1998/namespace)'

>>> regex.findall(test_2)
[('', '', '', '', 'http://www.w3.org/2000/01/rdf-schema#a', 'a', '', '', 
  '', '', '', '')]

因此,我修改了prefixes数据结构,使之成为一个字典,键入由m.lastindex返回的位置,这是匹配的括号子表达式的索引

需要调整背面参照以与匹配列表中的位置对齐。例如\1仅用于在结果中查找第一个匹配组

我使用的match对象的另一个特性是m.expand()方法,它将反向引用转换为它们引用的组

相关问题 更多 >