word文本替换工具.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import tkinter as tk
  2. from tkinter import ttk, filedialog, messagebox
  3. import os
  4. from docx import Document
  5. import threading
  6. class WordReplacerApp:
  7. def __init__(self, root):
  8. self.root = root
  9. self.root.title("Word日期替换工具")
  10. self.root.geometry("600x560")
  11. self.root.resizable(False, False)
  12. # 设置样式
  13. style = ttk.Style()
  14. style.theme_use('clam')
  15. # 创建主框架
  16. main_frame = ttk.Frame(root, padding="20")
  17. main_frame.pack(fill=tk.BOTH, expand=True)
  18. # 标题
  19. title_label = ttk.Label(main_frame, text="Word文档日期批量替换工具",
  20. font=("微软雅黑", 16, "bold"))
  21. title_label.pack(pady=(0, 20))
  22. # 说明区域
  23. info_frame = ttk.LabelFrame(main_frame, text="替换规则", padding="10")
  24. info_frame.pack(fill=tk.X, pady=(0, 15))
  25. rule1 = ttk.Label(info_frame, text="• 将 \"xx月\" 替换为 \"07月\"")
  26. rule1.pack(anchor=tk.W, pady=2)
  27. rule2 = ttk.Label(info_frame, text="• 将 \"xx日\" 替换为 \"08日\"")
  28. rule2.pack(anchor=tk.W, pady=2)
  29. rule3 = ttk.Label(info_frame, text="• 支持同时替换月和日", foreground="gray")
  30. rule3.pack(anchor=tk.W, pady=2)
  31. # 文件选择区域
  32. file_frame = ttk.LabelFrame(main_frame, text="文件选择", padding="10")
  33. file_frame.pack(fill=tk.X, pady=(0, 15))
  34. # 文件路径显示
  35. self.file_path_var = tk.StringVar()
  36. self.file_path_var.set("未选择文件")
  37. path_entry = ttk.Entry(file_frame, textvariable=self.file_path_var,
  38. state='readonly', font=("微软雅黑", 10))
  39. path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
  40. select_btn = ttk.Button(file_frame, text="选择Word文件",
  41. command=self.select_file, width=12)
  42. select_btn.pack(side=tk.RIGHT)
  43. # 选项区域
  44. options_frame = ttk.LabelFrame(main_frame, text="替换选项", padding="10")
  45. options_frame.pack(fill=tk.X, pady=(0, 15))
  46. # 替换月份选项
  47. self.replace_month_var = tk.BooleanVar(value=True)
  48. month_check = ttk.Checkbutton(options_frame, text="替换月份 (xx月 → 07月)",
  49. variable=self.replace_month_var)
  50. month_check.pack(anchor=tk.W, pady=2)
  51. # 替换日期选项
  52. self.replace_day_var = tk.BooleanVar(value=True)
  53. day_check = ttk.Checkbutton(options_frame, text="替换日期 (xx日 → 08日)",
  54. variable=self.replace_day_var)
  55. day_check.pack(anchor=tk.W, pady=2)
  56. # 进度条
  57. self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
  58. self.progress.pack(fill=tk.X, pady=(0, 15))
  59. # 操作按钮区域
  60. btn_frame = ttk.Frame(main_frame)
  61. btn_frame.pack(fill=tk.X, pady=(0, 10))
  62. self.process_btn = ttk.Button(btn_frame, text="开始替换",
  63. command=self.start_process, width=15)
  64. self.process_btn.pack(side=tk.LEFT, padx=(0, 10))
  65. self.save_btn = ttk.Button(btn_frame, text="另存为...",
  66. command=self.save_as, width=15, state='disabled')
  67. self.save_btn.pack(side=tk.LEFT)
  68. # 状态栏
  69. self.status_var = tk.StringVar()
  70. self.status_var.set("就绪 - 请选择Word文件")
  71. status_label = ttk.Label(main_frame, textvariable=self.status_var,
  72. relief=tk.SUNKEN, anchor=tk.W, padding=(5, 2))
  73. status_label.pack(fill=tk.X, pady=(10, 0))
  74. # 存储处理后的文档
  75. self.processed_doc = None
  76. self.original_path = None
  77. self.output_path = None
  78. def select_file(self):
  79. """选择Word文件"""
  80. file_path = filedialog.askopenfilename(
  81. title="选择Word文档",
  82. filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")]
  83. )
  84. if file_path:
  85. self.file_path_var.set(file_path)
  86. self.original_path = file_path
  87. self.processed_doc = None
  88. self.output_path = None
  89. self.save_btn.config(state='disabled')
  90. self.status_var.set(f"已选择: {os.path.basename(file_path)}")
  91. def start_process(self):
  92. """开始处理文档"""
  93. if not self.original_path:
  94. messagebox.showwarning("警告", "请先选择一个Word文件!")
  95. return
  96. # 检查文件是否存在
  97. if not os.path.exists(self.original_path):
  98. messagebox.showerror("错误", "文件不存在,请重新选择!")
  99. return
  100. # 检查是否至少选择了一个替换选项
  101. if not self.replace_month_var.get() and not self.replace_day_var.get():
  102. messagebox.showwarning("警告", "请至少选择一种替换选项!")
  103. return
  104. # 禁用按钮
  105. self.process_btn.config(state='disabled')
  106. self.save_btn.config(state='disabled')
  107. self.progress.start(10)
  108. self.status_var.set("正在处理文档...")
  109. # 在新线程中处理
  110. thread = threading.Thread(target=self.process_document)
  111. thread.daemon = True
  112. thread.start()
  113. def process_document(self):
  114. """处理文档的核心逻辑"""
  115. try:
  116. # 加载文档
  117. doc = Document(self.original_path)
  118. replace_count = 0
  119. # 遍历所有段落
  120. for paragraph in doc.paragraphs:
  121. text = paragraph.text
  122. modified = False
  123. # 替换月份
  124. if self.replace_month_var.get() and "xx月" in text:
  125. text = text.replace("xx月", "07月")
  126. modified = True
  127. replace_count += 1
  128. # 替换日期
  129. if self.replace_day_var.get() and "xx日" in text:
  130. text = text.replace("xx日", "08日")
  131. modified = True
  132. replace_count += 1
  133. # 如果段落被修改,更新内容
  134. if modified:
  135. # 保留原有格式
  136. paragraph.clear()
  137. paragraph.add_run(text)
  138. # 遍历所有表格中的单元格
  139. for table in doc.tables:
  140. for row in table.rows:
  141. for cell in row.cells:
  142. for paragraph in cell.paragraphs:
  143. text = paragraph.text
  144. modified = False
  145. if self.replace_month_var.get() and "xx月" in text:
  146. text = text.replace("xx月", "07月")
  147. modified = True
  148. replace_count += 1
  149. if self.replace_day_var.get() and "xx日" in text:
  150. text = text.replace("xx日", "08日")
  151. modified = True
  152. replace_count += 1
  153. if modified:
  154. paragraph.clear()
  155. paragraph.add_run(text)
  156. # 保存处理后的文档
  157. self.processed_doc = doc
  158. self.replace_count = replace_count
  159. # 更新UI
  160. self.root.after(0, self.process_complete, replace_count)
  161. except Exception as e:
  162. self.root.after(0, self.process_error, str(e))
  163. def process_complete(self, count):
  164. """处理完成回调"""
  165. self.progress.stop()
  166. self.process_btn.config(state='normal')
  167. self.save_btn.config(state='normal')
  168. if count > 0:
  169. self.status_var.set(f"处理完成!共替换 {count} 处")
  170. messagebox.showinfo("成功", f"文档处理完成!\n共进行了 {count} 处替换。\n请点击'另存为...'保存文件。")
  171. else:
  172. self.status_var.set("处理完成!未找到需要替换的内容")
  173. messagebox.showinfo("提示", "未找到需要替换的 'xx月' 或 'xx日' 内容。")
  174. def process_error(self, error_msg):
  175. """处理错误回调"""
  176. self.progress.stop()
  177. self.process_btn.config(state='normal')
  178. self.save_btn.config(state='disabled')
  179. self.status_var.set(f"错误: {error_msg}")
  180. messagebox.showerror("错误", f"处理文档时出错:\n{error_msg}")
  181. def save_as(self):
  182. """另存为功能"""
  183. if not self.processed_doc:
  184. messagebox.showwarning("警告", "请先处理文档!")
  185. return
  186. # 生成默认文件名
  187. base_name = os.path.splitext(os.path.basename(self.original_path))[0]
  188. default_name = f"{base_name}_替换后.docx"
  189. save_path = filedialog.asksaveasfilename(
  190. title="保存文档",
  191. defaultextension=".docx",
  192. filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")],
  193. initialfile=default_name
  194. )
  195. if save_path:
  196. try:
  197. self.processed_doc.save(save_path)
  198. self.output_path = save_path
  199. self.status_var.set(f"已保存: {os.path.basename(save_path)}")
  200. messagebox.showinfo("成功", f"文档已保存到:\n{save_path}")
  201. except Exception as e:
  202. messagebox.showerror("错误", f"保存文件时出错:\n{e}")
  203. def main():
  204. root = tk.Tk()
  205. app = WordReplacerApp(root)
  206. root.mainloop()
  207. if __name__ == "__main__":
  208. main()