# wc **Repository Path**: shengxuyi/wc ## Basic Information - **Project Name**: wc - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-26 - **Last Updated**: 2026-10-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # wc —— 命令行文本计数统计程序 > C# / .NET 控制台应用(生成 `wc.exe`) > 基础功能:统计文本文件的字符数、单词数、句子数 > 扩展功能:统计代码行、空行、注释行等,并处理各类异常输入 本项目是软件工程课程作业,模拟 Linux `wc` 命令实现一个命令行文本计数统计程序, 包含完整源码、单元测试(xUnit)、性能测试说明与分版本提交记录。 --- ## 目录 1. [项目简介](#1-项目简介) 2. [环境要求](#2-环境要求) 3. [编译与运行](#3-编译与运行) 4. [用法与参数](#4-用法与参数) 5. [统计规则](#5-统计规则) 6. [例程运行及结果](#6-例程运行及结果) 7. [文件列表及说明](#7-文件列表及说明) 8. [单元测试](#8-单元测试) 9. [性能测试](#9-性能测试) 10. [版本提交记录](#10-版本提交记录) 11. [码云仓库地址](#11-码云仓库地址) 12. [AI 对话提示词记录](#12-ai-对话提示词记录) 13. [局限性与已知问题](#13-局限性与已知问题) --- ## 1. 项目简介 `wc.exe` 是一个命令行文本计数统计程序,针对纯英文 txt 文本: - **基础功能**:统计字符数(`-c`)、单词数(`-w`)、句子数(`-s`); - **扩展功能**:统计代码行(`-a`)、空行(`-e`)、注释行(`-m`)与总行数(`-l`); - **健壮性**:对文件不存在、参数错误、无参数、空文件、目标是目录等异常情况给出友好提示与规范化退出码; - **可组合**:选项可以并列(`-c -w`)或合并(`-cw`)使用,一次输出多项统计。 程序结构上把「参数解析 / 文件读取 / 统计算法 / 输出」拆分为独立模块, 统计算法全部是纯函数(不依赖文件系统),单元测试不需要生成临时文件即可覆盖绝大多数场景。 ## 2. 环境要求 | 路径 | 要求 | |------|------| | 推荐:.NET SDK | Windows / Linux / macOS 均可。仓库当前 `TargetFramework` 为 **net10.0**(开发机安装 .NET 10 SDK,VS2022 亦支持);若你的环境是 **.NET 8 SDK**(如 VS2022 默认配置),把两个 `.csproj` 中的 `TargetFramework` 改回 `net8.0` 即可,代码无需任何改动 | | 备用:系统自带运行时 | Windows + .NET Framework 4.x(系统自带,无需安装任何东西),使用 `tools/build-netframework.cmd` 编译 | 源码刻意保持 **C# 5 兼容语法**,因此上述两种编译方式产物行为完全一致。 性能测试若使用 Visual Studio Performance Profiler,需要 Visual Studio 2022 Community 及以上版本。 输入文件编码:UTF-8(含/不含 BOM)、UTF-16(带 BOM)。GBK/ANSI 编码文件请先转存为 UTF-8。 ## 3. 编译与运行 **方式一:.NET CLI(推荐)** ```bash # 编译(Release) dotnet build -c Release # 产物位置 # src/WordCount/bin/Release/net10.0/wc.exe ``` **方式二:Visual Studio 2022** 打开 `WordCount.sln` → 选择 `WordCount` 项目 → `Ctrl+Shift+B` 编译 → `Ctrl+F5` 运行(或在该项目上右键「调试 → 启动新实例」并在项目属性中填写命令行参数)。 **方式三:无 SDK 的 Windows(备用)** ```bat tools\build-netframework.cmd :: 在仓库根目录生成 wc.exe(.NET Framework 4.x 版本) ``` **运行**(在产物目录下,或把 wc.exe 所在目录加入 PATH): ```bat wc.exe -c samples\basic.txt ``` ## 4. 用法与参数 ``` 用法: wc.exe [选项] <文件名> ``` | 选项 | 统计内容 | 归属 | |------|----------|------| | `-c` | 字符数 | 基础功能 | | `-w` | 单词数 | 基础功能 | | `-s` | 句子数 | 基础功能 | | `-l` | 总行数 | 扩展功能 | | `-e` | 空行数 | 扩展功能 | | `-m` | 注释行数 | 扩展功能 | | `-a` | 代码行数 | 扩展功能 | | `-h` / `--help` | 显示帮助 | — | | `--version` | 显示版本号 | — | - 选项可并列(`-c -w -s file.txt`)也可合并(`-cws file.txt`),输出按 `-c -w -s -l -e -m -a` 固定顺序排列; - 输出格式为:`右对齐数值 + 标签 + 文件名`,例如 ` 33 words samples/basic.txt`; - **退出码**:`0` 成功;`1` 命令行参数错误(无参数、未知选项、缺文件名等);`2` 文件读取错误(文件不存在、路径是目录、无权限等)。错误信息输出到 stderr,正常统计输出到 stdout,便于脚本中组合使用。 ## 5. 统计规则 所有规则在代码注释与单元测试中均有对应说明(`TextCounter.cs`、`CodeLineCounter.cs`)。 ### 5.1 字符数(-c) 统计文本中的**全部字符**,包括: - 字母、数字、标点; - 空格、制表符等空白字符; - 换行符:Windows 换行 `\r\n` 计 **2** 个字符,Unix 换行 `\n` 计 **1** 个字符。 按字符计数而非按字节计数(对纯英文文本两者相同)。示例:`"a\r\nb"` = 4 个字符。 ### 5.2 单词数(-w) 以任意空白字符(空格、制表符、换行)切分出字段,剥离字段**首尾**标点后仍非空者计为一个单词: | 输入 | 单词数 | 说明 | |------|--------|------| | `Hello, world!` | 2 | 首尾标点被剥离 | | `don't stop` | 2 | 内部撇号保留 | | `well-known tool` | 2 | 内部连字符保留 | | `3.14 is a number` | 4 | 数字、内部句点保留 | | `U.S.A. is here` | 3 | 尾部句点被剥离 | | `...` | 0 | 纯标点不计 | | ` hello world ` | 2 | 多空格不影响 | ### 5.3 句子数(-s) - 句子以 `.` `!` `?` 三种结束符收尾; - **连续**出现的结束符(如 `!!!`、`?!`、省略号 `...`)只计 **1** 次; - 文本末尾没有结束符、但仍有非空白内容时,该残句也计 1 句(`"Hello world"` = 1 句); - 只有标点或空白、没有任何实际内容时不计句(`"..."` = 0 句)。 | 输入 | 句子数 | |------|--------| | `Hi. How are you? Great!` | 3 | | `Wow!!! Amazing?!` | 2 | | `Wait... what?` | 2 | | `One. Two` | 2 | | `...` | 0 | ### 5.4 代码行统计(-l / -e / -m / -a) 针对 C 风格源代码(C/C++/C#/Java/JavaScript 等)逐行分类,**每行恰好属于一类**, 因此恒有:`总行数 = 空行数 + 注释行数 + 代码行数`。 | 类别 | 规则 | 示例 | |------|------|------| | 空行(-e) | 仅含空白字符的行;或仅由大括号 `{ }` 与空白组成的行(单独的 `{`、`}`、`{ }`) | `""`、`" "`、`"{"`、`" { } "` | | 注释行(-m) | 整行只有注释内容:以 `//` 开头(允许前导空白);或处于 `/* ... */` 块注释中且除注释外没有代码(含块注释的开头行和结尾行) | `// note`、`/* one */`、块注释中间的行 | | 代码行(-a) | 既非空行也非注释行的行,**包括「代码 + 行尾注释」的混合行** | `int a; // note`、`still */ int b;` | 细节约定: - 块注释**内部**的空行仍按空行统计; - `int a; /* opens` 这类「代码 + 块注释开头」算**代码行**,且块注释状态延续到后续行; - 字符串/字符字面量中的 `//` 与 `/*` 不当作注释(如 `string url = "http://x";` 是代码行); - 行数语义与常见编辑器一致:空文件为 0 行;`"a\n"` 为 1 行(末尾换行不产生额外空行);`"a\nb"` 为 2 行。 ## 6. 例程运行及结果 以下均为仓库中样例文件的**真实运行输出**(Windows 11,`-c` 数值基于 LF 换行的样例文件; `.gitattributes` 已固定文本文件换行符为 LF,各机器上结果一致)。 ### 6.1 基础功能 `samples/basic.txt` 内容: ```text Hello, world! This is wc. It counts characters, words and sentences. Can it count? Yes! It can. Second paragraph: numbers 1 2 3 appear here. Don't stop believing. Hold on to that feeling! ``` ```text > wc.exe -c samples/basic.txt 189 chars samples/basic.txt > wc.exe -w samples/basic.txt 33 words samples/basic.txt > wc.exe -s samples/basic.txt 9 sentences samples/basic.txt > wc.exe -c -w -s samples/basic.txt 189 chars samples/basic.txt 33 words samples/basic.txt 9 sentences samples/basic.txt ``` ### 6.2 扩展功能 `samples/code_sample.cs`(23 行 = 11 空行 + 4 注释行 + 8 代码行,可手工核对): ```text > wc.exe -l samples/code_sample.cs 23 lines samples/code_sample.cs > wc.exe -e samples/code_sample.cs 11 empty lines samples/code_sample.cs > wc.exe -m samples/code_sample.cs 4 comment lines samples/code_sample.cs > wc.exe -a samples/code_sample.cs 8 code lines samples/code_sample.cs > wc.exe -cwslema samples/code_sample.cs (全部统计项组合) 515 chars samples/code_sample.cs 50 words samples/code_sample.cs 7 sentences samples/code_sample.cs 23 lines samples/code_sample.cs 11 empty lines samples/code_sample.cs 4 comment lines samples/code_sample.cs 8 code lines samples/code_sample.cs ``` ### 6.3 异常处理 ```text > wc.exe (无参数) wc: 错误: 未提供任何参数。 (后接完整用法帮助,退出码 1) > wc.exe -x samples/basic.txt (未知参数) wc: 错误: 未知选项: -x(可用选项: -c -w -s -l -e -m -a,输入 -h 查看帮助) (后接用法帮助,退出码 1) > wc.exe -c no_such.txt (文件不存在) wc: 错误: 文件不存在: no_such.txt (退出码 2) > wc.exe -c samples (路径是目录) wc: 错误: 路径是一个目录,不是文件: samples (退出码 2) > wc.exe -c samples/empty.txt (空文件:正常输出 0,不算错误) 0 chars samples/empty.txt (退出码 0) > wc.exe -c (只有选项缺少文件名) wc: 错误: 缺少文件名。 (退出码 1) > wc.exe samples/basic.txt (只有文件、没有统计项) wc: 错误: 请至少指定一个统计参数(-c -w -s -l -e -m -a)。 (退出码 1) > wc.exe -c a.txt b.txt (多文件) wc: 错误: 一次只能统计一个文件,收到了多个: a.txt b.txt (退出码 1) ``` ## 7. 文件列表及说明 ``` wc/ ├── README.md 本文件 ├── .gitignore / .gitattributes Git 忽略规则 / 换行符统一(保证 -c 结果跨机一致) ├── WordCount.sln 解决方案(主程序 + 单元测试两个项目) ├── src/WordCount/ 主程序项目(AssemblyName=wc,生成 wc.exe) │ ├── WordCount.csproj │ ├── Program.cs 入口:流程编排、输出格式、帮助文本、退出码 │ ├── CommandLineOptions.cs 命令行解析(选项、合并选项、错误提示) │ ├── TextCounter.cs 基础统计:字符/单词/句子(纯函数) │ ├── CodeLineCounter.cs 扩展统计:总行/空行/注释行/代码行(状态机) │ └── TextFileReader.cs 文件读取与 IO 异常转换 ├── tests/WordCount.Tests/ xUnit 单元测试项目 │ ├── WordCount.Tests.csproj │ ├── TextCounterTests.cs 基础功能测试(v0.2) │ ├── CommandLineOptionsTests.cs 参数解析测试(v0.2) │ ├── CodeLineCounterTests.cs 扩展功能测试(v0.3) │ ├── ExtendedOptionsTests.cs 扩展参数解析测试(v0.3) │ └── ProgramEndToEndTests.cs 端到端测试:真实启动 wc.exe(v0.3) ├── samples/ 示例输入 │ ├── basic.txt 基础功能演示文本(LF 换行) │ ├── empty.txt 空文件(0 字节) │ └── code_sample.cs 代码行统计演示(23=11+4+8) ├── tools/ │ ├── build-netframework.cmd 备用编译脚本(系统自带 csc,无需 SDK) │ ├── gen_perf_file.py 性能测试大文件生成器(纯标准库) │ └── verify/VerifyAll.cs 无 NuGet 环境的本地自测器(与 xUnit 同数据集) ├── docs/ │ ├── performance.md 性能测试方法、结果与截图位置 │ ├── commit-plan.md v0.1/v0.2/v0.3 分版本提交计划(含命令) │ ├── ai-prompts.md AI 对话提示词记录 │ └── stages/ 各版本阶段文件(供分阶段提交时替换使用) └── screenshots/ 运行结果截图(命名约定见目录内说明) ``` ## 8. 单元测试 测试框架:**xUnit**,共 5 个测试文件、80 余个用例,覆盖: - **基础功能**:字符数(空文件、空格、CRLF/LF 换行、标点)、单词数(多空格、标点、缩写 `don't`、数字 `3.14`、纯标点、混合文本)、句子数(多句子、连续结束符、省略号、末尾残句、换行分隔); - **扩展功能**:单行分类(空行/大括号行/行注释/块注释/代码+行尾注释/字符串中的 `//` 与 `/*`)、整文本统计(块注释跨行、块内空行、末尾换行)、守恒关系(总行数 = 空行 + 注释行 + 代码行); - **参数解析**:单选项、合并选项、`-h/--help/--version`、未知选项、裸 `-`、未知长选项、缺文件、多文件、只有文件、空参数、无参数; - **端到端**(`ProgramEndToEndTests`):真实启动构建产物 `wc.exe`,验证帮助/无参数/未知选项/文件不存在/目录/空文件/正常统计的输出与退出码。 **运行方式:** ```bash # 方式一(推荐):.NET CLI dotnet test # 方式二:Visual Studio 2022 # 菜单「测试 → 运行所有测试」,或在测试资源管理器中点击「Run All」 ``` **无 NuGet 环境的备用自测**(可选,验证与 xUnit 相同的数据集,108 项断言): ```bash # 仓库根目录下执行 tools/build-netframework.cmd 编译后: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /nologo /codepage:65001 ^ /out:build\verify.exe /main:WordCountVerify.VerifyMain src\WordCount\*.cs tools\verify\VerifyAll.cs build\verify.exe # 预期输出: == verify: 108 checks, 0 failures == ``` ## 9. 性能测试 详细方法、环境、数据与截图位置见 [docs/performance.md](docs/performance.md)。摘要: - **方法**:Visual Studio 2022 Performance Profiler(CPU Usage)+ 命令行计时(各 3 次取平均); - **测试文件**:`tools/gen_perf_file.py` 生成的 1MB / 10MB / 50MB 英文文本(自然语言与代码行混合); - **结果**(本机参考值,Windows 11 / i7-14700HX / .NET Framework 4.8 编译版本): | 文件规模 | 耗时(3 次平均) | 吞吐 | |----------|------------------|------| | 1 MB | ≈ 0.15 s | ≈ 7 MB/s(进程启动与 JIT 占大头) | | 10 MB | ≈ 0.40 s | ≈ 26 MB/s | | 50 MB | ≈ 1.50 s | ≈ 34 MB/s | 结论:耗时随文件规模近似线性增长,50MB 文本全项统计约 1.5 秒,满足命令行工具的性能预期。 ## 10. 版本提交记录 本仓库按功能演进分三个版本提交(完整提交计划与操作命令见 [docs/commit-plan.md](docs/commit-plan.md)): | 版本 | 内容 | 关键提交 | |------|------|----------| | v0.1 | 项目初始化:解决方案骨架、README 初稿 | `v0.1 初始化项目骨架与 README 初稿` | | v0.2 | 基础功能:字符数、单词数、句子数 + 基础单元测试 + 运行截图 | `v0.2 完成基础统计功能(字符/单词/句子)与单元测试` | | v0.3 | 扩展功能:代码行/空行/注释行 + 扩展与端到端测试 + 性能测试 + 截图 | `v0.3 完成代码行统计扩展功能、端到端测试与性能测试` | 每个版本打对应 Git 标签(`v0.1` / `v0.2` / `v0.3`),运行结果截图存放于 `screenshots/` 目录。 ## 11. 码云仓库地址 ``` https://gitee.com/shengxuyi/wc ``` ## 12. AI 对话提示词记录 本项目在开发过程中使用了 AI 辅助(代码生成、测试设计、文档撰写)。 依照课程要求,**全部对话提示词记录**见 [docs/ai-prompts.md](docs/ai-prompts.md), 包含:原始作业要求提示词、各功能迭代提示词、以及 AI 生成内容的复核与修改记录。 ## 13. 局限性与已知问题 1. **缩写不识别**:`Mr.`、`U.S.A.` 等缩写中的句点会被当作句子结束符(`Mr. Smith is here.` 计 2 句)。该行为已在单元测试中文档化(`AbbreviationPeriod_CountsAsSentenceEnd_KnownLimitation`),如需精确处理需要引入缩写词典。 2. **注释识别面向 C 风格语言**:仅识别 `//` 与 `/* */`,不适用于 Python(`#`)、SQL(`--`)等注释风格。 3. **字符串识别的简化**:不解析逐字字符串 `@"..."`(其中出现的 `/*` 会被误认为块注释开始)与跨行字符串。 4. **编码**:无 BOM 的 GBK/ANSI 文件会按 UTF-8 解码,可能得到乱码计数;请将文件转存为 UTF-8。 5. **单词定义为「空白分隔的字段」**:`hello-world` 视为 1 个单词;如需把连字符词汇拆成两个单词,需调整 `TextCounter.TrimPunctuation` 的规则。