第二次作业:C++ 命令行文本计数统计程序
第二次作业:C++ 命令行文本计数统计程序
| 项目 | 链接或说明 |
|---|---|
| 所属课程 | 26软件技术基础 |
| 作业要求 | 第二次作业 |
| 码云仓库 | https://gitee.com/Gggffxu/second-assignment |
| 作业目标 | 实现英文文本计数,使用 Git 记录版本,完成单元测试和 IDE 性能分析 |
| AI 使用情况 | 本项目的代码、测试、说明及本篇博客由 AI 辅助生成,详见文末提示词记录 |
一、项目简介
本项目使用 C++17 实现命令行文本计数工具 wc.exe,可以读取 ASCII 纯英文 TXT 文件,统计字符数、单词数和句子数。在基础功能之外,还支持 C/C++ 风格代码行、空行和注释行统计。
程序将文件读取、参数处理和计数逻辑分开:main.cpp 处理命令行与文件输入,counter.cpp 实现计数,tests.cpp 对核心函数进行测试。这样可以直接测试计数逻辑,不必为每个用例都启动一次命令行程序。
二、功能与命令接口
命令格式为:
wc.exe [参数] [文件名]
| 参数 | 功能 | 示例 |
|---|---|---|
-c |
统计字符数 | wc.exe -c sample.txt |
-w |
统计单词数 | wc.exe -w sample.txt |
-s |
统计句子数 | wc.exe -s sample.txt |
-l |
统计代码行 | wc.exe -l counter.cpp |
-b |
统计空行 | wc.exe -b counter.cpp |
-n |
统计纯注释行 | wc.exe -n counter.cpp |
-a |
输出全部统计项 | wc.exe -a sample.txt |
--help |
查看帮助 | wc.exe --help |
参数可以组合,例如 wc.exe -c -w -s sample.txt。文件名放在最后,路径中含有空格时需要加双引号。退出码为 0 表示成功,1 表示文件或编码错误,2 表示参数错误。
统计规则
为了便于实现和验证,本项目明确采用以下规则:
- 字符数:包含英文字母、数字、空格、标点、制表符和换行字节。ASCII 文本中一个字节计一个字符,Windows 的 CRLF 换行计两个字符。
- 单词数:连续英文字母计一个单词,字母之间的撇号属于单词的一部分,因此
Don't计一个单词。连字符分隔单词,例如well-known计两个;纯数字不计单词。 - 句子数:连续出现的
.?!终止标点计一次,例如...和?!各计一次。没有终止标点的片段不计句子。本项目没有实现缩写和小数等语义识别。 - 行分类:纯空白行计空行,包含代码的行计代码行,其余纯注释行计注释行。一行同时包含代码和注释时计代码行,三类互斥。
扩展功能可以识别 // 和跨行 /* */ 注释,并忽略普通字符串及字符字面量里的注释符号。空文件计零行,文件末尾的换行不额外增加空行,块注释内部的纯空白行仍计空行。
三、项目文件说明
| 文件或目录 | 说明 |
|---|---|
main.cpp |
命令行参数校验、读取文件、输出结果 |
counter.h |
定义统计结果结构及计数函数接口 |
counter.cpp |
字符、单词、句子和行分类算法 |
tests.cpp |
25 个核心函数单元测试 |
test_cli.ps1 |
8 个命令行集成测试 |
build.ps1 |
编译程序并执行测试 |
sample.txt |
不含末尾换行的 Hello world! 示例 |
benchmark.cpp |
性能基准,支持指定重复次数 |
profile.ps1 |
编译采样程序、收集数据和生成报告 |
word-counter.cbp |
Code::Blocks 性能分析工程 |
evidence/ |
各版本日志、截图及原始采样证据 |
README.MD |
项目介绍、用法、文件说明和运行结果 |
PERFORMANCE.md |
IDE 性能分析方法、结果与局限 |
AI_PROMPTS.md |
本次项目的用户提示词记录 |
四、编译与运行结果
在 Windows 中准备好 MinGW-w64,并将其 bin 目录加入当前终端的 PATH。进入项目目录后,可以执行:
powershell -NoProfile -ExecutionPolicy Bypass -File .\build.ps1
也可以手动编译和运行:
g++ -std=c++17 -O2 -Wall -Wextra main.cpp counter.cpp -o wc.exe
.\wc.exe -c -w -s sample.txt
.\wc.exe -a sample.txt
sample.txt 的内容是 Hello world!,不含末尾换行。执行全部统计后得到:
characters: 12
words: 2
sentences: 1
code_lines: 1
blank_lines: 0
comment_lines: 0
这里的 code_lines: 1 表示该行既非空白行,也非纯注释行;行分类功能是对输入的文本进行词法分类,并不会判断一行是否真的是可以编译的 C++ 代码。
五、Git 版本迭代
项目通过多次真实提交记录迭代过程,保留了作业要求的三个标签。
| 版本 | 提交号 | 实现内容 |
|---|---|---|
| v0.1 | 6c89862 |
初始化空项目,未跟踪源文件 |
| v0.2 | 688ca60 |
完成基础计数、命令行输入和 10 个基本单元测试 |
| v0.3 | a3ee4ac |
增加三种行数统计,扩展为 25 个单元测试和 8 个命令行测试 |
后续提交补充了截图、提示词记录与 IDE 性能分析,没有移动或改写上述标签。可在仓库中执行以下命令查看:
git log --oneline --decorate
git tag
以下版本截图是实际运行日志在记事本中的显示截图,原始文字日志也在仓库中保留,便于核对;它们不是终端现场截图。v0.2 的运行结果来自该标签源码重新编译后的程序。
v0.1:空项目验证。

