作者:小小明

需求

有一个Excel文件:

需要按照题目和答案分别生成两个如下格式的word文档:

实现它的核心代码仅三行:

tpl = DocxTemplate("xxxx模板.docx")
tpl.render({'ps': df[columns].values.tolist()})
tpl.save("result/xxxx-yy.docx")

下面我们看看具体的实现过程:

实现过程

首先制作Word模板,编辑民法学必刷470题-题集模板.docx文件内容如下:

{%p for a,b,c,d in ps %}
第{{ a }}章 第{{ b }}节 第{{ c }}题
{{ d }}

{%p endfor %}

编辑民法学必刷470题-答案模板.docx文件内容如下:

{%p for a,b,num,answer,text in ps %}
第{{ a }}章 第{{ b }}节 第{{ num }}题
答案:{{ answer }}
知识:
{{ text }}

{%p endfor %}

可以根据需要,任意修改Word模板的样式,生成的内容都会跟着改变。

然后读取数据:

import pandas as pd
from docxtpl import DocxTemplate

df = pd.read_excel("《民法学》必刷分章练习-470题.xlsx")
df.sort_values(["章", "节"], inplace=True)
df
旧题号新题号解析参考答案
081形式意义上的民法指-\n\nA.民法典 \n\nB.所有调整民事关系的法律规范11【图】\n形式意义上的民法就是指民法典。法典是按照一定体系将各项法律制度系统编纂在一起的法律…A
112下列财产关系中属于民法调整的是-\n\nA.财政拨付关系\n\nB.赡养关系\n\nC.税收…12民法调整的社会关系的最本质特点在于其平等性,这是民法区别于其他部门法的根本特点。\n民法的调…B
223民法的调整对象是-\n\nA.财产关系和人身关系\n\nB.商品经济关系\n\nC.平等主体…12民法的调整对象是平等主体之间的财产关系和人身关系C
394下列对民法调整对象的表述正确的是-\n\nA.民法的调整对象是财产关系和人身关系\n\nB.…129.下列对民法调整对象的表述正确的是( B )\nA.民法的调整对象是财产关系和人身关系【需…B
4225根据民事法律关系是否直接具有财产利益的内容,民事法律关系可分为-\n\nA.财产法律关系与人…12考点:民事法律关系的分类A
465462456林某有儿子小强9岁,小强淘气异常。一日小强在邻居王某的鱼缸边玩耍时,另一邻居张某(成年人)对…502第一千一百六十九条 【教唆侵权、帮助侵权】教唆、帮助他人实施侵权行为的,应当与行为人承担连带…A
466466457小偷甲在某商场窃得乙的钱包后逃跑,乙发现后急追。甲逃跑中撞上欲借用商场厕所的丙,因商场地板湿…502第一千一百九十八条 宾馆、商场、银行、车站、机场、体育场馆、娱乐场所等经营场所、公共场所的经…AE
467467458甲搬家公司指派员工郭某为徐某搬家,郭某担心人手不够,请同乡蒙某帮忙。搬家途中,因郭某忘记拴上…502第一千一百九十一条 用人单位的工作人员因执行工作任务造成他人损害的,由用人单位承担侵权责任。…C
468468459甲饲养的一只狗卧在家门前,乙路过甲家前从路边拾起一块石头向狗砸去,狗被激怒后向乙扑去,乙躲闪…502饲养动物损害责任的归责原则\n《民法典》确定我国饲养动物损害责任的二元化归责原则体系,根据具…ABC
469469460下列情形可以适用精神损害赔偿的是-\nA.某公司连续一年未发工资,致职工甲忧心忡忡\nB.某…502精神损害赔偿的适用范围:\n一是侵害物质性人格权,可以请求精神损害抚慰金赔偿;\n二是侵害精…D

470 rows × 7 columns

此时再调用2次开头说的三行代码就可以了:

tpl = DocxTemplate("民法学必刷470题-题集模板.docx")
tpl.render({'ps': df[["章", "节", "新题号", "题"]].values.tolist()})
tpl.save("result/民法学必刷470题-题集.docx")

tpl = DocxTemplate("民法学必刷470题-答案模板.docx")
tpl.render({'ps': df[["章", "节", "新题号", "参考答案", "解析"]].values.tolist()})
tpl.save("result/民法学必刷470题-答案.docx")

生成结果:

至此,我们就完成了需求。

题目选项平衡

后面打印后,感觉题目空行太多,希望能去掉空行,并保持ABCDE选项的平衡。

一开始写了很多选项平衡算法,但感觉结果都还不够平衡不够美观,在考虑到选项最大5个选项后,我考虑的实现思路是:先判断前4个选项长度之和是否小于50,是的话合并到一行;否则判断,前2个选项的长度之和以及第3第4选项的长度之和,是否同时小于50,是的话,先将前2个选项合并,再将第3第4选项合并;否则前4个选项全部都不合并。最后判断是否存在第5个选项,存在的话尝试跟前面的选项合并,总长度小于50则应用合并。下面是实现代码:

titles = []
for row in df..str.split("\n+"):
    print(row)
    title = row[0].strip()
    options = [i.strip() for i in row[1:]]
    tmp = []
    if len('\t'.join(options[:4])) <= 50:
        tmp.append(options[:4])
    elif len('\t'.join(options[:2])) <= 50 and len('\t'.join(options[2:4])) <= 50:
        tmp.extend([options[:2], options[2:4]])
    else:
        tmp.extend([[i] for i in options[:4]])
    if len(options) == 5:
        if len("\t".join(tmp[-1]+[options[4]])) < 50:
            tmp[-1].append(options[4])
        else:
            tmp.append([options[4]])
    options = []
    for option_arr in tmp:
        options.append("\t".join(option_arr))
    print(title, options)
    titles.append("\n".join([title]+options))
df.= titles

重新生成题目Word文档:

tpl = DocxTemplate("民法学必刷470题-题集模板.docx")
tpl.render({'ps': df[["章", "节", "新题号", "题"]].values.tolist()})
tpl.save("result/民法学必刷470题-题集.docx")

结果:

感觉合并效果还不错。

完整代码:

import pandas as pd
from docxtpl import DocxTemplate

df = pd.read_excel("《民法学》必刷分章练习-470题.xlsx")
df.sort_values(["章", "节"], inplace=True)

titles = []
for row in df..str.split("\n+"):
    print(row)
    title = row[0].strip()
    options = [i.strip() for i in row[1:]]
    tmp = []
    if len('\t'.join(options[:4])) <= 50:
        tmp.append(options[:4])
    elif len('\t'.join(options[:2])) <= 50 and len('\t'.join(options[2:4])) <= 50:
        tmp.extend([options[:2], options[2:4]])
    else:
        tmp.extend([[i] for i in options[:4]])
    if len(options) == 5:
        if len("\t".join(tmp[-1]+[options[4]])) < 50:
            tmp[-1].append(options[4])
        else:
            tmp.append([options[4]])
    options = []
    for option_arr in tmp:
        options.append("\t".join(option_arr))
    print(title, options)
    titles.append("\n".join([title]+options))
df.= titles

tpl = DocxTemplate("民法学必刷470题-题集模板.docx")
tpl.render({'ps': df[["章", "节", "新题号", "题"]].values.tolist()})
tpl.save("result/民法学必刷470题-题集.docx")

tpl = DocxTemplate("民法学必刷470题-答案模板.docx")
tpl.render({'ps': df[["章", "节", "新题号", "参考答案", "解析"]].values.tolist()})
tpl.save("result/民法学必刷470题-答案.docx")

本文转载:CSDN博客