久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

docxtpl實(shí)戰(zhàn)案例-審計(jì)腳注表格回填

 小小明代碼實(shí)體 2021-11-30

作者:小小明

Pandas數(shù)據(jù)處理專家,幫助一萬(wàn)用戶解決數(shù)據(jù)處理難題。

最近碰到一個(gè)需求:

image-20201231152501300

雖然我沒(méi)完全看懂啥意思,但大意就是:

1.讀取word文檔,將其中所有的表格都寫(xiě)入到一個(gè)excel文件中

2.對(duì)寫(xiě)好的excel做出一些修改(包括改某幾個(gè)單元格的值和刪除行),然后將修改后的excel數(shù)據(jù)回填到word表對(duì)應(yīng)的位置

對(duì)于第一個(gè)需求,直接用pandas寫(xiě)出即可

對(duì)于第二個(gè)需求,先生成模板,再用docxtpl模板渲染

關(guān)于docxtpl,我已經(jīng)根據(jù)官方文檔,制作了一份操作手冊(cè):https://blog.csdn.net/as604049322/article/details/112008531

好了,就按照這個(gè)大致理解的需求開(kāi)始干:

讀取word文檔表格寫(xiě)入到excel

python代碼:

from docx import Document
import pandas as pd


doc = Document(r"test.docx")
writer = pd.ExcelWriter("test.xlsx")
for i, table in enumerate(doc.tables):
    header = [cell.text for cell in table.rows[0].cells]
    result = []
    for row in table.rows[1:]:
        tmp = []
        for cell in row.cells:
            tmp.append(cell.text)
        result.append(tmp)
    df = pd.DataFrame(result, columns=header)
    df.to_excel(writer, sheet_name=f"{i}", index=False)

writer.save()

經(jīng)過(guò)上面代碼處理,就將這樣一個(gè)word文檔:

image-20201231155311116

提取出來(lái)了這樣的一個(gè)excel文件:

image-20201231155425633

整體效果已經(jīng)達(dá)到,但是我覺(jué)得如果能順便設(shè)置好列寬就好看點(diǎn),要設(shè)置好列寬,我的思路是計(jì)算出每列的字符串的最大長(zhǎng)度,但不能直接用字符長(zhǎng)度,每個(gè)中文字符會(huì)占用兩個(gè)長(zhǎng)度,所以我直接取gbk編碼后的字節(jié)長(zhǎng)度:

from docx import Document
import pandas as pd
import numpy as np

doc = Document(r"test.docx")
writer = pd.ExcelWriter("test.xlsx")
workbook = writer.book

for i, table in enumerate(doc.tables):
    header = [cell.text for cell in table.rows[0].cells]
    result = []
    for row in table.rows[1:]:
        tmp = []
        for cell in row.cells:
            tmp.append(cell.text)
        result.append(tmp)
    df = pd.DataFrame(result, columns=header)
    df.to_excel(writer, sheet_name=f"{i}", index=False)
    worksheet = writer.sheets[f"{i}"]
    #  計(jì)算表頭的字符寬度
    column_widths = (
        df.columns.to_series()
        .apply(lambda x: len(x.encode('gbk'))).values
    )
    #  計(jì)算每列的最大字符寬度
    max_widths = (
        df.astype(str)
        .applymap(lambda x: len(x.encode('gbk')))
        .agg(max).values
    )
    # 計(jì)算整體最大寬度
    widths = np.max([column_widths, max_widths], axis=0)
    for i, width in enumerate(widths):
        worksheet.set_column(i, i, width)

writer.save()

結(jié)果:

image-20201231163620090

有了一個(gè)合適的列寬,我看的舒服多了,至少我自己是滿意了,要用代碼加什么好看的樣式也簡(jiǎn)單,。

好了,現(xiàn)在開(kāi)始處理需求2:

讀取修改過(guò)的excel回填到word文檔中

讀取word并生成word模板

要回填到word文檔中,我們應(yīng)該事先生成能夠被doctpl解析的模板,我的思路是每個(gè)表格除了表頭以外全部刪除,然后動(dòng)態(tài)生成以下格式的模板:

xxxxxxxxx
{%tr for cells in rows0 %}
{{ cells[0] }}{{ cells[1] }}{{ cells[2] }}
{%tr endfor %}
{{ footers0[0] }}{{ footers0[1] }}{{ footers0[2] }}

到時(shí)候再直接根據(jù)excel的數(shù)據(jù)渲染就行,那么如何生成word模板呢?

直接看看我的代碼吧:

from docx import Document

def set_font_style(after_font_style, before_font_style):
    after_font_style.bold = before_font_style.bold
    after_font_style.italic = before_font_style.italic
    after_font_style.underline = before_font_style.underline
    after_font_style.strike = before_font_style.strike
    after_font_style.shadow = before_font_style.shadow
    after_font_style.size = before_font_style.size
    after_font_style.color.rgb = before_font_style.color.rgb
    after_font_style.name = before_font_style.name

doc = Document("test.docx")
for i, table in enumerate(doc.tables):
    # 緩存最后一行的行對(duì)象
    last_row = table.rows[-1]._tr
    # 刪除除表頭外的所有行
    for row in table.rows[1:]:
        table._tbl.remove(row._tr)
    # 表格添加一行,第一個(gè)單元格文本指定為指定的內(nèi)容
    table.add_row().cells[0].text = '{%tr for cells in rows'+str(i)+' %}'
    # 再添加一行用于保存中間的模板
    row = table.add_row()
    for j, cell in enumerate(row.cells):
        cell.text = '{{ cells[%d] }}' % j
    # 再添加一行用于保存endfor模板
    table.add_row().cells[0].text = '{%tr endfor %}'
    # 將直接緩存的最后一行添加到行尾
    table._tbl.append(last_row)
    # 表格的行尾修改完樣式后,還原回以前的樣式
    for j, cell in enumerate(table.rows[-1].cells):
        before_font_style = cell.paragraphs[0].runs[0].font
        cell.text = '{{ footers%d[%d] }}' % (i, j)
        after_font_style = cell.paragraphs[0].runs[0].font
        set_font_style(after_font_style, before_font_style)

doc.save("test_template.docx")

模板生成的效果:

image-20201231165752271

根據(jù)word模板回填word

有了模板就可以開(kāi)始根據(jù)模板回填word了,首先我把excel修改成這樣:

image-20201231170411064

就是一個(gè)表改了兩個(gè)值,另一個(gè)表刪了兩行,保存后,執(zhí)行以下代碼:

from docxtpl import DocxTemplate
import pandas as pd

tpl = DocxTemplate('test_template.docx')
excel = pd.ExcelFile("test.xlsx")
context = {}
for sheet_name in excel.sheet_names:
    data = pd.read_excel(excel, sheet_name).values
    context[f'rows{sheet_name}'] = data[:-1].tolist()
    context[f'footers{sheet_name}'] = data[-1].tolist()
tpl.render(context)
tpl.save('result.docx')

回填結(jié)果:

image-20201231171022970

好了,到現(xiàn)在為止,我個(gè)人覺(jué)得已經(jīng)大體上完成效果了,。當(dāng)然還不夠完美,很多樣式適配都還沒(méi)有去做,首先是行高丟失,然后是修改數(shù)值后的千分符丟失,這都要等正式開(kāi)發(fā)后去適配,我這里不公布正式開(kāi)發(fā)的代碼,。

總結(jié)

你對(duì)doctpl怎么看呢?歡迎你在下方評(píng)論或留言表達(dá)你的看法,。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多