20252302 2025-2026-2 《Python程序设计》实验4报告
20252302 2025-2026-2 《Python程序设计》实验4报告
课程:《Python程序设计》
班级: 2523
姓名: 邢城瑜
学号:20252302
实验教师:王志强
实验日期:2026年6月13日
必修/选修: 公选课
一、实验内容
自动化公文格式检测程序(公文标准采用DKY公文格式)
二、实验分析
公文需要严格遵照公文格式,但公文格式条目较多,检查起来费时费力(还容易出错),我希望制作一个公文格式检测程序,检测现有docx公文是否符合公文格式,以节省人工反复校验的时间。
同时,公文校验相对比较简单,只要学习python-docx API相关知识和部分XML的知识即可,无需像网络渗透工具一样精通网络、通信等各领域知识,更适合人工实现。
本实验设计思路以及命令行工具由人类实现(好像叫什么邢城瑜),GUI由大模型实现。
三、实验设计
公文格式有许多条要求,其中部分功能较难实现。为此需要明确各格式校验路径,再判断是否在编写能力范围内、是否必要。
3.1 功能实现的依赖
构想以使用python-docx API为主,直接使用XML为辅
3.2 功能分类
(参考:公文要求(ver2025).docx,在作业zip中)
预想实现功能从具体类别上可以分为以下四类:页面设置、标题设置、正文设置、表格设置,
通过了解python-docx和XML现成功能,可讲所有小功能从实现方式上分为以下四类:
1.能直接调用python-docx实现的,非常简单
这里包含页面设置(上下左右边距)、大标题与正文的部分设置(字号、对齐方式、行间距、段前段后间距、文本前后缩进、首行缩进)、表格中的部分设置(字号、行距)
2.需深入到XML实现
各部分字体、字符间距,表格中的水平/垂直对齐
3.python-docx和XML结合实现
各级标题实现
4.不易实现,暂时跳过
上下文极其复杂类:标题上空2行下空1行、附件格式、落款格式
实现极其繁琐:表格行高、特殊标点、表格内两字词空格
各功能实现思路
Document()读入文件->识别不同信息分别为页面设置、标题设置、正文设置、表格设置并四个函数(check_page_margins()、check_title()、check_body_paragraphs()、check_tables())分别进行处理。每一函数内部对于需要用不同方式(python-docx OR XML)处理的要素就分别处理即可,最终print_report()打印报告
┌─────────────────────────────────────┐
│ 全部待检查功能 (36项) │
└─────────────────┬───────────────────┘
│
┌─────────────┬───────────────────────┼───────────────────┬
▼ ▼ ▼ ▼
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌───────────────────┐
│ 直接调用 │ │ 深入XML │ │ API+XML │ │ 暂时不实现的功能 │
│python-docx│ │ 实现 │ │ 结合 │ │ │
│ (16项) │ │ (8项) │ │ (1项) │ │ │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬───────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────┐
│ 页面边距4项 │ │ 各级字体6项 │ │ 各级标题 │ │ 上下文过于复杂 │
│ 标题字号 │ │ 字符间距2项 │ │ 字体+字号 │ │ 标题空行/附件/落款 │
│ 正文字号 │ │ │ │ 识别与检查 │ │ │
│ 对齐方式3项│ │ 表格对齐3项 │ └────────────┘ │ 实现过于繁琐 │
│ 行间距3项 │ │ │ │ 表格行高/特殊标点 │
│ 段间距3项 │ │ │ │ 两字空格 │
│ 缩进4项 │ │ │ └────────────────────┘
│ 表格字号 │ │ │
│ 表格行距 │ │ │
└────────────┘ └────────────┘
API直接拿 (16项): XML挖 (8项): API+XML (1项):
例: pf.alignment → 居中 例: get_cn_font() 例: 各级标题
pf.line_spacing → Pt(29) → rFonts.eastAsia → get_cn_font取字体类型
section.top_margin → Cm(3.6) get_latin_font() → run.font.size取字号
→ rFonts.ascii/hAnsi → 字体+字号联合判断角色
get_char_spacing()
→ spacing.val / 20
get_table_horizontal_align()
→ tblPr.jc.val
get_cell_vertical_align()
→ tcPr.vAlign
_is_in_table()
→ 沿XML树爬祖先
四、实现过程
代码分层设计概览
自上而下:上层可调用下层,下层不调上层
同级可互调
┌──────────────────────────────────────────────────────────────────┐
│ 第七层 入口层 (main) 行714-734 1个函数 │
├──────────────────────────────────────────────────────────────────┤
│ 第六层 报告输出层 (print_report) 行668-708 1个函数 │
├──────────────────────────────────────────────────────────────────┤
│ 第五层 调度层 (check_document) 行646-662 1个函数 │
├──────────────────────────────────────────────────────────────────┤
│ 第四层 四大检查层 行207-640 4个函数 │
│ check_page_margins check_title │
│ check_body_paragraphs check_tables │
├──────────────────────────────────────────────────────────────────┤
│ 第三层 正文单项检查层 行470-537 8个函数 │
│ _check_body_cn_font _check_body_latin_font │
│ _check_body_size _check_body_alignment │
│ _check_body_first_line _check_body_line_spacing │
│ _check_body_spacing _check_body_indent │
├──────────────────────────────────────────────────────────────────┤
│ 第二层 结果数据层 行183-201 2个方法 │
│ CheckResult CheckReport.add / summary │
├──────────────────────────────────────────────────────────────────┤
│ 第一层 工具函数层 行77-177 10个函数 │
│ 字体挖掘: get_cn_font get_latin_font │
│ 间距挖掘: get_char_spacing │
│ 单位转换: emu_to_cm 对齐映射: align_to_str │
│ 表格属性: get_cell_vertical_align get_table_horizontal_align │
│ has_text_wrapping │
│ 角色识别: _is_in_table _find_title_para │
├──────────────────────────────────────────────────────────────────┤
│ 第零层 常量层 行26-70 │
│ 页面边距 大标题标准 正文标准 标题标准 表格标准 │
└──────────────────────────────────────────────────────────────────┘
4.1 入口(读取文件)
命令行入口,输入路径以使用,做了一点错误提示,其中链接校验函数

