detailed-docx:一个能保住格式的 Word 文档操作库

项目地址:

问题

用 Python 改 Word 文档里的内容,最怕的就是格式丢失。

python-docx 是 Python 生态里操作 .docx 的标准库,功能很全,但它提供的是底层能力------你得自己处理文本碎片、格式保留、合并单元格等问题。对于"改几个字但格式不能动"这种需求,裸用 python-docx 其实不太行。

detailed-docx 就是在 python-docx 之上封装的一层,专门解决格式保留问题。

Word 的内部结构:理解 Run

要理解为什么"改个字"这么难,需要先了解 Word 文档的内部结构。

一个段落(Paragraph)并不是一整段文字,而是由多个 Run 拼接而成。每个 Run 是一段格式一致的文本片段:

复制代码
段落: "北京公司在2023年取得了非常优秀的业绩"

  Run[0]: "北京公司"     → 粗体, 蓝色, 14pt
  Run[1]: "在2023年取得了" → 常规, 黑色, 12pt
  Run[2]: "非常优秀"     → 粗体, 斜体, 红色
  Run[3]: "的业绩"       → 常规, 黑色, 12pt

每个 Run 在 XML 层面有独立的格式节点 <w:rPr>,这就是 Word 实现"一段话里混合多种格式"的机制。

问题在于:Run 的拆分是不可控的 。Word 会因为拼写检查、编辑历史、中英文切换等原因,自动把文字拆成碎片。你以为 "北京公司" 在一个 Run 里,实际上可能被拆成 "北京""公司" 两个 Run。这导致直接搜索 paragraph.text 能找到,但逐个 Run 遍历却找不到完整匹配。

如果你直接写 paragraph.text = "新内容",python-docx 会把所有 Run 清空再重建------格式全没了

核心算法:跨 Run 映射与替换

detailed-docx 的核心是一个字符位置映射算法:

复制代码
1. 拼接所有 Run 的文本 → full_text = "北京公司在2023年取得了非常优秀的业绩"
2. 构建映射表:每个字符位置属于哪个 Run
3. 在 full_text 上搜索目标文本
4. 将匹配区间映射回各个 Run,逐个修改其 text 属性
5. 关键:只改 text,不动 <w:rPr> 格式节点

替换 "北京公司""上海分公司" 的实际操作:

  • Run0 的 text 从 "北京公司" 改成 "上海分公司"<w:rPr>(粗体+蓝色+14pt)完全不动
  • 如果匹配横跨多个 Run,后续 Run 只清空被命中的文字部分

这样就可以做到文本变了但是格式原封不动。

格式修改:增量叠加

修改格式同样是,保证只动你指定的,不碰其他的:

python 复制代码
# "非常优秀" 原来是 {粗体, 斜体, 红色}
editor.modify_format("非常优秀", {"underline": True})
# 结果:{粗体, 斜体, 红色, 下划线} ← 只新增,不覆盖

API 概览

python 复制代码
from my_docx import DocxEditor

# ── 读取 ──
editor = DocxEditor("input.docx")
editor.get_structural_map()        # 段落 + 表格 + 节的完整结构
editor.get_run_details(para_idx=1) # 查看某段的 Run 碎片和精确格式

# ── 替换(自动跨 Run,自动保格式)──
editor.replace_text("旧词", "新词")
editor.replace_in_table(0, 1, 3, "旧值", "新值")

# ── 格式(增量叠加)──
editor.modify_format("重点内容", {"bold": True, "color": "FF0000"})

# ── 写入空单元格 ──
editor.set_table_cell_text(0, 0, 3, "张三", {"name": "黑体", "size": 12})

# ── 创建 ──
editor = DocxEditor.create_new()
editor.add_heading("标题", level=1)
editor.add_paragraph("正文", fmt={"name": "宋体", "size": 12})

# ── 删除 ──
editor.delete_paragraph(3)
editor.delete_table_row(0, 2)

editor.save("output.docx")
相关推荐
泡海椒12 分钟前
告别 iText 繁杂配置:jquick-pdf 极简 PDF 生成实战(零基础上手)
java·开发语言·pdf
赵大仁1 小时前
极空间 NAS 没有命令行,我逆向了它的桌面客户端
python·ai编程·nas·mcp·极空间
空白2 小时前
Power BI +VBA 【数据分析】
python
科技苑8 小时前
Python简单网络爬虫教程
爬虫·python
Patrick在香港10 小时前
Claude Prompt 香港场景:公文里「今日」落在 6 个日历日上,「翌日」锚错了 5 天
python·自然语言处理·正则表达式·claude·数据清洗
YsyaaabB11 小时前
Python 数值分析
python
阿洛学长11 小时前
计算机二级 Python 基本操作题(15 分)真题笔记(0101 ~ 1903 全套)
python·pycharm
君顾111 小时前
上海24小时自助健身房系统开发实战指南:从架构设计到落地部署
java·开发语言·健身房
weixin1997010801611 小时前
[特殊字符]️《二手ERP对接电商平台的总体方案:统一数据模型 + 事件驱动 + 灰度上线6原则》(附Python源码)
大数据·python
香菜TTT12 小时前
大模型上下文协议(MCP):AI 应用的“USB-C”接口技术
开发语言·人工智能·经验分享