python-docx 是用于创建和更新Microsoft Word(.docx)文件的Python库。
使用docx.Document(docx=None)构造函数可以创建一个Document 对象;关于Document和相关对象的用法如下:
add_heading(text=‘’, level=1)
返回新添加到文档末尾的标题段落。
add_paragraph(text=‘’, style=None)
返回新添加到文档末尾的段落,填充 text 有段落风格 风格 . text 可以包含制表符 (\t )字符,这些字符将转换为选项卡的适当XML格式。 text 也可以包括换行符 (\n )或回车 (\r )字符,每个字符都转换为换行符。
property paragraphs
列表 Paragraph 与文档中的段落相对应的实例,按文档顺序排列。
更多详细用法可参阅帮助文档 python-docx 0.8.11文档
python-docx 托管在PyPI上,所以安装相对简单。
python-docx 可以使用 pip 安装,如果你的网络链接正常的话:
pip install python-docx
python-docx 也可以使用 easy_install ,尽管不鼓励这样做:
easy_install python-docx
如果既不 pip 也不 easy_install 它可以通过从PyPI下载发行版、解包tarball并运行来手动安装 setup.py :pypi&python-docx下载
tar xvzf python-docx-{version}.tar.gz
cd python-docx-{version}
python setup.py install
如果您使用最后一种方法,则需要自己安装这些依赖项。
依赖关系
Python2.6、2.7、3.3或更高版本
lxml>=2.3.2
win10家庭中文版
python 3.9.0
python-docx 0.8.11
由其他程序产生的输出,已经保存为.txt文件;需要按照给定的格式输出一个新的文档。
从无到有的生成新的文档听起来令人振奋,实际应用过程中却并不可取;因为不确定因素导致的结果可能与你的最初的目的大相径庭。一个更可靠的做法是事先确定一个标准,将后续也许会出现在计划外的部分以一个固定的模板加以约束。于是就有了以下想法:
一、读取模板文档
首先构造一个Document对象;
doc_test = Document(r'.\test.docx')
接下来添加paragraph样式的索引,通过样式及索引确定paragraph的内容;
for i in doc_test.paragraphs: #
a += 1
self.par_list.append(i) # 通过正则匹配返回 {paragraph索引:style}的列表
style_m_1 = re.search('Normal', str(i.style))
style_m_2 = re.search('Heading 1', str(i.style))
if style_m_1:
self.style_list.append({a - 1: style_m_1.group(0)})
elif style_m_2:
self.style_list.append({a - 1: style_m_2.group(0)})
最后返回两个列表:
self.par_list = [] # test.docx文档paragraphs对象的paragraph类列表
self.style_list = [] # paragraph类的style索引列表
二、格式化源文件
打开源文件,保存line的内容列表;
with open('Prin.txt') as f_obj:
line_list = f_obj.readlines()
# print(line_list)
for line in line_list:
a += 1
if line == '---------------\n':
self.prn_list.append(a)
列出 ‘---------------\n’ 在 Prin.txt内容列表 line_list 中的索引;
hd_1 = int(self.prn_list[0]) # Prin.txt的第一个'---------------\n'索引
hd_2 = int(self.prn_list[1]) # Prin.txt的第二个'---------------\n'索引
hd_3 = int(self.prn_list[2]) # Prin.txt的第三个'---------------\n'索引
for ii in range(hd_1 + 1, hd_2):
self.prn_text1 += line_list[ii] # 第一个'---------------\n'索引到第二个'---------------\n'索引内容添加至字符串
for ii in range(hd_2 + 1, hd_3):
self.prn_text2 += line_list[ii] # 第二个'---------------\n'索引到第三个'---------------\n'索引内容添加至字符串
for ii in range(hd_3 + 1, len(line_list)):
self.prn_text3 += line_list[ii] # 第三个'---------------\n'索引到最后的内容添加至字符串
最终将源文件按照分割符’---------------'分为三部分内容分别保存至self.prn_text1、self.prn_text2、self.prn_text3中。
三、文档对象内容更新
确定标题及文档内容更新方法;
# 文档标题
self.TiTle_txt = 'XXX' + TiTle_txt + '数据检查'
# paragraph 方法 'add_run', 'alignment', 'clear', 'insert_paragraph_before'
TiTle = self.par_list[4].add_run(text=self.TiTle_txt)
TiTle.bold = True
TiTle.font.size = Pt(18)
对于字体的设定方法如下,这里注意设置了paragraph 对象的style字体后,你对应的样式字体会被全部修改;例如标题字体与正文不一致但是同样使用正文的样式"Normal",不能直接使用此类方法修改字体,应创建新的样式标题使用新样式的字体;
"""
中文字体的设置 paragraph对象
self.list[4].style.font.name = '楷体'
self.list[4].style._element.rPr.rFonts.set(qn('w:eastAsia'), u'楷体')
self.list[4].style.font.bold = True
self.list[4].style.font.size = Pt(18)
西文字体的设置 run对象
TiTle.bold = True
TiTle.font.size = Pt(18)
TiTle.font.name = '楷体'
"""
确定文档内容的输入位置;
for i in self.style_list:
for k, v in i.items():
if v == 'Heading 1': # 各分段标题的统一样式
self.Heading_list.append(k)
清理标题(‘Heading 1’)之间的内容;
hd_1 = int(self.Heading_list[0]) # 标题一的paragraph索引
hd_2 = int(self.Heading_list[1]) # 标题二的paragraph索引
hd_3 = int(self.Heading_list[2]) # 标题三的paragraph索引
hd_4 = int(self.Heading_list[3]) # 标题四的paragraph索引
for ii in range(hd_2 + 1, hd_3):
# print(ii)
self.par_list[ii].clear()
for ii in range(hd_3 + 1, hd_4):
# print(ii)
self.par_list[ii].clear()
在标题(‘Heading 1’)之间写入内容;
self.par_list[hd_2 + 1].add_run(text=self.prn_text1) # 标题二 之后的内容
self.par_list[hd_2 + 1].add_run(text=self.prn_text2) # 标题二 之后的内容
self.par_list[hd_3 + 1].add_run(text=self.prn_text3) # 标题三 之后的内容
self.par_list[hd_4 + 1].add_run(text='') # 标题四 之后的内容
四、保存输出新文档
消除上一步,清除内容后留下的空行;
hd_2 = int(self.Heading_list[1]) # 标题二的paragraph索引
hd_3 = int(self.Heading_list[2]) # 标题三的paragraph索引
hd_4 = int(self.Heading_list[3]) # 标题四的paragraph索引
for ii in range(hd_2, hd_3): # 消除空行 ? 存在问题未处理 标题二、标题三、标题四之间多一个空行
if len(self.par_list[ii].text) == 0:
p = self.par_list[ii]._element
p.getparent().remove(p)
p._p = p._element = None
for ii in range(hd_3, hd_4):
if len(self.par_list[ii].text) == 0:
p = self.par_list[ii]._element
p.getparent().remove(p)
p._p = p._element = None
输出新文档到指定路径;
a = list(os.path.split(path))[0]
self.doc.save(os.path.join(str(a), self.TiTle_txt + '报告.docx'))
# encoding: utf-8
# design by bill_love_3
from docx import Document
from docx.shared import Pt
import re
import os
"""
需求:
1.读取test.docx模板文档内容及样式;
2.用模板的样式格式化Prin.txt文档
3.将格式化后的内容添加到test.docx文档中去
4.添加内容后输出新的文档
"""
class FormatDocument():
def __init__(self):
self.par_list = [] # test.docx文档paragraphs对象的paragraph类列表
self.style_list = [] # paragraph类的style索引列表
self.doc = '' # test.docx文档对象
self.Heading_list = [] # 标题所在位置的paragraph索引列表 整数
self.prn_text1 = '' # 源txt的内容部分一
self.prn_text2 = '' # 源txt的内容部分二
self.prn_text3 = '' # 源txt的内容部分三
self.prn_list = [] # 源txt的分隔标识符索引位置列表 整数 “---------------”
self.TiTle_txt = '' # 输出文档的标题内容 样式固定
def ReadTestDocx(self, a=0): # 读取模板文档方法
doc_test = Document(r'.\test.docx') #
self.doc = doc_test
# 添加paragraph样式的索引 通过样式及索引确定paragraph内容
for i in doc_test.paragraphs: #
a += 1
self.par_list.append(i) # 通过正则匹配返回 {paragraph索引:style}的列表
style_m_1 = re.search('Normal', str(i.style))
style_m_2 = re.search('Heading 1', str(i.style))
if style_m_1:
self.style_list.append({a - 1: style_m_1.group(0)})
elif style_m_2:
self.style_list.append({a - 1: style_m_2.group(0)})
# print(self.style)
def FormatPrin(self, a=-1): # 格式化源文件方法
with open('Prin.txt') as f_obj:
line_list = f_obj.readlines()
# print(line_list)
for line in line_list:
a += 1
if line == '---------------\n':
self.prn_list.append(a) # 列出 '---------------\n' 在 Prin.txt内容列表 line_list 中的索引
print(self.prn_list)
hd_1 = int(self.prn_list[0]) # Prin.txt的第一个'---------------\n'索引
hd_2 = int(self.prn_list[1]) # Prin.txt的第二个'---------------\n'索引
hd_3 = int(self.prn_list[2]) # Prin.txt的第三个'---------------\n'索引
for ii in range(hd_1 + 1, hd_2):
self.prn_text1 += line_list[ii] # 第一个'---------------\n'索引到第二个'---------------\n'索引内容添加至字符串
for ii in range(hd_2 + 1, hd_3):
self.prn_text2 += line_list[ii] # 第二个'---------------\n'索引到第三个'---------------\n'索引内容添加至字符串
for ii in range(hd_3 + 1, len(line_list)):
self.prn_text3 += line_list[ii] # 第三个'---------------\n'索引到最后的内容添加至字符串
# print(self.prn_text1, self.prn_text2, self.prn_text3)
def AddToTestDocx(self, TiTle_txt): # 文档对象内容更新方法
# 文档标题
self.TiTle_txt = 'XXX' + TiTle_txt + '数据检查'
# paragraph 方法 'add_run', 'alignment', 'clear', 'insert_paragraph_before'
TiTle = self.par_list[4].add_run(text=self.TiTle_txt)
TiTle.bold = True
TiTle.font.size = Pt(18)
# 文档内容 确定输入位置
for i in self.style_list:
for k, v in i.items():
if v == 'Heading 1': # 各分段标题的统一样式
self.Heading_list.append(k)
# print(self.Heading_list)
# 清理标题之间的内容
hd_1 = int(self.Heading_list[0]) # 标题一的paragraph索引
hd_2 = int(self.Heading_list[1]) # 标题二的paragraph索引
hd_3 = int(self.Heading_list[2]) # 标题三的paragraph索引
hd_4 = int(self.Heading_list[3]) # 标题四的paragraph索引
for ii in range(hd_2 + 1, hd_3):
# print(ii)
self.par_list[ii].clear()
for ii in range(hd_3 + 1, hd_4):
# print(ii)
self.par_list[ii].clear()
# 在标题之间写入内容
self.par_list[hd_2 + 1].add_run(text=self.prn_text1) # 标题二 之后的内容
self.par_list[hd_2 + 1].add_run(text=self.prn_text2) # 标题二 之后的内容
self.par_list[hd_3 + 1].add_run(text=self.prn_text3) # 标题三 之后的内容
self.par_list[hd_4 + 1].add_run(text='') # 标题四 之后的内容
def SaveNewDocx(self, path): # 保存输出新文档方法
hd_2 = int(self.Heading_list[1]) # 标题二的paragraph索引
hd_3 = int(self.Heading_list[2]) # 标题三的paragraph索引
hd_4 = int(self.Heading_list[3]) # 标题四的paragraph索引
for ii in range(hd_2, hd_3): # 消除空行 ? 存在问题未处理 标题二、标题三、标题四之间多一个空行
if len(self.par_list[ii].text) == 0:
p = self.par_list[ii]._element
p.getparent().remove(p)
p._p = p._element = None
for ii in range(hd_3, hd_4):
if len(self.par_list[ii].text) == 0:
p = self.par_list[ii]._element
p.getparent().remove(p)
p._p = p._element = None
a = list(os.path.split(path))[0]
self.docs.save(os.path.join(str(a), self.TiTle_txt + '报告.docx'))
if __name__ == "__main__":
path = 'C:\\drea\\python3\\Qu_Ins_04_04_2023\\数据库.gdb'
myDocument = FormatDocument()
myDocument.ReadTestDocx()
myDocument.FormatPrin()
myDocument.AddToTestDocx('xxxx')
myDocument.SaveNewDocx(path)
目前只是完成了简单的格式化输出,对样式的定义及缩进等控制还没有更深入的涉及;接下来的想法是构造一个包含多种样式的定义及缩进等格式的程序,后续会陆续更新的。