第二次作业
| 项目 | 链接或说明 |
|---|---|
| 所属课程 | https://edu.cnblogs.com/campus/zjlg/26rjjc |
| 作业要求 | 完成命令行纯英文文本计数统计工具 |
| 码云仓库 | https://gitee.com/let-me-jot-this-down-first/ruanjianjishujichuzuoye |
| 作业目标 | 实现一个命令行文本计数统计程序 |
| AI 使用情况 | 本项目的代码、测试、说明及本篇博客由 AI 辅助生成 |
wc-tool · 命令行文本计数统计程序
一个用 C++17 写的命令行文本统计工具(wc.exe),可以统计纯英文文本文件的
字符数 / 单词数 / 句子数,并扩展支持 总行数 / 空行数 / 注释行数 / 代码行数。
- 无第三方依赖,单个静态链接的
wc.exe,拷到别的机器直接就能跑; - 流式扫描,64 KiB 读块,内存占用与文件大小无关(处理 50 MiB 文本仅约 250 ms);
- 核心统计逻辑与命令行界面分离成静态库
wc_core,方便单元测试; - 内置 32 个单元测试、性能测试工具、以及一键构建/演示脚本。
1. 项目简介
wc.exe 模仿 Unix 的 wc 命令,但对“句子”“空行”“注释行”“代码行”这类
文本/代码结构做了更细的统计。典型用法:
wc.exe -c file.txt 统计字符数
wc.exe -w file.txt 统计单词数
wc.exe -s file.txt 统计句子数
wc.exe -l file.txt 统计总行数
wc.exe -b file.txt 统计空行数
wc.exe -m file.txt 统计注释行数
wc.exe -k file.txt 统计代码行数
wc.exe -a file.txt 全部统计项
程序名与参数名可按喜好修改(作业允许),本实现沿用 wc.exe 与 -c/-w/-s 的习惯命名,
便于与 Linux wc 对照验证。
设计要点
| 关注点 | 做法 |
|---|---|
| 可测试性 | 统计逻辑全部在 wc_core 静态库中,不含任何 main/I/O 输出代码 |
| 内存占用 | Analyzer 逐字节状态机,一次只读 64 KiB,额外空间 O(1) |
| 正确性 | 跨读块边界的状态(是否在单词中、是否在块注释中)保存在 Analyzer 内部,分块大小不影响结果(有专门单元测试) |
| 可移植性 | 标准 C++17,只依赖 <fstream>/<string>,MinGW 下静态链接运行时 |
2. 构建
2.1 环境要求
- Windows 10/11
- 任选其一:Visual Studio 2022(含“使用 C++ 的桌面开发”工作负载)、MinGW-w64 (g++ ≥ 9)、或 VS Code + C/C++ 插件
- CMake ≥ 3.15(若用
scripts/build.sh直接调 g++,则不需要 CMake)
2.2 使用 CMake(推荐)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
产物统一输出到 build/bin/:
build/bin/wc.exe 主程序
build/bin/wc_tests.exe 单元测试
build/bin/wc_bench.exe 性能测试工具
运行测试:
ctest --test-dir build --output-on-failure
:: 或直接执行
build\bin\wc_tests.exe
2.3 不用 CMake 的快捷方式
scripts\build.bat :: Windows:有 cmake 用 cmake,没有则退回 g++
bash scripts/build.sh :: Git Bash / WSL / Linux / macOS
2.4 在 Visual Studio 2022 中打开
文件 → 打开 → 文件夹 选择本目录即可(VS 会自动识别 CMakeLists.txt),
然后选择启动项 wc,在“调试 → 命令参数”里填 -a samples\demo.cpp。
3. 用法说明
3.1 参数一览
| 参数 | 长参数 | 含义 |
|---|---|---|
-c |
--chars |
字符数(不含换行符) |
-w |
--words |
单词数(被空白分隔的连续非空白串) |
-s |
--sentences |
句子数(以 . ! ? 结尾) |
-l |
--lines |
总行数 |
-b |
--blank |
空行数(只含空白字符的行) |
-m |
--comments |
注释行数(//、/* */,可选 #) |
-k |
--code |
代码行数(非空且非注释的行) |
-a |
--all |
以上全部 |
--hash / --no-hash |
强制开启/关闭 # 行注释识别(默认按扩展名自动判断) |
|
-h |
--help |
显示帮助 |
-v |
--version |
显示版本号 |
规则细节:
- 短参数可以合并:
wc.exe -lw file.txt等价于wc.exe -l -w file.txt; - 不带任何统计参数时,默认输出
-c -w -s三项; - 支持一次传入多个文件,最后追加
total汇总行; - 退出码:
0成功、1文件读取失败、2参数错误。
3.2 统计口径(重要)
| 指标 | 定义 | 与 GNU wc 的关系 |
|---|---|---|
| characters | 文件字节数中除去 \r、\n 的数量(UTF-8 BOM 不计) |
wc -c = characters + 换行符个数 |
| words | 被空格 / 制表符 / 换行分隔的连续非空白串数量 | 等价于 wc -w |
| sentences | 以 . ! ? 结尾的片段数;连续终止符算一句;末尾无终止符的残句也算一句 |
无对应项 |
| lines | 换行符个数,末尾无换行的最后一行额外计一行 | 等价于 wc -l |
| blank | 只含空格/制表符的行 | 无对应项 |
| comments | 整行内容都是注释的行:// 行注释、/* */ 块注释内各行、以及(按需)# 行首注释 |
无对应项 |
| code | 非空行中至少出现一个代码字符的行;int a; // note 记为代码行 |
无对应项 |
几个刻意处理的细节:
3.14中的.后面紧跟数字,不会被误判为句末;6 / 2中的/不会被误判为注释,a /*这种行尾开口的块注释会延续到下一行;#include <cstdio>在.cpp文件中算代码行(#默认只在.py/.sh/.txt/.yml等文件里当注释);- 注释行里的单词、句子仍然按原始文本计入
words/sentences(与wc的行为一致,统计的是“文本”而不是“语义”)。
4. 文件列表及说明
wc-tool/
├── CMakeLists.txt 构建脚本:wc_core 静态库 + 三个可执行目标 + ctest 用例
├── README.md 本说明文档
├── .gitignore
├── src/
│ ├── text_stats.h wc_core 公开接口:Options / Stats / Analyzer
│ ├── text_stats.cpp 统计核心:逐字节状态机(字符、词、句、行、注释、代码)
│ └── main.cpp 命令行入口:参数解析、结果表格输出、退出码
├── tests/
│ ├── test_framework.h 约 100 行的极简测试框架(TEST / CHECK 宏,无第三方依赖)
│ ├── test_main.cpp 32 个单元测试用例
│ └── data/
│ ├── sample.txt 纯英文文本样例(期望值写在用例里)
│ ├── comments.cpp C/C++ 注释与代码行样例
│ └── script.py '#' 注释样例
├── samples/
│ ├── sample.txt 演示用英文文本
│ └── demo.cpp 演示用 C++ 源文件
├── tools/
│ └── bench.cpp 性能测试工具 wc_bench.exe
├── scripts/
│ ├── build.bat 一键构建(Windows)
│ ├── build.sh 一键构建(g++ 直接编译)
│ ├── run_demo.bat 一键跑完 6 组演示命令,方便截图
│ ├── run_tests_demo.bat 一键跑单元测试 + 性能测试,方便截图
│ ├── push_to_gitee.bat 一键推送到码云(首次推送用)
│ └── gen_big_text.py 生成 50 MiB 大文本用于性能测试
└── docs/
├── perf.md 性能测试方法、结果与 IDE 工具使用步骤
└── images/ 运行结果截图(v0.1 / v0.2 / v0.3)
5. 例程运行及结果
以下输出均为在本机(Windows 11 + MinGW-w64 g++ 16.2,Release 构建)实际运行结果。
① 默认输出(字符/单词/句子)
> wc.exe samples/sample.txt
characters words sentences file
378 72 6 samples/sample.txt
② 只统计字符数
> wc.exe -c samples/sample.txt
characters file
378 samples/sample.txt
③ 合并短参数
> wc.exe -lws samples/sample.txt
words sentences lines file
72 6 7 samples/sample.txt
④ 扩展功能:对 C++ 源文件做全量统计
> wc.exe -a samples/demo.cpp
characters words sentences lines blank comments code file
370 56 1 18 3 6 9 samples/demo.cpp
demo.cpp 共 18 行,其中 3 个空行、6 个注释行(// 两行,/* */ 四行)、9 个代码行,与人工核对一致。
⑤ 只关心注释行与代码行
> wc.exe -m -k tests/data/comments.cpp
comments code file
4 5 tests/data/comments.cpp
⑥ 多文件与汇总
> wc.exe -a samples/sample.txt tests/data/comments.cpp
characters words sentences lines blank comments code file
378 72 6 7 2 0 5 samples/sample.txt
111 22 1 11 2 4 5 tests/data/comments.cpp
489 94 7 18 4 4 10 total
⑦ 与 GNU wc 交叉验证(同一个文件)
> wc -l -w -c samples/sample.txt
7 72 385 samples/sample.txt
> wc.exe -a samples/sample.txt
characters words sentences lines blank comments code file
378 72 6 7 2 0 5 samples/sample.txt
385 - 7(换行符)= 378,单词数、行数与 GNU wc 完全一致。
⑧ 错误处理
> wc.exe -a nosuchfile.txt
wc: cannot open file: nosuchfile.txt
[exit=1]
一键复现全部演示(输出可以直接截图):
scripts\run_demo.bat
5.1 运行结果截图
① v0.1 — 空项目骨架(码云上 v0.1 标签的提交内容:9 个文件,+86 / -0)

