Python将多个字符串添加到另一个具有单个索引的字符串中

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

我有一个长文本,还有一些dict对象的列表,这些对象具有此长文本的索引。我想向这些索引添加一些字符串。如果设置循环,索引会更改,并且必须再次计算索引。我认为这种方式非常令人困惑。有没有办法一次将不同的字符串添加到不同的索引?

我的样本数据:

main_str = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.'

我的indexes列表:

indexes_list = [
    {
      "type": "first_type",
      "endOffset": 5,
      "startOffset": 0,
    },
    {
      "type": "second_type",
      "endOffset": 22,
      "startOffset": 16,
    }
]

我的主要目的:我想为基于类型的某些颜色样式的给定索引添加<span>属性。之后,我直接在模板上渲染它。还有其他建议吗?

例如,我想根据上述变量main_strindexes_list创建此数据(请忽略样式的color部分。我根据type中的indexes_list的值动态提供它):

new_str = '<span style="color:#FFFFFF">Lorem</span> Ipsum is <span style="color:#FFFFFF">simply</span> dummy text of the printing and typesetting industry.'
python python-3.x string dictionary string-parsing
3个回答
1
投票

创建一个新的str以避免更改main_str:

main_str = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.'
indexes_list = [
    {
      "type": "first_type",
      "startOffset": 0,
      "endOffset": 5,
    },
    {
      "type": "second_type",
      "startOffset": 16,
      "endOffset": 22,
    }
]

new_str = ""
index = 0
for i in indexes_list:
    start = i["startOffset"]
    end = i["endOffset"]
    new_str += main_str[index: start] + "<span>" + main_str[start:end] + "</span>"
    index = end
new_str += main_str[index:]
print(new_str)

1
投票

这里是没有任何imperative for loops的解决方案。对于列表推导,它仍然使用大量循环。

for

此外,尽管您说过不希望循环,但要注意,如果以相反的顺序进行更新,则不必进行任何索引修改。

# Get all the indices and label them as starts or ends.
starts = [(o['startOffset'], True) for o in indexes_list]
ends = [(o['endOffset'], False) for o in indexes_list]

# Sort everything...
all_indices = sorted(starts + ends)

# ...so it is possible zip together adjacent pairs and extract substrings.
pieces = [
    (s[1], main_str[s[0]:e[0]])
    for s, e in zip(all_indices, all_indices[1:])
]

# And then join all the pieces together with a bit of conditional formatting.
formatted = ''.join([
    f"<span>{part}</span>" if is_start else part
    for is_start, part in pieces
])

formatted
# '<span>Lorem</span> Ipsum is s<span>imply </span>dummy text of the printing and typesetting industry.'

-1
投票

如果您向后迭代,则未访问的插入索引不会更改。对于所有此类问题都是如此。如果您谨慎的话,有时它甚至可以让您在迭代过程中修改序列(不是我所推荐的)。

您可以从字典中找到所有插入点,将它们向后排序,然后进行插入。例如:

def update_str(s, spans): 
    for lookup in sorted(spans, reverse=True, key=lambda o: o['startOffset']): 
        start = lookup['startOffset'] 
        end = lookup['endOffset'] 
        before, span, after = s[:start], s[start:end], s[end:] 
        s = f'{before}<span>{span}</span>{after}' 
    return s 

update_str(main_str, indexes_list)                                                                                                                                                                                                   
# '<span>Lorem</span> Ipsum is s<span>imply </span>dummy text of the printing and typesetting industry.'

不这样做的原因是效率低下。对于合理大小的文本来说,这不是一个大问题,但是请记住,您正在砍伐,并在每一步中重新分配越来越多的字符串。

一种更有效的方法是在所有插入点处将整个字符串切碎一次。用适当的方式在适当的位置将列表元素添加到适当的位置会便宜得多,而且您只需重新加入整个内容一次:

items = ['<span ...>', '</span>']
keys = ['startOffset', 'endOffset']
insertion_points = [(d[key], item) for d in indexes_list for key, item in zip(keys, items)]
insertion_points.sort(reverse=True)

for index, content in insertion_points:
    main_str = main_str[:index] + content + main_str[index:]
© www.soinside.com 2019 - 2024. All rights reserved.