【问题标题】:Python add multiple strings to another string with indexes single timePython一次将多个字符串添加到另一个具有索引的字符串
【发布时间】:2020-07-31 13:38:35
【问题描述】:

我有一个长文本,以及一些 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


    【解决方案1】:

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

    # 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.'
    

    另外,虽然您说您不想要 for 循环,但请务必注意,如果您以相反的顺序进行更新,则无需进行任何索引修改。

    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.'
    

    【讨论】:

    • 感谢您的注释和回答,我更新了索引。实际上我需要一个新字符串,它将新字符串添加到相关索引中。我不需要听写对象。
    • 您能否提供您期望的示例数据输出?
    • 我已经添加了我想要输出的数据。
    • 好的,我已经为你实现了这个,没有任何循环。或者至少,没有任何程序 for 循环。所有列表推导在技术上仍然是循环。
    【解决方案2】:

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

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

    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:]
    

    不这样做的原因是效率低下。对于大小合理的文本,这不是一个大问题,但请记住,每一步都在切分并重新分配不断增加的字符串。

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

    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()
    
    last = 0
    chopped_str = []
    for index, content in insertion_points:
        chopped_str.append(main_str[last:index])
        chopped_str.append(content)
        last = index
    chopped_str.append[main_str[last:]]
    main_str = ''.join(chopped_str)
    

    【讨论】:

      【解决方案3】:

      创建一个新的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)
      

      【讨论】:

      • 您的解决方案工作正常。谢谢你的回答。实际上我搜索是否可以单次而不是循环。
      猜你喜欢
      • 2017-01-20
      • 2020-04-13
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-19
      • 1970-01-01
      相关资源
      最近更新 更多