第二次作业
第二次作业Word Counter:命令行文本计数与扩展功能实现
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 26 软件技术基础 |
| 这个作业的目标 | 实现英文 TXT 统计,通过真实版本迭代、单元测试和运行截图展示开发结果 |
| 姓名—学号 | 吕文浩-2024329301058 |
| 码云仓库地址 | https://gitee.com/l-wenhao1226/word-counter |
| 最终交付版本 | v0.4 |
一、项目简介与完成情况
Word Counter 使用 Python 3.13 标准库实现,基础功能是统计纯英文 TXT 文件中的字符数、单词数和句子数。在此基础上,增加了 Python、C/C++ 源码行分类,以及多文件分析、词频、交互菜单、中文 GUI 和离线报告。
本项目保留命令行入口。课程中的 wc.exe -c file.txt 对应本项目的 python wc.py -c file.txt,其余统计参数同样通过脚本命令使用。
| 作业要求或增强内容 | 实际完成情况 | 主要证据 |
|---|---|---|
| 字符、单词、句子统计及命令参数 | 已完成 | 基础命令与特殊文本运行截图 |
| README:简介、用法、文件说明、运行结果 | 已完成 | 仓库 README |
| v0.1、v0.2、v0.3 多次真实提交 | 已完成,并继续迭代至 v0.4 | Git 历史和版本标签 |
| 基础单元测试及更多边界用例 | 完整测试集合 200 项,已有真实通过记录 | 测试截图及测试源文件 |
| 代码行、空行、注释行统计 | 已完成 | v0.3 源码统计截图 |
| 批量、词频、终端菜单、GUI、JSON/HTML | 已完成 | 批量、菜单、GUI、报告截图 |
| AI 提示词记录 | 已列出关键提示词精选 | 归档范围说明见第九节 |
二、开发环境与项目结构
2.1 开发环境
| 项目 | 实际使用情况 |
|---|---|
| 语言 | Python 3.13.7 |
| IDE | 中文 PyCharm 2025.2.2,Build PY-252.26199.168 |
| 终端 | Windows CMD |
| 版本管理 | Git 2.53.0.windows.3、Gitee |
| 自动化测试 | 标准库 unittest |
| 桌面界面 | tkinter/Tk |
| 报告 | JSON、离线 HTML/CSS/SVG |
| 第三方 Python 包 | 无需安装 |
选择 Python,是因为标准库已经提供参数解析、正则、词法分析、测试和 GUI 等所需能力,便于将注意力放在统计规则和工程组织上。使用 PyCharm 管理代码与运行配置,使用 Git 记录真实演进,而不是把所有功能一次性提交成一个版本。
2.2 文件结构与职责
.
├── wc.py # 命令行入口
├── counter.py # 字符、单词、句子统计
├── code_counter.py # Python/C/C++ 源码行分类
├── analysis.py # TXT 批量分析和词频结果模型
├── source_analysis.py # GUI 源文件集合分析
├── reports.py # 终端、JSON、HTML 报告
├── interactive.py # 终端交互菜单
├── gui.py # 中文桌面界面
├── gui_service.py # GUI 业务调用和后台任务
├── tests/ # 单元测试与 CLI 测试
├── samples/ # TXT、源码及批量演示样例
├── docs/ # 开发日志、AI 节选记录和真实截图
├── .gitignore # 排除缓存、虚拟环境等本地文件
├── .gitattributes # 保留样例原始换行
└── README.md # 项目说明
outputs/ 用于本地生成报告,已被 Git 忽略;新检出仓库时如需导出到该目录,应先创建它。具体统计算法位于核心模块,CLI、菜单、GUI 负责输入与展示,不各自实现一套分词或句子算法。
三、真实版本演进
3.1 四个版本的功能边界
| 版本 | 实际功能范围 | 标签对应提交 |
|---|---|---|
| v0.1 | 空项目:README、忽略规则、开发日志及 AI 记录,没有统计代码 | 395d57959252b885c075eba196e70677c59f8f44 |
| v0.2 | 字符、单词、句子统计,命令参数和基础测试 | dc656c50dece5698b33d3af9e6846fe16a885674 |
| v0.3 | Python/C/C++ 代码行、空行、注释行分类及扩展测试 | fc0342c23c723ee819c8f06ce7dd796eff36edef |
| v0.4 | 批量、高级分析、终端菜单、JSON/HTML 和中文 GUI,完成交付文档 | ecb488e1ead06cd607e925146804a9ecea6f8349 |
v0.1 先明确工程边界与文档;v0.2 把英文文本统计口径落实为可测试规则;v0.3 增加源码词法分类;v0.4 在原核心上增加新的输入和展示方式。原计划单独安排的 GUI 后来统一纳入 v0.4。

