ppt文档中批量文本替换

查看 79|回复 9
作者:top7777   
实现了对ppt和pptx文档中指定文本的批量替换,需要安装python-pptx库,需要提前准备好替换文本的规则文件,其格式类似:旧文本=新文本,可以多行。
[Python] 纯文本查看 复制代码import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from pptx import Presentation
from pptx.text.text import _Run
import os
import re
import win32com.client
import pythoncom
import win32gui
import win32con
class PPTTextReplacer:
    def __init__(self, root):
        self.root = root
        self.root.title("PPT文本替换工具")
        self.root.geometry("600x500")  # 调整窗口大小
        
        # 配置网格权重
        self.root.grid_rowconfigure(0, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="5")
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置主框架的网格权重
        self.main_frame.grid_rowconfigure(4, weight=1)
        self.main_frame.grid_columnconfigure(1, weight=1)
        
        # 创建控件
        self.create_widgets()
        
    def create_widgets(self):
        # 目录选择
        ttk.Label(self.main_frame, text="PPT文件目录:").grid(row=0, column=0, sticky=tk.W, pady=2)
        self.dir_path = tk.StringVar()
        dir_entry = ttk.Entry(self.main_frame, textvariable=self.dir_path)
        dir_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2)
        ttk.Button(self.main_frame, text="浏览", command=self.browse_directory, width=8).grid(row=0, column=2, padx=5, pady=2)
        
        # 替换规则文件选择
        ttk.Label(self.main_frame, text="替换规则文件:").grid(row=1, column=0, sticky=tk.W, pady=2)
        self.rule_file = tk.StringVar()
        rule_entry = ttk.Entry(self.main_frame, textvariable=self.rule_file)
        rule_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2)
        ttk.Button(self.main_frame, text="浏览", command=self.browse_rule_file, width=8).grid(row=1, column=2, padx=5, pady=2)
        
        # 开始替换按钮
        ttk.Button(self.main_frame, text="开始替换", command=self.start_replacement, width=15).grid(row=2, column=0, columnspan=3, pady=10)
        
        # 日志显示区域
        ttk.Label(self.main_frame, text="替换进度:").grid(row=3, column=0, sticky=tk.W, pady=2)
        self.log_text = scrolledtext.ScrolledText(self.main_frame, width=50, height=20)
        self.log_text.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=2)
        
    def browse_directory(self):
        directory = filedialog.askdirectory()
        if directory:
            self.dir_path.set(directory)
            
    def browse_rule_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
        if file_path:
            self.rule_file.set(file_path)
            
    def log_message(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        
    def load_replacement_rules(self):
        rules = {}
        try:
            with open(self.rule_file.get(), 'r', encoding='utf-8') as f:
                for line in f:
                    if '=' in line:
                        old_text, new_text = line.strip().split('=', 1)
                        rules[old_text] = new_text
            return rules
        except Exception as e:
            self.log_message(f"错误:无法读取替换规则文件 - {str(e)}")
            return None
            
    def minimize_powerpoint_window(self):
        """最小化PowerPoint窗口"""
        try:
            # 查找PowerPoint窗口
            def callback(hwnd, extra):
                if win32gui.IsWindowVisible(hwnd):
                    title = win32gui.GetWindowText(hwnd)
                    if "PowerPoint" in title:
                        # 最小化窗口
                        win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
            win32gui.EnumWindows(callback, None)
        except Exception:
            pass
            
    def convert_ppt_in_memory(self, ppt_path):
        """在内存中将旧版PPT转换为PPTX格式"""
        try:
            # 初始化COM
            pythoncom.CoInitialize()
            
            # 创建PowerPoint应用程序对象
            powerpoint = win32com.client.Dispatch("PowerPoint.Application")
            powerpoint.Visible = True
            
            # 最小化PowerPoint窗口
            self.minimize_powerpoint_window()
            
            # 打开PPT文件
            presentation = powerpoint.Presentations.Open(ppt_path)
            
            # 创建临时文件路径
            temp_pptx = os.path.join(os.path.dirname(ppt_path), f"temp_{os.path.basename(ppt_path)}.pptx")
            
            # 保存为PPTX格式
            presentation.SaveAs(temp_pptx, 24)  # 24 表示PPTX格式
            
            # 加载到python-pptx中
            prs = Presentation(temp_pptx)
            
            # 关闭并删除临时文件
            presentation.Close()
            powerpoint.Quit()
            os.remove(temp_pptx)
            
            return prs
        except Exception as e:
            self.log_message(f"转换文件 {os.path.basename(ppt_path)} 时出错: {str(e)}")
            try:
                if 'temp_pptx' in locals() and os.path.exists(temp_pptx):
                    os.remove(temp_pptx)
            except:
                pass
            return None
        finally:
            # 清理COM
            pythoncom.CoUninitialize()
            
    def replace_text_in_paragraph(self, paragraph, rules):
        """替换段落中的文本,保持原有格式"""
        for old_text, new_text in rules.items():
            if old_text in paragraph.text:
                # 获取段落中的所有run
                runs = paragraph.runs
                text = paragraph.text
               
                # 找到所有匹配的位置
                matches = [(m.start(), m.end()) for m in re.finditer(re.escape(old_text), text)]
               
                if matches:
                    # 从后向前替换,避免索引变化
                    for start, end in reversed(matches):
                        # 计算在哪个run中
                        run_start = 0
                        for run in runs:
                            run_end = run_start + len(run.text)
                            if run_start  {new_text}")
                                break
                            run_start = run_end
                           
    def replace_text_in_shape(self, shape, rules):
        """替换形状中的文本,保持原有格式"""
        if hasattr(shape, "text_frame"):
            for paragraph in shape.text_frame.paragraphs:
                self.replace_text_in_paragraph(paragraph, rules)
               
        if shape.has_table:
            for row in shape.table.rows:
                for cell in row.cells:
                    for paragraph in cell.text_frame.paragraphs:
                        self.replace_text_in_paragraph(paragraph, rules)
                           
    def start_replacement(self):
        try:
            if not self.dir_path.get() or not self.rule_file.get():
                messagebox.showerror("错误", "请选择PPT文件目录和替换规则文件")
                return
               
            rules = self.load_replacement_rules()
            if not rules:
                return
               
            ppt_files = [f for f in os.listdir(self.dir_path.get()) if f.lower().endswith(('.ppt', '.pptx'))]
            if not ppt_files:
                messagebox.showerror("错误", "所选目录中没有PPT文件")
                return
               
            for ppt_file in ppt_files:
                try:
                    ppt_path = os.path.join(self.dir_path.get(), ppt_file)
                    self.log_message(f"\n处理文件: {ppt_file}")
                    
                    # 获取文件扩展名
                    file_ext = os.path.splitext(ppt_file)[1].lower()
                    
                    # 如果是旧版PPT格式,先转换为PPTX
                    if file_ext == '.ppt':
                        prs = self.convert_ppt_in_memory(ppt_path)  # 修改这里
                        if not prs:
                            continue
                        file_ext = '.pptx'
                    else:
                        prs = Presentation(ppt_path)
                    
                    for slide in prs.slides:
                        for shape in slide.shapes:
                            self.replace_text_in_shape(shape, rules)
                           
                    # 保存修改后的文件,添加日期前缀
                    import datetime
                    date_str = datetime.datetime.now().strftime("%Y%m%d")
                    new_filename = f"modified_{date_str}_{os.path.splitext(ppt_file)[0]}{file_ext}"
                    new_path = os.path.join(self.dir_path.get(), new_filename)
                    prs.save(new_path)
                    self.log_message(f"成功保存修改后的文件: {new_filename}")
                    
                except Exception as e:
                    self.log_message(f"处理文件 {ppt_file} 时出错: {str(e)}")
                    
            messagebox.showinfo("完成", "所有文件处理完成!")
        except KeyboardInterrupt:
            self.log_message("操作被用户中断")
        except Exception as e:
            self.log_message(f"发生未预期的错误: {str(e)}")
if __name__ == "__main__":
    root = tk.Tk()
    app = PPTTextReplacer(root)
    root.mainloop()

文件, 文本

wudalang123   

com资源漏洞修复
[Python] 纯文本查看 复制代码def convert_ppt_in_memory(self, ppt_path):
    try:
        pythoncom.CoInitialize()
        # 增加超时机制
        powerpoint = win32com.client.DispatchEx("PowerPoint.Application")
        powerpoint.Visible = False  # 禁止界面弹出
        presentation = powerpoint.Presentations.Open(ppt_path, ReadOnly=1)
    finally:
        if 'presentation' in locals():
            presentation.Close()
        if 'powerpoint' in locals():
            powerpoint.Quit()
        pythoncom.CoUninitialize()
wudalang123   

多线程批量处理
[Python] 纯文本查看 复制代码from concurrent.futures import ThreadPoolExecutor
def start_replacement(self):
    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = [executor.submit(self.process_single_file, ppt_file)
                  for ppt_file in ppt_files]
        for future in as_completed(futures):
            future.result()
pc466   

学习一下,谢谢分享
hygqx6   

这个值得学习
sanyisi   

谢谢分享,很有用
afti   

这个还是很实用的
shenwq   

这个可以学习一下,谢谢楼主分享。
wocaishihuanxio   

感谢楼主分享
wan_lei2008   

感谢分享,学习。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部