第二次作业

项目 链接或说明
所属课程 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.1 空项目

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

v0.2 基础功能

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

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 吞吐。
posted @ 2026-11-01 22:58  我先记个笔记  阅读(9)  评论(0)    收藏  举报