Python pptx (Power Point) Найти и заменить текст (Ctrl + H)
Короче вопрос: как я могу использовать опцию поиска и замены (Ctrl+H) с помощью модуля Python-pptx?
Пример кода:
from pptx import Presentation
nameOfFile = "NewPowerPoint.pptx" #Replace this with: path name on your computer + name of the new file.
def open_PowerPoint_Presentation(oldFileName, newFileName):
prs = Presentation(oldFileName)
prs.save(newFileName)
open_PowerPoint_Presentation('Template.pptx', nameOfFile)
У меня есть документ Power Point с именем "Template.pptx". С моей программой Python я добавляю несколько слайдов и помещаю в них несколько картинок. После того, как все изображения помещены в документ, он сохраняет их в качестве другой презентации Power Point.
Проблема в том, что в этом "Template.pptx" есть все старые номера недели, например "Неделя 20". Я хочу, чтобы Python нашел и заменил все эти словосочетания на "Неделя 25" (например).
8 ответов
Вам нужно будет посетить каждый слайд на каждой фигуре и искать совпадения, используя доступные текстовые функции. Это может быть не красиво, потому что PowerPoint имеет привычку разбивать на части, которые могут показаться странными. Он делает это для поддержки таких функций, как проверка орфографии и т. Д., Но его поведение там непредсказуемо.
Так что найти вхождения с такими вещами, как Shape.text, вероятно, будет легко. Замена их без потери форматирования шрифта может быть более сложной, в зависимости от конкретной ситуации.
Публикация кода из моего собственного проекта, потому что ни один из других ответов не смог попасть в цель со строками, которые имеют сложный текст с несколькими абзацами без потери форматирования:
prs = Presentation('blah.pptx')
# To get shapes in your slides
slides = [slide for slide in prs.slides]
shapes = []
for slide in slides:
for shape in slide.shapes:
shapes.append(shape)
def replace_text(self, replacements: dict, shapes: List):
"""Takes dict of {match: replacement, ... } and replaces all matches.
Currently not implemented for charts or graphics.
"""
for shape in shapes:
for match, replacement in replacements.items():
if shape.has_text_frame:
if (shape.text.find(match)) != -1:
text_frame = shape.text_frame
for paragraph in text_frame.paragraphs:
for run in paragraph.runs:
cur_text = run.text
new_text = cur_text.replace(str(match), str(replacement))
run.text = new_text
if shape.has_table:
for row in shape.table.rows:
for cell in row.cells:
if match in cell.text:
new_text = cell.text.replace(match, replacement)
cell.text = new_text
replace_text({'string to replace': 'replacement text'}, shapes)
Для тех из вас, кто просто хочет скопировать и вставить в свою программу код, который находит и заменяет текст в PowerPoint , СОХРАНЯЯ форматирование (как и я), вот и все:
def search_and_replace(search_str, repl_str, input, output):
""""search and replace text in PowerPoint while preserving formatting"""
#Useful Links ;)
#https://stackru.com/questions/37924808/python-pptx-power-point-find-and-replace-text-ctrl-h
#https://stackru.com/questions/45247042/how-to-keep-original-text-formatting-of-text-with-python-powerpoint
from pptx import Presentation
prs = Presentation(input)
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
if(shape.text.find(search_str))!=-1:
text_frame = shape.text_frame
cur_text = text_frame.paragraphs[0].runs[0].text
new_text = cur_text.replace(str(search_str), str(repl_str))
text_frame.paragraphs[0].runs[0].text = new_text
prs.save(output)
Prior - это комбинация многих ответов, но она выполняет свою работу. Он просто заменяетsearch_str
с участием repl_str
в каждом случае search_str
.
В рамках этого ответа вы должны использовать:search_and_replace('Week 20', 'Week 25', "Template.pptx", "NewPowerPoint.pptx")
Слияние приведенных выше и других ответов таким образом, что у меня хорошо сработало (PYTHON 3). Был сохранен весь исходный формат:
from pptx import Presentation
def replace_text(replacements, shapes):
"""Takes dict of {match: replacement, ... } and replaces all matches.
Currently not implemented for charts or graphics.
"""
for shape in shapes:
for match, replacement in replacements.items():
if shape.has_text_frame:
if (shape.text.find(match)) != -1:
text_frame = shape.text_frame
for paragraph in text_frame.paragraphs:
whole_text = "".join(run.text for run in paragraph.runs)
whole_text = whole_text.replace(str(match), str(replacement))
for idx, run in enumerate(paragraph.runs):
if idx != 0:
p = paragraph._p
p.remove(run._r)
if(not(not paragraph.runs)):
paragraph.runs[0].text = whole_text
if __name__ == '__main__':
prs = Presentation('input.pptx')
# To get shapes in your slides
slides = [slide for slide in prs.slides]
shapes = []
for slide in slides:
for shape in slide.shapes:
shapes.append(shape)
replaces = {
'{{var1}}': 'text 1',
'{{var2}}': 'text 2',
'{{var3}}': 'text 3'
}
replace_text(replaces, shapes)
prs.save('output.pptx')
Я знаю, что этот вопрос старый, но я только что закончил проект, который использует python для ежедневного обновления PowerPoint. По сути, каждое утро запускается скрипт python, который извлекает данные за этот день из базы данных, помещает данные в powerpoint, а затем запускает просмотрщик powerpoint для воспроизведения powerpoint.
Чтобы ответить на ваш вопрос, вам придется пройтись по всем Shapes на странице и проверить, находится ли искомая строка в shape.text. Вы можете проверить, есть ли у формы текст, проверив, имеет ли значение shape.has_text_frame значение true. Это позволяет избежать ошибок.
Вот где все становится хитрее. Если вы просто замените строку в shape.text текстом, который хотите вставить, вы, вероятно, потеряете форматирование. shape.text - это конкатенация всего текста в форме. Этот текст может быть разбит на множество "прогонов", и все эти прогоны могут иметь различное форматирование, которое будет потеряно, если вы запишете поверх shape.text или замените часть строки.
На слайде у вас есть фигуры, и у фигур может быть text_frame, а у text_frames есть параграфы (по крайней мере, один. Всегда. Даже если он пуст), а у параграфов могут быть прогоны. Любой уровень может иметь форматирование, и вы не можете определить, сколько прогонов разбита на вашу строку.
В моем случае я позаботился о том, чтобы любая строка, которая должна была быть заменена, имела свою собственную форму. Вам все еще нужно детализировать все до самого прогона и установить там текст, чтобы все форматирование было сохранено. Кроме того, строка, которой вы соответствуете в shape.text, на самом деле может быть распределена по нескольким прогонам, поэтому при установке текста в первом прогоне я также установил пустой текст во всех других прогонах в этом абзаце.
фрагмент кода:
from pptx import Presentation
testString = '{{thingToReplace}}'
replaceString = 'this will be inserted'
ppt = Presentation('somepptxfile.pptx')
def replaceText(shape, string,replaceString):
#this is the hard part
#you know the string is in there, but it may be across many runs
for slide in ppt.slides:
for shape in slide.shapes:
if shape.has_text_frame:
if(shape.text.find(testString)!=-1:
replaceText(shape,testString,replaceString)
Извините, если есть какие-либо опечатки. Я на работе.....
Я столкнулся с аналогичной проблемой, когда форматированный заполнитель распространяется на объект с несколькими запусками. Я хотел бы сохранить формат, чтобы я не мог произвести замену на уровне абзаца. Наконец, я нашел способ заменить заполнитель.
variable_pattern = re.compile("{{(\w+)}}")
def process_shape_with_text(shape, variable_pattern):
if not shape.has_text_frame:
return
whole_paragraph = shape.text
matches = variable_pattern.findall(whole_paragraph)
if len(matches) == 0:
return
is_found = False
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
matches = variable_pattern.findall(run.text)
if len(matches) == 0:
continue
replace_variable_with(run, data, matches)
is_found = True
if not is_found:
print("Not found the matched variables in the run segment but in the paragraph, target -> %s" % whole_paragraph)
matches = variable_pattern.finditer(whole_paragraph)
space_prefix = re.match("^\s+", whole_paragraph)
match_container = [x for x in matches];
need_modification = {}
for i in range(len(match_container)):
m = match_container[i]
path_recorder = space_prefix.group(0)
(start_0, end_0) = m.span(0)
(start_1, end_1) = m.span(1)
if (i + 1) > len(match_container) - 1 :
right = end_0 + 1
else:
right = match_container[i + 1].start(0)
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
segment = run.text
path_recorder += segment
if len(path_recorder) >= start_0 + 1 and len(path_recorder) <= right:
print("find it")
if len(path_recorder) <= start_1:
need_modification[run] = run.text.replace('{', '')
elif len(path_recorder) <= end_1:
need_modification[run] = data[m.group(1)]
elif len(path_recorder) <= right:
need_modification[run] = run.text.replace('}', '')
else:
None
if len(need_modification) > 0:
for key, value in need_modification.items():
key.text = value
Поскольку PowerPoint разбивает текст абзаца на, казалось бы, случайные прогоны (а сверху каждый прогон несет свое — возможно, различное — форматирование символов), вы не можете просто искать текст в каждом прогоне, потому что текст на самом деле может быть распределен по паре прогонов, и в каждом из них вы найдете только часть текста, который ищете.
Выполнение этого на уровне абзаца возможно, но вы потеряете все форматирование символов этого абзаца, что может немного испортить вашу презентацию.
Использование текста на уровне абзаца, выполнение замены и присвоение этого результата первому прогону абзаца при удалении других прогонов из абзаца лучше, но это изменит форматирование символов всех прогонов на форматирование первого, снова закручивая места, где не должно.
Поэтому я написал достаточно полный скрипт, который можно установить с помощью
python -m pip install python-pptx-text-replacer
и это создает командуpython-pptx-text-replacer
который вы можете использовать для выполнения этих замен из командной строки, или вы можете использовать класс TextReplacer в этом пакете в своих собственных сценариях Python. Он может изменять текст в таблицах, диаграммах и везде, где может появиться какой-либо текст, сохраняя при этом любое форматирование символов, указанное для этого текста.
Прочтите README.md по адресу https://github.com/fschaeck/python-pptx-text-replacer для получения более подробной информации об использовании. И открывайте там вопрос, если у вас возникли проблемы с кодом!
Также см. мой ответ на python-pptx — Как заменить ключевое слово при нескольких запусках?для примера того, как скрипт работает с форматированием символов...
Вот код, который может помочь. Я нашел это здесь:
search_str = '{{{old text}}}'
repl_str = 'changed Text'
ppt = Presentation('Presentation1.pptx')
for slide in ppt.slides:
for shape in slide.shapes:
if shape.has_text_frame:
shape.text = shape.text.replace(search_str, repl_str)
ppt.save('Presentation1.pptx')