替换字符串中多个重叠的子字符串

问题描述 投票:0回答:1

我的 HTML 文档中有一个字符串。

astring = "R=500 mm, φ=180°, Z=599 mm von TL Boden oben. Unterliegende Schale: Boden oben."

我想替换

astring
的子字符串来建立链接。为此,我有一个像

这样的字典列表
lst = [{'id': 'coordinate_systems', 'linktext': 'TL Boden oben'},
       {'id': 'PartID_1', 'linktext': 'Boden oben'}]

其中

linktext
字段是要在
astring
中找到的值。我想通过简单的替换来添加 href 标签,大致如下

astring.replace(linktext, '<a href="#{}">{}</a>'.format(_id, linktext))

通过迭代

lst
并在每行中进行替换。简单的实现是双循环,即根据
lst
的每个元素检查 HTML 文档的每一行并进行替换。

这会产生不正确的结果,例如首先替换子字符串“TL Boden oben”

'TL Boden oben' -> '<a href="#coordinate_systems">TL Boden oben</a>'

这是可以的,但是然后里面的“Boden oben”又被替换了

'Boden oben' -> '<a href="#coordinate_systems">TL <a href="#PartID_1">Boden oben</a></a>'

这已经不行了,我需要分别处理“TL Boden oben”和“Boden oben”:

"R=500 mm, φ=180°, Z=599 mm von <a href="#coordinate_systems">TL Boden oben</a>. Unterliegende Schale: <a href="#PartID_1">Boden oben</a>."

linktext
字段是用户定义的,所以是任意的。这些可能是不同的或重叠的,也就是说,我不能简单地以简单的方式进行替换,如前面所示。我没有先验知识如何
linktext
字段重叠。

我找到并实现了一种解决方案,用于检查

astring
是否包含多个
linktext
。如果是这样,它只是将
astring
拆分为句子,并在句子级别进行替换;这是可以的,因为重叠的链接文本不太可能出现在同一个句子中(参见上面的示例)。

但这不是我想要的强大解决方案。

如何解决这个问题?

编辑:

通过 @Nick 的 answer,外部循环被消除,并且通过正则表达式替换完成替换。保留内部循环,因为并非所有出现的链接都将被替换,例如id 标签不应链接到其自身。

不应发生替换的行包含子字符串“nolink”。我的策略是循环各行,如果 'nolink' 不是行中的子字符串,则进行替换,否则将 'nolink' 替换为 ''。

部分原始内容(使用jinja2生成),替换前:

'<table class="table w-auto table-hover table-sm">\n'
    '<thead>\n'
        '<tr>\n'
            '<th colspan="2" scope="col" id="PartID_1">Boden obennolink</th>\n'
        '</tr>\n'
    '</thead>\n'
    '<tbody>\n'
        '<tr>\n'
            '<td>Halbkugelbodennolink</td>\n'
            '<td>Position Z = 6000.0 mm. Bordhöhe 50.0 mm. Wanddicke s = 15 mm MW. Werkstoff 1.4541, Blech.</td>\n'
        '</tr>\n'
    '</tbody>\n'
'</table>\n'

'<table class="table w-auto table-hover table-sm">\n'
    '<thead>\n'
        '<tr>\n'
            '<th colspan="2" scope="col" id="PartID_14">N02nolink</th>\n'
        '</tr>\n'
    '</thead>\n'
    '<tbody>\n'
        '<tr>\n'
            '<td>Positionnolink</td>\n'
            '<td>R=500 mm, φ=180°, Z=599 mm von TL Boden oben. Unterliegende Schale: Boden oben. Ausrichtung: normal.</td>\n'
        '</tr>\n'
        '<tr>\n'
            '<td>Zargenolink</td>\n'
            '<td>168.3 mm x 5.60 mm NW (5.20 mm MW). Werkstoff 1.4571, Blech.</td>\n'
        '</tr>\n'
    '</tbody>\n'
'</table>\n'
python string replace
1个回答
1
投票

您可以同时使用正则表达式替换all链接模式来解决此问题,因为这不会替换之前替换的文本。关键是要确保

linktext
值按长度降序排序;这样
TL Boden oben
就不会被错误地替换为
Boden oben
的链接。为了简化替换,我们制作了从
linktext
到生成的链接文本的映射。例如:

astring = "R=500 mm, φ=180°, Z=599 mm von TL Boden oben. Unterliegende Schale: Boden oben."
lst = [{'id': 'coordinate_systems', 'linktext': 'TL Boden oben'},
       {'id': 'PartID_1', 'linktext': 'Boden oben'}]

links = { l['linktext'] : f'''<a href="#{l['id']}">{l['linktext']}</a>''' for l in lst }
# {
#   'TL Boden oben': '<a href="#coordinate_systems">TL Boden oben</a>',
#   'Boden oben': '<a href="#PartID_1">Boden oben</a>'
# }

pattern = re.compile('|'.join(sorted(links.keys(), key=len, reverse=True)))
# re.compile('TL Boden oben|Boden oben')

out = pattern.sub(lambda m:links[m[0]], astring)

输出:

'R=500 mm, φ=180°, Z=599 mm von <a href="#coordinate_systems">TL Boden oben</a>. Unterliegende Schale: <a href="#PartID_1">Boden oben</a>.'
© www.soinside.com 2019 - 2024. All rights reserved.