Python добавить несколько строк в другую строку с индексами один раз - PullRequest
1 голос
/ 18 апреля 2020

У меня есть длинный текст и некоторый список объектов dict, у которых есть индексы этого длинного текста. Я хочу добавить несколько строк в эти индексы. Если я установлю al oop, индексы изменятся, и я должен снова вычислить индексы. Я думаю, что этот способ очень сбивает с толку. Можно ли как-нибудь добавить разные строки в разные индексы за один раз?

Мои образцы данных:

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_str и indexes_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.'

Ответы [ 3 ]

1 голос
/ 18 апреля 2020

Создайте новую строку, чтобы избежать изменения 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 голос
/ 18 апреля 2020

Вот решение без каких-либо императивов 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.'

Кроме того, хотя вы сказали, что не хотите использовать циклы, важно отметить, что вам не нужно вносить какие-либо изменения в индекс, если вы это делаете. обновления в обратном порядке.

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.'
0 голосов
/ 18 апреля 2020

Не посещенные индексы вставки не изменятся, если вы выполните итерацию в обратном направлении. Это верно для всех таких проблем. Иногда он даже позволяет вам изменять последовательности во время итерации, если вы осторожны (не то, чтобы я когда-либо рекомендовал это).

Вы можете найти все точки вставки из 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)
...