python-docx を使用して出力ドキュメントをフォーマットする簡単な試み

Python-docxとは何ですか?

python-docx は、Microsoft Word (.docx) ファイルを作成および更新するための Python ライブラリです。

Python-docx の概要

docx.Document(docx=None) コンストラクターを使用して Document オブジェクトを作成します。Document および関連オブジェクトの使用法は次のとおりです:
add_Heading(text='', level=1) は、
ヘッダーの末尾に新しく追加された見出し段落を返します。書類。
add_paragraph(text='', style=None) は、
文書の末尾に新しく追加された段落を返します。この段落には段落スタイルのテキストが埋め込まれています。テキストにはタブ (\t) 文字を含めることができ、適切な XML に変換されます。タブの形式。テキストには改行 (\n ) またはキャリッジ リターン (\r ) 文字を含めることもでき、それぞれ改行に変換されます。
プロパティ段落は、
文書内の段落に対応する段落インスタンスを文書順にリストします。
詳しい使用方法については、ヘルプドキュメント python-docx 0.8.11 ドキュメントを参照してください。

Python-docxをインストールする

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 download
tar xvzf python-docx-{version}.tar.gz
cd python-docx-{version}
python setup.py install
ここに画像の説明を挿入

最後の方法を使用する場合は、これらの依存関係を自分でインストールする必要があります。
依存関係
Python 2.6、2.7、3.3 以降
lxml >= 2.3.2

ソフトウェア環境

win10 ホーム中国語版
python 3.9.0
python-docx 0.8.11

ニーズを判断する

他のプログラムによって生成された出力は .txt ファイルとして保存されているため、新しいドキュメントを指定された形式に従って出力する必要があります。

具体的な実装とアイデア

新しい書類をゼロから作成するのは魅力的ですが、実際の申請プロセスではお勧めできません。不確実な要因によって結果が本来の目的と大きく異なる可能性があります。より確実なアプローチは、事前に標準を決定し、固定テンプレートを使用して後続の計画外の部分を制約することです。そこで次のような考え方があります。
ここに画像の説明を挿入

1. テンプレートドキュメントを読み取ります
。まず Document オブジェクトを構築します。

doc_test = Document(r'.\test.docx')

次に、段落スタイルのインデックスを追加し、スタイルとインデックスによって段落の内容を決定します。

        for i in doc_test.paragraphs:  # <docx.text.paragraph.Paragraph object at 0x000002533CF7AA00>
            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)})

最後に 2 つのリストを返します。

        self.par_list = []  # test.docx文档paragraphs对象的paragraph类列表
        self.style_list = []  # paragraph类的style索引列表

次に、ソースファイルをフォーマットします

ソース ファイルを開き、その行の内容リストを保存します。

        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) 

Prin.txt コンテンツ リスト line_list 内の '--------------\n' のインデックスを一覧表示します。

        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'索引到最后的内容添加至字符串

最後に、ソースファイルを区切り文字「---------------」に従って 3 つの部分に分割し、内容をそれぞれ self.prn_text1、self.prn_text2、self.prn_text3 に保存します。

3. ドキュメントオブジェクトのコンテンツの更新

文書内容のタイトルと更新方法を決定します。

        # 文档标题
        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对象
        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)

見出し間のコンテンツをクリーンアップします (「見出し 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()

見出し (「見出し 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='')  # 标题四 之后的内容

4 番目に、出力された新しいドキュメントを保存します。

前の手順でコンテンツをクリアした後に残った空白行を削除します。

        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')  # <class 'docx.document.Document'>
        self.doc = doc_test
        # 添加paragraph样式的索引 通过样式及索引确定paragraph内容
        for i in doc_test.paragraphs:  # <docx.text.paragraph.Paragraph object at 0x000002533CF7AA00>
            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)

まとめと考察

現時点では、単純な書式設定された出力だけが完成しており、スタイルの定義やインデント制御には深く関わっていませんが、次のアイデアとしては、複数のスタイル定義やインデント形式を含むプログラムを構築し、順次実行していきます。更新しました。

おすすめ

転載: blog.csdn.net/bill_love_c/article/details/130023947