校验函数,分别调用几个功能检查函数
4.2 预写通用工具函数(用来挖数据)(提前写了避免后续重复写)
4.2.1 XML挖属性
获取中文字体

获取西文字体类似,不再赘述
字符间距检查

4.2.2数据转化
emu转厘米

对齐样式转中文

4.2.3 表格归属类
单元格垂直对齐、表格水平对齐、表格文字环绕

判断段落是否在表格里
_is_in_table(para)的逻辑说明:从当前段落出发向上爬,碰到<w:tbl>就说明在表格里,如果一直没找到就不在表格里。
设计这个函数的原因在于,不是所有段落都是正文。没有这个函数,表格里的所有段落都会被当成正文检查,然后报一大堆"表格内容仿宋小四不对(应为仿宋三号)"的误报。
4.3对每个段落确定其角色(标题?正文?表格内文字?)

4.4 分别写不同角色的对应函数
4.4.1 页面设置check_page_margins()
这部分最简单,直接调用python-docx写思路中预设的check_page_margins即可,利用API中section.xxx_margin直接拿,对比逻辑是简单的abs(实际 - Cm(3.6)) < Cm(0.05) (这里以上边距为例),留了一点容错

4.4.2 大标题设置check_title()
首先定位标题段落,然后再提取所有文字片段

之后分python-docx和XML两种类别分别实现不同要素(字体、间距等)的检验
python-docx实现的部分
字号实现,利用API中run.font.size(所有字号必须为二号(22),容差为一磅)
对齐方式实现,利用API中pf.alignment

行间距实现,利用API中pf.line_spacing_rule和pf.line_spacing(验证rule==EXACTLY且值约为Pt(29))

段前段后实现,利用API中pf.space_before和pf.space_after,这里特意做了None保护

前后缩进实现,利用API中pf.left_indent和pf.right_indent,还经过预写函数emu_to_cm进行格式转换,设置容差为0.1cm

首行缩进实现,利用API中pf.first_line_indent和上面的预写函数emu_to_cm实现

字符间距实现,值必须为None(未设置)或者0

XML实现部分
中文字体
调用预写工具函数get_cn_font,然后逐个检查

西文字体同理,不再赘述。
4.4.3正文设置check_body_paragraphs()
思路和4.4.2的标题大致相同,先定位,然后调用八个三项函数分别检验字体、字号、对齐等要素,分别输出检查结果。

