这是一个典型的“模板填充”需求:使用 Python 自动将用户输入的字段(送检人1、送检人2、案件名称、案件编号、杀毒版本)替换 Word 文档中预定义的占位符 `{{C1}}` ~ `{{C5}}`。推荐使用 **`python-docx`** 库(操作 `.docx` 文件) + **`tkinter`**(轻量级图形输入界面),无需依赖 Microsoft Word 进程,纯 Python 实现,跨平台、稳定可靠。
⚠️ 注意:`python-docx` **不能处理 `.doc`(旧版二进制格式)或带宏/复杂域代码的文档**,仅支持 `.docx`(Office Open XML 格式)。确保你的模板是 `.docx` 文件,且 `{{C1}}` 等标记存在于**普通段落文本中**(非页眉/页脚/文本框/表格单元格内需额外处理——下文会覆盖)。
---
### ✅ 完整解决方案(含 GUI 输入 + Word 填充)
#### 步骤说明:
1. 用 `tkinter` 弹出简洁输入对话框,获取 5 个字段;
2. 加载 `.docx` 模板文件;
3. 全局查找并替换所有 `{{C1}}` → `送检人1值`,…,`{{C5}}` → `杀毒版本值`;
4. **关键增强**:同时处理段落(Paragraph)、表格单元格(Table cell)、页眉/页脚(Header/Footer)中的文本;
5. 保存为新文件(如 `已填写_XXX.docx`),避免覆盖原模板。
---
### 🧾 Python 代码(完整可运行)
```python
import tkinter as tk
from tkinter import ttk, messagebox
from docx import Document
from docx.document import Document as DocType
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import os
def replace_in_paragraph(paragraph, replacements):
"""在段落中安全替换所有占位符(支持加粗/斜体等格式保留)"""
for run in paragraph.runs:
text = run.text
for key, value in replacements.items():
if key in text:
run.text = text.replace(key, str(value))
break # 避免重复替换干扰格式
def replace_in_table(table, replacements):
"""递归替换表格中所有单元格的文本(含嵌套表格)"""
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
replace_in_paragraph(paragraph, replacements)
for table_in_cell in cell.tables:
replace_in_table(table_in_cell, replacements)
def replace_in_header_footer(secs, replacements, is_header=True):
"""替换页眉或页脚中的文本"""
for section in secs:
if is_header:
header = section.header
elements = [header] + list(header._element.xpath('.//w:t'))
else:
footer = section.footer
elements = [footer] + list(footer._element.xpath('.//w:t'))
# 更可靠方式:遍历所有段落
for paragraph in header.paragraphs if is_header else footer.paragraphs:
replace_in_paragraph(paragraph, replacements)
# 处理页眉/页脚中的表格
for table in (header.tables if is_header else footer.tables):
replace_in_table(table, replacements)
def fill_word_template(template_path, output_path, data):
"""
将 data 字典(key: {{C1}}~{{C5}})填入 template_path 的 .docx,保存到 output_path
"""
try:
doc = Document(template_path)
# 构建替换映射(注意:必须用字符串形式匹配)
replacements = {
"{{C1}}": data.get("C1", ""),
"{{C2}}": data.get("C2", ""),
"{{C3}}": data.get("C3", ""),
"{{C4}}": data.get("C4", ""),
"{{C5}}": data.get("C5", "")
}
# 1. 替换正文段落
for paragraph in doc.paragraphs:
replace_in_paragraph(paragraph, replacements)
# 2. 替换所有表格
for table in doc.tables:
replace_in_table(table, replacements)
# 3. 替换页眉和页脚
for section in doc.sections:
replace_in_header_footer([section], replacements, is_header=True)
replace_in_header_footer([section], replacements, is_header=False)
doc.save(output_path)
return True
except Exception as e:
messagebox.showerror("错误", f"填充 Word 失败:{str(e)}")
return False
def show_input_dialog():
"""创建输入窗口"""
root = tk.Tk()
root.title("案件信息填写")
root.geometry("450x320")
root.resizable(False, False)
# 输入字段变量
c1_var = tk.StringVar()
c2_var = tk.StringVar()
c3_var = tk.StringVar()
c4_var = tk.StringVar()
c5_var = tk.StringVar()
# 表单布局
fields = [
("送检人1", c1_var),
("送检人2", c2_var),
("案件名称", c3_var),
("案件编号", c4_var),
("杀毒版本", c5_var),
]
for i, (label_text, var) in enumerate(fields):
ttk.Label(root, text=f"{label_text}:", font=("Arial", 10)).grid(
row=i, column=0, padx=10, pady=8, sticky="e"
)
entry = ttk.Entry(root, textvariable=var, width=35, font=("Arial", 10))
entry.grid(row=i, column=1, padx=10, pady=8, sticky="w")
def on_submit():
# 获取输入值
data = {
"C1": c1_var.get().strip(),
"C2": c2_var.get().strip(),
"C3": c3_var.get().strip(),
"C4": c4_var.get().strip(),
"C5": c5_var.get().strip(),
}
# 校验必填项(可根据业务调整)
if not all(data.values()):
messagebox.showwarning("警告", "请填写所有字段!")
return
# 选择模板路径(硬编码 or 弹窗选择?此处用固定路径示例)
template_path = "template.docx" # ← 替换为你的真实模板路径
if not os.path.exists(template_path):
messagebox.showerror("错误", f"未找到模板文件:{template_path}\n请确保当前目录下有 template.docx")
return
# 生成输出路径
output_path = "已填写_" + os.path.basename(template_path)
# 执行填充
if fill_word_template(template_path, output_path, data):
messagebox.showinfo("成功", f"已成功生成:\n{output_path}")
root.destroy()
ttk.Button(root, text="确认填写并保存", command=on_submit, width=20).grid(
row=len(fields), column=0, columnspan=2, pady=20
)
root.mainloop()
# —— 启动程序 ——
if __name__ == "__main__":
# ⚠️ 首次运行前请安装依赖:
# pip install python-docx
show_input_dialog()
```
---
### 🔍 代码关键点解释:
| 模块 | 作用 | 注意事项 |
|------|------|----------|
| `tkinter` | 提供轻量 GUI 输入框 | 无需额外安装(Python 内置),适合内部工具 |
| `python-docx` | 读写 `.docx` 文件 | **不修改原模板**,只读取后另存新文件;支持段落/表格/页眉页脚 |
| `replace_in_paragraph()` | 安全替换段落文本 | 逐 `run` 处理,**保留字体加粗、颜色、字号等格式**(`run.text` 是最小格式单位) |
| `replace_in_table()` | 递归处理表格(含嵌套表) | Word 表格可能多层嵌套,必须深度遍历 |
| `replace_in_header_footer()` | 覆盖页眉页脚 | `section.header/footer` 可能含段落和表格,需分别处理 |
| 错误处理 | `try/except` + `messagebox` | 用户友好提示,避免崩溃 |
✅ **优势总结**:
- ✅ 纯 Python,无 Office 依赖,Linux/macOS/Windows 均可运行
- ✅ 保留原文档所有格式(加粗、颜色、缩进、项目符号、表格边框)
- ✅ 支持页眉页脚、表格、多级嵌套内容替换
- ✅ 输入校验 + 友好弹窗反馈
- ✅ 输出文件自动命名,防止误覆盖
🔧 **使用前准备**:
1. `pip install python-docx`
2. 将你的 Word 模板保存为 `template.docx`(与本脚本同目录),并在其中插入 `{{C1}}` ~ `{{C5}}` 占位符(直接打字即可,无需特殊样式)
3. 运行脚本,填写后点击“确认填写并保存”
---
### 📌 常见问题 & 排查建议:
- ❌ **替换没生效?** → 检查占位符是否拼写完全一致(`{{C1}}` 不是 `{C1}` 或 `{{c1}}`,区分大小写)
- ❌ **页眉里的 `{{C3}}` 没替换?** → 确认页眉已启用(Word 中双击页眉区域可编辑),且未设置“首页不同”导致 section 数量异常
- ❌ **表格内文字没变?** → `python-docx` 对某些复杂表格(如合并单元格含多个段落)可能需额外逻辑,可提供样例我帮你扩展
- 💡 **想支持更多字段?** → 只需在 `fields` 列表和 `replacements` 字典中追加,无需改核心逻辑
---