Сохранить текстовый формат при чтении / записи для формирования текста python pptx - PullRequest
1 голос
/ 30 января 2020

Я хочу выполнить замену текста в тексте фигуры. Я использую код, подобный приведенному ниже фрагменту кода:

# define key/value
SRKeys, SRVals = ['x','y','z'], [1,2,3]

# define text
text = shape.text

# iterate through values and perform subs
for i in range(len(SRKeys)):
    # replace text
    text = text.replace(SRKeys[i], str(SRVals[i]))

# write text subs to comment box
shape.text = text

Однако, если начальные символы shape.text имеют отформатированные символы (например, жирным шрифтом), форматирование удаляется при чтении. Есть ли решение для этого?

Единственное, о чем я мог подумать, - это перебирать символы и проверять форматирование, а затем добавлять эти форматы перед записью в shape.text.

Ответы [ 2 ]

2 голосов
/ 01 февраля 2020

@ usr2564301 находится на правильном пути. Форматирование символов (aka. «Шрифт») указывается на уровне выполнения. Вот что такое бег; "последовательность" (последовательность) символов, все с одинаковым форматированием символов.

Когда вы назначаете shape.text, вы заменяете все серии, которые были там, одним новым циклом, имеющим форматирование по умолчанию. Если вы хотите сохранить форматирование, вам нужно сохранить все те прогоны, которые непосредственно не участвуют в замене текста.

Это не тривиальная проблема, потому что нет гарантийных разрывов прогонов на границах слов. Попробуйте распечатать прогоны для нескольких абзацев, и я думаю, вы поймете, что я имею в виду.

В грубом псевдокоде, я думаю, что такой подход вам потребуется:

  • выполните поиск целевого текста в абзаце, чтобы определить смещение его первого символа.
  • проследите все серии в абзаце, сохранив промежуточную сумму количества символов перед каждым циклом, возможно, что-то вроде (run_idx, prefix_len, length): (0, 0, 8), (1, 8, 4), (2, 12, 9) и др. c.
  • Определите, какой прогон является стартовым, конечные и промежуточные запуски, включающие строку поиска.
  • Разделить первый прогон в начале поискового термина, разделить последний прогон в конце поискового термина и удалить все, кроме первого из "средние" прогоны.
  • Измените текст промежуточного прогона на текст замены и клонируйте форматирование из предыдущего (оригинального запуска) прогона. Может быть, это последний бит, который вы делаете во время начала разделения.

Это сохраняет все запуски, которые не включают строку поиска, и сохраняет форматирование "совпадающего" слова в слове "заменено".

Для этого требуется несколько операций, которые напрямую не поддерживаются текущим API. Для тех, кому нужно использовать низкоуровневые вызовы lxml, чтобы напрямую манипулировать XML, хотя вы можете получить все существующие элементы, которые вам нужны, от python-pptx объектов без необходимости разбора в XML сами.

0 голосов
/ 01 апреля 2020

Вот адаптированная версия кода, который я использую (вдохновленный ответом @ scanny). Он заменяет текст для всех фигур (с текстовой рамкой) на слайде.

from pptx import Presentation

prs = Presentation('../../test.pptx')
slide = prs.slides[1]

# iterate through all shapes on slide
for shape in slide.shapes:
    if not shape.has_text_frame:
        continue

    # iterate through paragarphs in shape
    for p in shape.text_frame.paragraphs:
        # store formats and their runs by index (not dict because of duplicate runs)
        formats, newRuns = [], []

        # iterate through runs
        for _, r in enumerate(p.runs):
            # get text
            text = r.text

            # replace text
            text = text.replace('s','xyz')

            # store run
            newRuns.append(text)

            # store format
            formats.append({'size':r.font.size,
                            'bold':r.font.bold,
                            'underline':r.font.underline,
                            'italic':r.font.italic})

        # clear paragraph
        p.clear()

        # iterate through new runs and formats and write to paragraph
        for i in range(len(newRuns)):
            # add run with text
            run = p.add_run()
            run.text = newRuns[i]

            # format run
            run.font.bold = formats[i]['bold']
            run.font.italic = formats[i]['italic']
            run.font.size = formats[i]['size']
            run.font.underline = formats[i]['underline']

prs.save('../../test.pptx')
...