由于代码简单且思路与4.4.2中的几个单向函数思路重复,为重复性工作,故这里不再详细放出八个单项函数。
4.4.4 表格check_tables()
基本逻辑一致,筛选出对应数据为表格后分别调用水平对齐函数get_table_horizontal_align(table)、文字环绕函数has_text_wrapping(table)和垂直居中函数get_cell_vertical_align(cell),对于单元格内内容,调整字体字号和行距即可。


4.5 LLM生成GUI
模型使用deeepseekV4 pro
生成GUI,
五、实现结果
最终完成了一个命令行工具(手搓)和一个对应的GUI(deepseek),可以初步检测docx类型文档是否符合公文格式
5.1 命令行工具(Powered by XCY)
在终端中输入python Format_Checker.py并按提示手动输入被检测文件的路径即可
测试样例:一个正常的不完美的docx文件

测试成功嘿嘿嘿
5.2 GUI工具(made by DeepseekV4pro)
GUI工具可以通过“浏览”来找寻文件,无需手动寻找路径(但是需要手动浏览,但还是方便多了),同时还可以导出txt形式的报告
界面如下

测试文档:

导出报告:

六、实验中遇到的困难与解决、实验收获
困难与解决
1.中文字体读不出来,遇到中文时run.font.name 永远只返回 'Times New Roman',原来word把中文字体单独存在w:eastAsia,英文存在w:ascii,python默认只读英文的那个
解决:发现run._element能进底层XML,一层层往下找w:rPr → w:rFonts,再 .get('w:eastAsia')才拿到中文字体
这说明python-docx库的封装也可能有问题,可能需要人工处理(百行代码消耗一个鸡蛋糕)
2.程序莫名其妙崩溃
人工校验没发现,然后扔给AI校验一下,发现是对None的逻辑问题,pf.space_before.pt 报了 AttributeError:NoneType。我的判断逻辑是"None算通过",但写报错信息时没想过它可能是None,直接 .pt 了
解决:在每个对应的执行前加了一个判断,如果是None直接输出‘未设置’而不是直接崩溃。()
3.旧版代码中表格段落被按照正文处理。
发现原因:没有正确定位哪些段落在表格中、哪些是真正的正文段落。
解决:python-docx的Paragraph对象没有直接判断的接口,询问AI后明白修正思路:通过检索<w:tbl>来判断是否在表格中。
实验收获
1.第三方API不一定全,如果用不了就只能手动编写。
2.需要养成良好的封装习惯,在本实验中体现为任何拿到的值都得先看是不是None,否则可能出现“点了一碗炒饭然后程序炸了”的情况。
3.校验类工具难点不在校验而在于繁琐的分类。
七、课程总结、感想体会与建议
课程总结
强哥教的Python课覆盖以下知识点:简单语法、序列、函数、字符串、异常处理、调试、socket通信、简单爬虫等。其中,部分知识点做了实验,完成了简易计算器、简易猜测游戏等简单程序,还有一些略有实用性的socket通信、敏感词过滤等工具。在这些工具编写中,python的“轻量化”体现得淋漓尽致:字少。
分几个我印象深刻的知识点来说:
初识python时“蛋炒饭盖浇饭”的比喻让当时只学过C语言的我对不同语言之间的分类有了形象的理解
类与对象的一课“水果”和具体水果的比喻让我明白了python语言中类与对象的方便
socket通信实验中顺便了解了通信相关知识(还不小心因为没关防火墙闹了笑话)
总体来讲,课程内容丰富,强哥讲解诙谐幽默,很有个人魅力。
课程感悟
当初选这门课时,是在学CTF过程中发现还是需要掌握一些简单的脚本技能,而这些脚本大多都是python写的,这些脚本可以节省大量时间,便因此报了强哥久享盛誉的python课,也确实学到了不少东西,例如socket通信、爬虫,这些都是在大一上的C语言中没有接触过的东西,让我真正感受到技术应用到实际的落地的安心感。但一学期学下来,总有一种越学不会的东西越多的感觉,说明自己还是有很多很多需要了解的吧。
本次选题是基于我日常干学生工作时的实际需求(人工机械校对挺耗精力的)。
本次综合实验也把我之前很多学的东西串了起来,而且做成一个小项目还挺有成就感的。
课程建议
总体来讲课程节奏和内容充实度适中,形象生动、风趣幽默,看来学长学姐没推荐错~
至于建议,可以适当增加“边带着敲代码边讲解”的教学方式比重,感觉对于学时不算太多的晚课,在提升学生能力上还是挺有用的。

浙公网安备 33010602011771号