② v0.2 — 基础功能(字符数 / 单词数 / 句子数)

③ v0.3 — 扩展功能(总行数 / 空行数 / 注释行数 / 代码行数)

6. 单元测试
测试用例集中在 tests/test_main.cpp,采用自研的极简框架(不引入第三方库,离线可用):
[ OK ] basic_empty_input
[ OK ] basic_single_character_without_newline
...
cases: 32 checks: 151 failed cases: 0
ALL TESTS PASSED
覆盖矩阵:
| 分组 | 用例数 | 覆盖内容 |
|---|---|---|
基础功能 basic_* |
8 | 空输入、单字符、无末尾换行、空白分隔、连续终止符、3.14 小数不误判、跨行句子、只有标点的输入 |
换行处理 newline_* |
4 | LF / CRLF、末尾多个空行、末尾无换行、空行计数 |
扩展功能 ext_* |
10 | 行注释、缩进注释、多行块注释、单行块注释、行尾注释、代码行+跨行块注释、除号不误判、# 注释开关、注释内单词仍计数 |
边界健壮性 edge_* |
5 | UTF-8 BOM、非 ASCII 字节计数、只有空格、文件不存在、连续空行 |
流式一致性 stream_* |
1 | 以 1/2/7/13 字节分块喂入,结果必须与整体统计完全相同 |
文件级 file_* |
3 | sample.txt / comments.cpp / script.py 的精确期望值 |
运行方式:
build\bin\wc_tests.exe
:: 或
ctest --test-dir build --output-on-failure
7. 性能测试
详见 docs/perf.md。核心结论(50.00 MiB、9,043,659 单词的生成文本):
| 指标 | 结果 |
|---|---|
| 单次统计耗时(10 次) | 最小 248.5 ms / 平均 269.1 ms / 最大 284.0 ms |
| 吞吐量 | 约 201 MiB/s |
| 内存占用 | 常驻 ≈ 64 KiB 读缓冲,与文件大小无关 |
对照组(GNU wc -l -w -c 同一文件) |
489 ms(本工具 339 ms,含进程启动开销) |
复现方式:
python scripts\gen_big_text.py build\big_text.txt 50
build\bin\wc_bench.exe build\big_text.txt 10
IDE 自带性能工具的使用步骤(VS 2022 性能探查器 / VS Code Profiler / CLion Profiler)见 docs/perf.md。
8. 版本历史
| 版本 | 提交内容 |
|---|---|
| v0.1 | 空项目:目录骨架、.gitignore、README 初稿 |
| v0.2 | 基础功能:字符数 / 单词数 / 句子数统计、命令行参数解析、基础单元测试 |
| v0.3 | 扩展功能:总行数 / 空行数 / 注释行数 / 代码行数、多文件汇总、# 注释开关、单元测试扩充到 32 例、性能测试工具与文档 |
对应的 git 提交与 tag 与上表一致,可用 git log --oneline --decorate 查看逐版本演进。
ai提示词:
用 C++ 写一个命令行文本统计工具 wc.exe,不引入任何第三方库,用 CMake 构建。
一、基础功能:统计纯英文文本文件的字符数、单词数、句子数,参数为 -c / -w / -s。
二、扩展功能:统计总行数 -l、空行数 -b、注释行数 -m、代码行数 -k,-a 表示全部。
三、统计口径:
- 字符数不含 \r \n,忽略 UTF-8 BOM,结果需与 wc -c 减去换行数一致;
- 单词按空白分隔,需与 wc -w 完全一致;
- 句子以 . ! ? 结尾,连续终止符算一句,"3.14" 中的点不判为句末;
- 注释识别 // 和 /* */(块注释可跨行),# 行注释按扩展名决定是否启用;
- "6 / 2" 里的除号不能误判为注释起点。
四、工程要求: - 统计逻辑抽成独立静态库,不含 main 与输出代码,便于单测;
- 逐字节状态机 + 64 KiB 流式读块,内存占用与文件大小无关,跨块状态要正确;
- 支持短参数合并(-lws)、多文件 + total 汇总行、-h / -v;
- 退出码:0 成功、1 文件读取失败、2 参数错误;
- 输出对齐的表格,表头只在有输出时打印。
五、测试:不依赖第三方框架,自带极简 TEST/CHECK 宏,覆盖基础、换行、扩展、边界
(BOM、非 ASCII)、流式一致性(用 1/2/7/13 字节分块喂入结果必须相同)等 30 个以上用例。
六、性能:提供一个独立的性能测试工具,输出单次耗时、最小值/平均值/最大值与 MiB/s 吞吐。

浙公网安备 33010602011771号