图1:v0.1空项目结构与当时的README
3.2 实际提交记录
以下为仓库已有的真实提交摘录,按时间顺序列出:
395d579 chore: initialize empty project (v0.1)
357c22a docs: archive v0.1 screenshots and AI collaboration notes
ddfa48e docs: finalize v0.1 audit corrections
dc656c5 feat: implement v0.2 basic text counting with tests
fc0342c feat: add Python and C++ source line statistics
51faf38 feat: add batch text analysis and offline reports
c6f38d6 feat: add Chinese desktop GUI and shared code reports
ecb488e docs: finalize v0.4 course delivery
最终文档提交和 v0.4 附注标签已推送到 Gitee,旧标签保持原位。封版时本地与远程 master 一致,工作区干净。可在 v0.4 仓库 查看交付内容,在 提交历史 查看多次提交。
四、基础统计规则与命令行运行
4.1 字符数
字符数统计解码后的 Unicode 码点数,不是文件字节数。空格、制表符和标点均计入;保留原始换行,CRLF 计 2 个字符,LF 计 1 个字符。按 UTF-8 严格读取,文件开头的 UTF-8 BOM 不计入正文。空文件为 0;编码错误明确报错。
4.2 英文单词数
单词识别使用同一条规则:
[A-Za-z]+(?:['’\-][A-Za-z]+)*
以 ASCII 英文字母为主体,字母组之间允许单个内部撇号或连字符。
| 输入 | 单词数 | 原因 |
|---|---|---|
don't、well-known |
各 1 | 允许单个词内连接符 |
well--known |
2 | 连续连字符形成边界 |
123 |
0 | 数字不构成英文单词 |
abc123def |
2 | 数字将两段英文字母分开 |
hello!!! |
1 | 末尾标点不构成额外单词 |
| 纯标点、空白、空文件 | 0 | 没有合法词元 |
这也是不能简单按空格切分的原因:标点和数字可能构成词边界,而词内撇号、连字符又可能属于同一个词。
4.3 句子数
句子统计采用规则识别:连续 .?! 只形成一个句末边界;数字之间的小数点不分句;常见缩写中的句点受到保护;片段至少含一个 ASCII 字母或数字才视为有效句子。文件末尾有有效文本而没有句末标点时,仍计一句。
| 输入 | 句子数 |
|---|---|
Really?! |
1 |
Dr. Smith is here. |
1 |
The value is 3.14. |
1 |
Wait... What happened? |
2 |
An unfinished sentence |
1 |
| 空白或纯标点 | 0 |
缩写表包含 mr.、mrs.、ms.、dr.、prof.、sr.、jr.、st.、e.g.、i.e.、etc.、vs.、fig.、no.,并保护 U.S. 一类多段字母缩写。句末引号和括号不会单独增加句数。这比直接数句号更符合本项目确定的规则,但不等同于完整自然语言理解。
4.4 基础命令与真实结果
在项目根目录运行:
python wc.py -c samples/basic.txt
python wc.py -w samples/basic.txt
python wc.py -s samples/basic.txt
python wc.py -a samples/basic.txt
python wc.py -c -w -s samples/basic.txt
python wc.py -h
samples/basic.txt 的正文为下面两行,使用 LF,末尾没有换行:
Hello world.
How are you?
已有实际运行结果为:
Characters: 25
Words: 5
Sentences: 2
图2:基础命令行统计结果

含特殊英文标点的真实样例:
Dr. Smith said, “Don't panic!”
The value is 3.14. Really?!
Wait... What happened? A well-known fact
该文件包含三个 LF,运行命令及已有结果为:
python wc.py -a "samples/special punctuation.txt"
Characters: 100
Words: 15
Sentences: 6
图 3:组合参数及缩写、小数、省略号等特殊文本的运行结果。

未指定统计选项、路径不存在、文件不可读或编码错误时,程序明确提示并以非零退出码结束。带空格的命令行路径使用英文双引号。
五、扩展功能:代码行、空行与注释行
5.1 指标与接口
支持 .py、.c、.h、.cpp、.hpp:
python wc.py --mode code --code-stats samples/source_python.py
python wc.py --mode code --code-stats samples/source_c.c
python wc.py --mode code --code-stats samples/source_cpp.cpp
python wc.py --mode code -l -b -m samples/source_cpp.cpp
-l 为总物理行,-b 为空行,-m 为纯注释行;--code-stats 展示全部七项。
四种基础分类互斥,满足:
总物理行 = 空行 + 纯代码行 + 纯注释行 + 混合行
代码行总数 = 纯代码行 + 混合行
含注释行总数 = 纯注释行 + 混合行
空文件为 0 行,末尾换行不产生额外一行。CRLF/LF 按一个物理换行处理,空白行优先归为空行,包括块注释内部的完全空白行。
5.2 识别方法与结果
Python 使用 ast.parse 和 tokenize,区分字符串与 # 注释,三引号字符串按代码处理,分析时不执行输入文件。C/C++ 通过词法状态扫描区分代码、//、/* ... */、字符串和字符字面量,并处理跨行注释及常见转义。
| 样例 | 总行 | 空行 | 纯代码 | 纯注释 | 混合 | 代码总数 | 含注释总数 |
|---|---|---|---|---|---|---|---|
| Python | 14 | 3 | 7 | 2 | 2 | 9 | 4 |
| C | 6 | 0 | 4 | 1 | 1 | 5 | 2 |
| C++ | 12 | 2 | 4 | 3 | 3 | 7 | 6 |
这些结果已在正式项目实际运行,并与预先逐行确定的分类核对。
图4:C和C++代码行分类

六、v0.4 增强:批量分析、词频、交互与报告
6.1 多文件、目录和汇总
python wc.py -a samples/batch/a.txt samples/batch/b.txt
python wc.py --batch -a samples/batch
python wc.py --batch -a --recursive samples/batch
目录默认只扫描当前层 TXT,--recursive 扫描子目录。规范化路径去重,逐文件结果按确定性路径顺序展示;同一文件经目录和显式路径重复指定时,只统计一次。
| 已有实际场景 | 成功文件 | 字符 | 单词 | 句子 | 全局唯一词 |
|---|---|---|---|---|---|
| 顶层两文件 | 2 | 40 | 6 | 3 | 3 |
| 递归包含子目录 | 3 | 48 | 7 | 4 | 3 |
| a.txt 加缺失文件 | 1 | 21 | 3 | 2 | 2 |
图 5:批量分析与汇总。

各文件独立统计后累加字符、单词、句子,不跨文件拼接正文。批量词频合并后再计算全局唯一词数,不能直接把每个文件的唯一词数相加。部分文件失败时保留成功结果,并列出失败项;全部失败不生成虚假的零汇总。
6.2 词频与交互菜单
python wc.py --advanced --top 3 --visualize samples/batch
python wc.py --interactive
词频复用原单词规则,并统一小写;排名按次数降序、词元升序,保证并列时结果确定。词长只计 ASCII 字母,不含内部撇号或连字符。平均词长按出现次数加权;平均句子词数为总词数除以总句数。无单词时均值为 0,最长词为空,不触发异常。
顶层两文件的实际词频为 apple=3、banana=2、cherry=1;最长词为 banana,平均词长 5.50,平均句子词数 2.00。
终端菜单提供路径选择、分析类型、统计显示、高频词图和报告导出,支持返回、退出及无效输入提示。
图 6:终端交互菜单中与高频词

6.3 JSON 与离线 HTML
首次检出仓库时,如果还没有 outputs 目录,在 CMD 中先创建,再导出:
if not exist outputs mkdir outputs
python wc.py --format json --output outputs/v0.4-results.json samples/batch
python wc.py --format html --top 3 --output outputs/v0.4-report.html samples/batch
JSON 包含逐文件结果、汇总、词频和失败列表,格式可解析。输出 JSON 到标准输出时,不混入菜单或保存提示。HTML 使用本地 CSS/SVG 展示摘要、逐文件结果、高频词和词长分布,离线可打开;路径、标题和错误信息经过 HTML 转义。
GUI 和 HTML 的图表来自同一份统计结果,图形从零开始,并显示数值标签,不只用柱长表达结果。
七、中文 GUI 与手动验证
启动命令:
python gui.py
界面支持单文件、多文件、文件夹、文本/源码模式和递归选择,结果分为逐文件、汇总图表、失败输入三个页面,并提供 JSON/HTML 导出及浏览器预览。
分析与导出在后台线程执行,工作线程只把普通结果或异常放入队列,主线程通过 after 处理界面更新。修改输入后清除旧结果,避免把上一次分析当成本次结果导出。
图 7:TXT 目录汇总与高频词图,40 字符、6 单词、3 句。

图 8:中文GUI源文件统计


图 9:部分失败时保留成功结果

图 10:离线HTML报告

实际人工操作中发现过底部导出栏被表格挤出可视区域的问题。随后调整布局,先预留底栏空间,再分配表格区域,并做了两种窗口尺寸的专项检查;更新后的界面已显示导出按钮。这是布局修正,没有修改统计规则。
八、单元测试与验证依据
8.1 测试组织
使用标准库 unittest,运行方法为:
python -m unittest discover -s tests -v
| 测试文件 | 测试方法数 | 重点 |
|---|---|---|
| test_counter.py | 17 | 文本统计规则及边界 |
| test_cli.py | 18 | 单参数、组合参数、路径、编码及错误处理 |
| test_code_counter.py | 44 | 源码词法、换行和分类等式 |
| test_code_cli.py | 19 | 代码命令参数及旧接口兼容 |
| test_analysis.py | 29 | 批量、递归、去重及全局汇总 |
| test_batch_cli.py | 24 | 批量 CLI、输出格式和失败场景 |
| test_interactive.py | 12 | 菜单流程与无效输入 |
| test_reports.py | 14 | JSON、HTML、转义及展示一致性 |
| test_gui_service.py | 23 | GUI 业务、CLI 一致性、代码报告和后台任务 |
| 合计 | 200 | 部分方法还使用多组子用例 |
测试覆盖空文件、空白/纯标点、词内连接符、缩写、小数、句末符号、CRLF/LF、BOM、非法编码、路径不存在、跨行注释、字符串内注释标记、批量部分失败,以及 JSON/HTML 与共享模型的一致性。
预期结果先依据确定的统计规则计算,再用于验证程序,不根据程序错误输出反向调整预期。GUI 业务测试还与真实 CLI 子进程输出进行比对,而不只是重复调用同一个函数后比较自身。
8.2 实际测试结果
正式项目中保存的最后一次完整测试输出为:
Ran 200 tests in 4.274s
OK
图 11:正式项目完整单元测试的真实通过记录

上述完整测试发生在最后的 GUI 底栏布局修正之前。此后统计核心、业务层、CLI 和测试用例未变,布局另有专项检查及人工验证。最终封版只收尾文档,没有重跑测试,也不将此记录描述为最终标签提交上重新运行的结果。
8.3 性能分析加分项
本项目没有完成 PyCharm Profiler 性能分析。开发过程中曾准备固定输入和运行配置,随后取消该非必要加分项,没有取得真实热点函数、Profiler 快照或 IDE 性能分析结果,因此不把普通计时或测试耗时作为该加分项证据。
九、AI 使用说明与提示词归档
本项目开发过程中使用了 AI:Codex 参与需求拆分、代码与测试生成、文档整理、命令指导;使用者在本机执行运行、测试、截图、Git 提交和推送,并反馈实际结果。阶段任务中也使用 ChatGPT 审核和调整开发范围。本文由 AI 协助整理,运行和提交证据来自实际项目记录。
现有 AI 协作记录 明确区分实际开发指令节选、关键对话摘录、过程摘要和事后优化稿。以下按开发目标选取实际发送过的关键指令,不代表全部提示词,也不表示消息发送者一定是指令的最初撰写者。
9.1 控制版本范围
本轮严格只完成 v0.1 空项目初始化,不实现任何文本统计功能。
这条指令先限定 v0.1 为空项目,再通过后续真实提交逐步增加功能,避免一次性完成所有代码后伪造演进。
9.2 分离核心与界面
使用 Python 3.13 标准库,保持统计核心和 CLI 分离,便于后续 v0.3、GUI 和可视化复用。
这是 v0.2 开发指令中的要求,后续 CLI、菜单、GUI 和报告复用了共享统计与分析结果。
9.3 先确定规则,再检查测试
确保测试预期依据事先确定的统计规则,而不是根据程序错误输出反向修改测试答案。
不准针对单个测试字符串硬编码答案。
这些要求用于约束句子规则和边界测试,避免只让某个演示字符串得到指定答案。
9.4 正确合并批量结果
批量汇总时,词频合并后计算全局唯一单词数,不能简单相加各文件的唯一单词数。
这条指令强调了跨文件重复单词的处理方式,最后用共享词频模型实现汇总。
9.5 保持 GUI 线程安全
较耗时任务应避免阻塞 GUI 主线程,界面更新必须遵守 tkinter 的线程安全要求。
因此采用后台任务加队列,由主线程处理控件更新。
9.6 保留真实历史与证据
不得强制推送、修改已有标签、伪造提交或重新制造版本历史。
不得伪造截图。
9.7 实际协作方式与归档范围
这些我来操作,你给指导
pycharm是中文的
不得伪造截图。
本篇采用关键提示词精选的展示方式。引文来自实际消息,旁边的用途解释是本次整理的过程摘要,不能当作历史原话;仓库中的事后优化稿也不作为原始指令。
归档范围说明:本文与仓库记录均为节选,没有完整收录全程实际提示词。因此不能宣称已经完全满足老师“附上所有对话提示词”的要求;如果按全量归档验收,仍需从原会话补存真实原文,精选和事后优化稿不能替代。
十、已知限制与开发体会
句子统计属于规则识别,缩写恰好位于真实句尾时可能少计,未收录缩写、网址或邮箱中的句点可能多计。输入统一为 UTF-8,不自动猜测其他编码。Python 源码要求当前解释器可以解析,C/C++ 不做宏展开、条件编译或完整语法检查,特殊原始字符串的反斜杠物理续行暂不支持。
这次项目中,较重要的工程选择是先明确“统计什么”,再验证结果。字符与字节、物理行与逻辑行、唯一词数与词频累加都不能混用。把规则放在共享核心后,新增命令行选项、菜单、GUI 和报告时,可以复用相同结果,并通过测试检查一致性。
从 v0.1 空项目到 v0.4,Git 记录保留了功能和交付材料的真实演进。最终代码、README、开发日志、测试和截图已上传,四个版本标签均指向实际提交。Profiler 不作为已完成成果,AI 记录按关键提示词精选展示,保留与全量归档要求之间的差异说明。

浙公网安备 33010602011771号