【问题标题】:Python pptx (Power Point) Find and replace text (ctrl + H)Python pptx (Power Point) 查找和替换文本 (ctrl + H)
【发布时间】:2016-10-21 20:15:29
【问题描述】:

简短问题:如何使用 Python-pptx 模块使用查找和替换选项 (Ctrl+H)?

示例代码:

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)

我有一个名为“Template.pptx”的 Power Point 文档。使用我的 Python 程序,我正在添加一些幻灯片并在其中放入一些图片。将所有图片放入文档后,它会将其保存为另一个 power point 演示文稿。

问题是这个“Template.pptx”包含所有旧的周数,比如“第 20 周”。我想让 Python 查找所有这些单词组合并将其替换为“第 25 周”(例如)。

【问题讨论】:

    标签: python python-2.7 powerpoint python-pptx


    【解决方案1】:

    您必须访问每个形状上的每张幻灯片,并使用可用的文本功能查找匹配项。它可能不漂亮,因为 PowerPoint 习惯于将运行分成看起来很奇怪的块。它这样做是为了支持拼写检查等功能,但它的行为是不可预测的。

    因此,使用 Shape.text 之类的内容查找出现可能会很容易。在不丢失任何字体格式的情况下替换它们可能会更困难,具体取决于您的具体情况。

    【讨论】:

    • 那么在使用 Python 的 Power Point 演示文稿中没有像样的/简单的方法来模拟查找和替换功能吗?即使没有其他模块?
    • @Morganis - 您可以使用 IronPython 在 Windows 下使用 Microsoft API(类似于 VBA)来操作 PowerPoint 演示文稿。这只能在客户端(而不是在服务器上)工作,并且可能有点慢(它在我的机器上,但我在 VM 中运行 Windows)。但这比手工操作要快得多。我不知道有任何其他 Python 库可以提供对 PowerPoint 文件的详细编辑,尽管我已经有一段时间没有环顾四周了。我是python-pptx btw的作者。
    【解决方案2】:

    我知道这个问题很老了,但我刚刚完成了一个使用 python 每天更新 powerpoint 的项目。基本上每天早上都会运行 python 脚本,它会从数据库中提取当天的数据,将数据放在 powerpoint 中,然后执行 powerpoint viewer 来播放 powerpoint。

    要回答您的问题,您必须遍历页面上的所有形状并检查您要搜索的字符串是否在 shape.text 中。您可以通过检查 shape.has_text_frame 是否为真来检查形状是否有文本。这样可以避免错误。

    这就是事情变得棘手的地方。如果您只是将 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)
    

    如有错别字,请见谅。我在工作.....

    【讨论】:

    • 这个答案如果包含 replaceText 函数的代码会更有帮助。
    • 最初我没有输入replaceText函数的代码,因为我还没有完成它。我同意如果包含该功能,我的答案会更完整。我将用代码更新我的答案。它并不完美,但它确实有效。
    【解决方案3】:

    这里有一些可以提供帮助的代码。 I found it here:

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

    【讨论】:

      【解决方案4】:

      对于那些只想将一些代码复制并粘贴到程序中同时保持格式化(就像我一样)在 PowerPoint 中查找和替换文本的人,你可以这样做:

      def search_and_replace(search_str, repl_str, input, output):
          """"search and replace text in PowerPoint while preserving formatting"""
          #Useful Links ;)
          #https://stackoverflow.com/questions/37924808/python-pptx-power-point-find-and-replace-text-ctrl-h
          #https://stackoverflow.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)
      

      先验是许多答案的组合,但它可以完成工作。它只是在每次出现search_str 时将search_str 替换为repl_str。

      在此答案的范围内,您将使用: search_and_replace('Week 20', 'Week 25', "Template.pptx", "NewPowerPoint.pptx")

      【讨论】:

      • 这几乎就在那里,并且绝对指向正确的方向。但是,文本可以有多个段落并运行。我已经发布了一个适用于诸如此类的更复杂文本的答案。
      • 我知道已经两年了,但使用 Sam Redway 的答案,会更好。
      【解决方案5】:

      从我自己的项目中发布代码,因为其他答案都没有完全成功地使用具有多个段落的复杂文本的字符串而不丢失格式:

      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) 
      

      【讨论】:

      • 非常感谢,这么好的解决方案。
      【解决方案6】:

      以适合我的方式合并上述和其他响应(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')
      

      【讨论】:

      • 这太棒了!正是我一次完成多个文本替换所需要的
      【解决方案7】:

      我遇到了一个类似的问题,即格式化的占位符分布在​​多个运行对象上。我想保留格式,所以我无法在段落级别进行替换。最后,我想出了一个替换占位符的方法。

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-20
        • 1970-01-01
        • 2022-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-30
        • 1970-01-01
        相关资源
        最近更新 更多