python-docx替换字符串【保存原有样式】

Background

  • 最近做的项目,需要根据模板生成报表。思路就和Java中使用EasyExcel一样,模板中使用占位符,然后替换成数据。
  • python3中操作docx可以使用python-docx。但是替换占位符时出现了问题,查找的基本都是基于paragraph替换,会改变原有的格式,自己经过摸索,最终找到一个解决办法,是基于run
  • python-docx官方文档地址

1、python-docx中概念介绍

python-docx在操作docx文档时分为Document - Paragraph - Run三级结构

  • 文档 Document:就是docx文件的逻辑表示;
  • 段落 Paragraph:docx文件中的段落;
  • 文字块 Run:Run 的概念比较难理解,且文字块间的划分也是很神奇的,所以我们后面需要验证下模板是否可用,即判断我们的占位符是否被划分成了一个文字块。

2、开始准备模板

如下图模板中,以ph_开头的斜体字即为占位符,后面需要替换成相应的数据。

在这里插入图片描述

3、测试模板是否可用

为什么需要测试模板可用?

  • 因为这个run文字块的划分真的很神奇。
  • 例如:ph_date_start这个占位符,如果ph_date_start不是同一时间写的即使你肉眼看着格式是一样的也会被划分为不同的文字块,遇到这种情况,只需要删除用键盘再敲出来就行了
  • 如果我们的占位符没有被拆成多个文字块就算测试通过了(即使多个占位符划分在了一个文字块也没关系),如下图所示。

在这里插入图片描述

  • 测试源码
from docx import Document


def main():
    """主函数"""
    file = 'reports/tpl/template.docx'
    doc = Document(file)
    paragraphs = doc.paragraphs
    for paragraph in paragraphs:
        for run in paragraph.runs:
            if 'ph_' in run.text:
                print(f'{run.italic}==={run.text}')


if __name__ == '__main__':
    main()

4、替换占位符

  • 最终效果
    在这里插入图片描述

  • 替换源码

from docx import Document


def replace_placeholder(doc, params):
    """替换占位符"""
    for paragraph in doc.paragraphs:
        for param in params:
            pv = str(params[param])
            ph = f'ph_{param}'
            if ph in paragraph.text:
                for run in paragraph.runs:
                    if ph in run.text:
                        run.text = run.text.replace(ph, pv)
                        run.italic = False


def main():
    """主函数"""
    tpl_doc = 'reports/tpl/建研院通用报表-template.docx'
    res_doc = 'reports/res/result.docx'
    doc = Document(tpl_doc)
    params = {
        "num_section": 1,
        "subject": "监测数据分析",
        "date_start": "2022年02月",
        "date_start": "2022年02月",
        "date_end": "2022年03月",
        "name_project": "塔筒结构健康监测",
        "names_types": "应变,索力,GPS,风速,风向",
        "count_target_all": 100,
    }
    replace_placeholder(doc, params)
    doc.save(res_doc)


if __name__ == '__main__':
    main()
  • 9
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WaiSaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值