v0.2:基础计数与基本测试。

v0.3:扩展统计、测试及提交记录。

六、单元测试与命令行测试
核心函数测试使用独立的 tests.exe,通过比较实际统计值和期望值验证结果;不一致时抛出异常并让测试失败。命令行测试由 test_cli.ps1 调用程序,检查输出和退出码。
| 类别 | 代表用例 | 检查内容 |
|---|---|---|
| 空输入 | 空字符串、空文件 | 各项计数为零 |
| 基础英文 | Hello world! |
字符 12、单词 2、句子 1 |
| 句末标点 | One. Two? Three! |
三个句子 |
| 撇号与连续标点 | Don't stop... Really?! |
三个单词、两个句子 |
| 边界字符 | 空白、制表符、CRLF、纯数字 | 空白与换行按既定规则计数,数字不计单词 |
| 单词边界 | well-known、连续撇号 |
验证分词边界 |
| 较长输入 | 100000 个连续字母 | 字符数 100000、单词数 1 |
| 行分类 | 行注释、块注释、代码和注释混合 | 验证三类行数互斥 |
| 字面量 | 字符串或字符中的注释符号 | 避免误判为注释 |
| 错误输入 | 未知参数、缺少参数、文件不存在、非 ASCII 文件 | 检查错误处理与退出码 |
实际运行结果为:
PASS: 25 unit cases
PASS: 8 CLI cases
总计 33 项测试通过。这些用例覆盖了当前实现的规则,但不意味着程序实现了完整的英文语法分析或 C++ 语法分析。
七、IDE 附带工具的性能分析
本项目使用 Code::Blocks 25.03 官方发行版附带的 Code Profiler。它是 GNU gprof 的图形界面,可在 IDE 的 Plugins → Code profiler 中打开。官方用户手册的 Code profiler 一节介绍了该工具。
测试方法
基准程序先将一行英文文本重复 200000 次,构造 4600000 字节的输入。随后对同一段内存调用 count_text 500 次,累计统计返回值作为校验。
采样构建和数据收集命令为:
powershell -NoProfile -ExecutionPolicy Bypass -File .\profile.ps1 -Iterations 500
采样完成后,在 Code::Blocks 中打开 word-counter.cbp,选择 Profile 目标,执行 Plugins → Code profiler,查看 Flat Profile,再通过 Export to File 导出报告。分析针对的是内存中的计数函数,不包括读取 TXT 文件和命令行启动的时间。
环境与结果
测试环境为 Windows 11 64 位,Intel Core i5-11400H,6 核 12 线程;工具链为 GCC 12.2.0 和 GNU gprof 2.39,采用 -O2 优化及 -pg 采样构建。
| 测量项目 | 本次结果 |
|---|---|
| 每轮输入大小 | 4600000 字节 |
| 重复次数 | 500 |
| 累计处理字节数 | 2300000000 |
| 墙钟总耗时 | 8461.41 ms |
| 平均每轮墙钟耗时 | 16.92282 ms |
| 累计返回值校验 | 2800000000 |
count_text 调用次数 |
500 |
count_text 自身采样时间 |
7.16 s |
count_text 自身采样时间占比 |
95.47% |

主要热点位于 count_text,与程序逐字符扫描并完成行分类的设计一致。另有少量采样时间位于字符串查找和 memchr。
程序计数的时间复杂度为 O(N)。命令行程序当前一次性读入文件,输入存储空间为 O(N)。本轮采样复用内存,不能据此推断磁盘读取速度或峰值内存。
-pg 插桩存在额外开销,采样时间和墙钟时间的统计口径也不同,因此本次结果不应直接作为普通发布版的端到端性能。报告没有声称经过优化后取得了性能提升,也没有用单轮数据推断统计置信区间。
完整证据可在仓库的 PERFORMANCE.md 和 evidence/performance 中查看,其中包含 IDE 原生导出报告、截图、原始 gmon.out 及匹配的可执行文件压缩包。
八、当前限制与可改进方向
本项目采用明确的 ASCII 和标点规则,没有实现英文缩写、缩写句点与小数的语义识别。注释统计支持常见 C/C++ 风格,但不支持 C++ 原始字符串、预处理行拼接或嵌套注释。
后续可以将整文件读取改为分块读取,在保留跨块单词、句子和注释状态的同时减少内存占用;也可以补充更接近真实英文文档和真实源码的测试集。若开展性能优化,应在相同输入、编译配置和机器负载下进行多轮对照测试。
九、AI 使用说明与提示词记录
本项目全程使用 AI 协助生成代码、测试、文档和本篇博客,并通过工具在本机完成编译、测试及性能采样;码云和课程平台的登录验证由用户在登录窗口中完成。
按作业要求,本次相关用户提示词已整理到 AI_PROMPTS.md,包括原始作业要求、补充指令和后续操作请求。文件不包含密码或私人令牌,原始对话保留在本次聊天中。
原文地址: https://www.cveoy.top/t/topic/qHPT 著作权归作者所有。请勿转载和采集!