WordCount的实现
一、开发者:201631062414
二、代码地址:https://gitee.com/myValue/WordCount/tree/master
三、https://edu.cnblogs.com/campus/xnsy/Test/homework/2203
四、功能概述
1.1 基本功能
wc.exe -c file.c //返回文件 file.c 的字符数
wc.exe -w file.c //返回文件 file.c 的单词总数
wc.exe -l file.c //返回文件 file.c 的总行数
wc.exe -o outputFile.txt //将结果输出到指定文件outputFile.txt
注意:
空格,水平制表符,换行符,均算字符。
由空格或逗号分割开的都视为单词,且不做单词的有效性校验,例如:thi#,that视为用逗号隔开的2个单词。
-c, -w, -l参数可以共用同一个输入文件,形如:wc.exe –w –c file.c 。
-o 必须与文件名同时使用,且输出文件必须紧跟在-o参数后面,不允许单独使用-o参数。
1.2 扩展功能
wc.exe -s //递归处理目录下符合条件的文件
wc.exe -a file.c //返回更复杂的数据(代码行 / 空行 / 注释行)
wc.exe -e stopList.txt // 停用词表,统计文件单词总数时,不统计该表中的单词
其中,
代码行:本行包括多于一个字符的代码。
空 行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:}//注释
在这种情况下,这一行属于注释行。
-e 必须与停用词文件名同时使用,且停用词文件必须紧跟在-e参数后面,不允许单独使用-e参数。
stopList.txt中停用词可以多于1个,单词之间以空格分割,不区分大小写,形如:while if switch
则while,if,switch作为3个停用词,在单词统计的时候不予考虑。停用词表仅对单词统计产生影响,不影响字符和行数的统计。
2 项目规划
项目阶段 | 项目进度 | 实际进度 |
需求分析 | 1h | 1h |
项目设计 | 2h | 1.5h |
设计复审 | 1h | 1h |
代码规范 | 1h | 0.5h |
代码实现 | 48h | 48h |
代码复审 | 3h | 3h |
测试设计 | 1h | 1h |
测试 | 1h | 2h |
测试报告 | 1h | 2h |
代码改进 | 2h | 2h |
3设计
分析输入符
public void ExecutiveCommand(string strCommand)
获取字符数
public int GetCharNum(string fileName)
获取单词数
public int GetWordNum(string fileName)
获取总行数
public int GetRowNum(string fileName)
循环执行所有文件
public void ExeAllFile()
获取代码行数
public int GetCodeRowNum(string fileName)
获取空行数
public int GetBlankRowNum(string fileName)
获取注释行数
public int GetNoteRowNum(string fileName)
设置禁用词
public void GetStopList(string fileName)
将结果写入文件
public void OutputResult(string fileName)
五、项目实现
1.操作类
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace WordCount 9 { 10 class WC 11 { 12 int charNum = 0; 13 int wordNum = 0; 14 int rowNum = 0; 15 string strResult = ""; 16 string[] stopWord; 17 public void ExecutiveCommand(string strCommand) 18 { 19 string[] strOperate = strCommand.Split(' '); 20 string fileName = "file.c";//默认操作文件 21 //获取.c操作文件 22 for (int i = 0; i < strOperate.Length; ++i) 23 { 24 if (strOperate[i] != "-c" && strOperate[i] != "-w" && 25 strOperate[i] != "-l" && strOperate[i] != "-a" && 26 strOperate[i] != "-o" && strOperate[i] != "-e" && 27 strOperate[i] != "-s" && System.IO.Path.GetExtension(strOperate[i]).Equals(".c")) 28 { 29 fileName = strOperate[i]; 30 } 31 } 32 //循环操作 33 for (int i = 0; i < strOperate.Length; ++i) 34 { 35 if (strOperate[i].Equals("-c")) 36 { 37 charNum = GetCharNum(fileName); 38 SaveResult(fileName + ",字符数:" + charNum); 39 } 40 else if (strOperate[i].Equals("-w")) 41 { 42 wordNum = GetWordNum(fileName); 43 SaveResult(fileName + ",单词数:" + wordNum); 44 } 45 else if (strOperate[i].Equals("-l")) 46 { 47 rowNum = GetRowNum(fileName); 48 SaveResult(fileName + ",行数:" + rowNum); 49 } 50 else if (strOperate[i].Equals("-a")) 51 { 52 SaveResult(fileName + ",代码行数:" + GetCodeRowNum(fileName)); 53 SaveResult(fileName + ",空白行数:" + GetBlankRowNum(fileName)); 54 SaveResult(fileName + ",注释行数:" + GetNoteRowNum(fileName)); 55 } 56 else if (strOperate[i].Equals("-o")) 57 { 58 OutputResult(strOperate[i + 1]); 59 } 60 else if (strOperate[i].Equals("-e")) 61 { 62 GetStopList(strOperate[i + 1]); 63 } 64 else if (strOperate[i].Equals("-s")) 65 { 66 ExeAllFile(); 67 } 68 } 69 } 70 //获取字符数 71 public int GetCharNum(string fileName) 72 { 73 // 打开文件 74 FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); 75 // 读取文件的 byte[] 76 byte[] bytes = new byte[fileStream.Length]; 77 fileStream.Read(bytes, 0, bytes.Length); 78 fileStream.Close(); 79 string strfile = Encoding.UTF8.GetString(bytes);// 字节向字符串转化 80 81 return strfile.Length - GetRowNum(fileName) + 1;//换行符占两个字符 82 } 83 //获取单词数 84 public int GetWordNum(string fileName) 85 { 86 // 打开文件 87 FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); 88 // 读取文件的 byte[] 89 byte[] bytes = new byte[fileStream.Length]; 90 fileStream.Read(bytes, 0, bytes.Length); 91 fileStream.Close(); 92 string strfile = Encoding.UTF8.GetString(bytes);// 字节向字符串转化 93 int wNum = 0; 94 string strword = ""; 95 strfile += '\n';//在最后添加换行符 96 for (int i = 1; i < strfile.Length; ++i) 97 { 98 if (strfile[i].Equals(' ') || strfile[i].Equals(',') || strfile[i].Equals('\n')) 99 { 100 if (strfile[i - 1].Equals(' ') == false && strfile[i - 1].Equals(',') == false && strfile[i - 1].Equals('\n') == false) 101 { 102 ++wNum; 103 //停用词 104 if (stopWord != null) 105 { 106 strword = strword.ToLower(); 107 for (int j = 0; j < stopWord.Length; ++j) 108 { 109 if (strword == stopWord[j]) 110 { 111 --wNum; 112 } 113 } 114 } 115 strword = ""; 116 } 117 } 118 else 119 { 120 strword += strfile[i];//记录单词 121 } 122 } 123 return wNum; 124 } 125 //获取行数 126 public int GetRowNum(string fileName) 127 { 128 StreamReader sr = new StreamReader(fileName, Encoding.Default); 129 int rNum = 0; 130 while (sr.ReadLine() != null) 131 { 132 ++rNum; 133 } 134 return rNum; 135 } 136 //获取代码行/空行/注释行 137 public int GetCodeRowNum(string fileName) 138 { 139 StreamReader sr = new StreamReader(fileName, Encoding.Default); 140 string str; 141 int codeNum = 0; 142 int noteNum = 0; 143 int blankNum = 0; 144 while ((str = sr.ReadLine()) != null) 145 { 146 noteNum = 0; 147 blankNum = 0; 148 for (int i = 0; i < str.Length; ++i) 149 { 150 if (i < str.Length - 1 && str[i].Equals('/') && str[i + 1].Equals('/')) 151 {//注释点 152 noteNum = i; 153 break; 154 } 155 if (str[i].Equals(' ') || str[i].Equals('\t') || str[i].Equals('{') || str[i].Equals('}')) 156 {//空白数 157 ++blankNum; 158 } 159 } 160 if (noteNum != 0 && noteNum > blankNum) 161 { 162 ++codeNum; 163 } 164 else if (noteNum == 0 && blankNum < str.Length) 165 { 166 ++codeNum; 167 } 168 } 169 return codeNum; 170 } 171 public int GetBlankRowNum(string fileName) 172 { 173 StreamReader sr = new StreamReader(fileName, Encoding.Default); 174 string str; 175 int num = 0; 176 int noteNum = 0; 177 int blankNum = 0; 178 while ((str = sr.ReadLine()) != null) 179 { 180 noteNum = 0; 181 blankNum = 0; 182 for (int i = 0; i < str.Length; ++i) 183 { 184 if (i < str.Length - 1 && str[i].Equals('/') && str[i + 1].Equals('/')) 185 {//注释点 186 noteNum = i; 187 break; 188 } 189 if (str[i].Equals(' ') || str[i].Equals('\t') || str[i].Equals('{') || str[i].Equals('}')) 190 {//空白数 191 ++blankNum; 192 } 193 } 194 if (noteNum != 0 && noteNum == blankNum) 195 { 196 ++num; 197 } 198 else if (str.Length == 0 || noteNum == 0 && blankNum == str.Length) 199 { 200 ++num; 201 } 202 } 203 204 return num; 205 } 206 public int GetNoteRowNum(string fileName) 207 { 208 StreamReader sr = new StreamReader(fileName, Encoding.Default); 209 string str; 210 int noteNum = 0; 211 while ((str = sr.ReadLine()) != null) 212 { 213 for (int i = 0; i < str.Length; ++i) 214 { 215 if (i < str.Length - 1 && str[i].Equals('/') && str[i + 1].Equals('/')) 216 {//注释点 217 ++noteNum; 218 break; 219 } 220 } 221 } 222 return noteNum; 223 } 224 //写入结果 225 public void OutputResult(string fileName) 226 { 227 FileStream fileStream = new FileStream(fileName, FileMode.Create); 228 StreamWriter sw = new StreamWriter(fileStream); 229 //开始写入 230 sw.WriteLine(strResult); 231 //清空缓冲区 232 sw.Flush(); 233 //关闭流 234 sw.Close(); 235 fileStream.Close(); 236 } 237 //输出并存结果 238 public void SaveResult(string str) 239 { 240 Console.WriteLine(str); 241 strResult += str + "\r\n"; 242 } 243 //获取停用单词 244 public void GetStopList(string fileName) 245 { 246 StreamReader sr = new StreamReader(fileName, Encoding.Default); 247 string strfile = sr.ReadToEnd(); 248 strfile = strfile.ToLower(); 249 stopWord = strfile.Split(' '); 250 for (int i = 0; i < stopWord.Length; ++i) 251 { 252 Console.Write(stopWord[i] + "\t"); 253 } 254 Console.WriteLine(); 255 } 256 //循环处理目录下所有.c文件 257 public void ExeAllFile() 258 { 259 string rootPath = Directory.GetCurrentDirectory();//当前路径 260 DirectoryInfo sfolder = new DirectoryInfo(rootPath); 261 foreach (FileInfo file in sfolder.GetFiles("*.c")) 262 { 263 SaveResult("\n"); 264 SaveResult(file.Name + ",字符数:" + GetCharNum(file.Name)); 265 SaveResult(file.Name + ",单词数:" + GetWordNum(file.Name)); 266 SaveResult(file.Name + ",总行数:" + GetRowNum(file.Name)); 267 SaveResult(file.Name + ",代码行数:" + GetCodeRowNum(file.Name)); 268 SaveResult(file.Name + ",空白行数:" + GetBlankRowNum(file.Name)); 269 SaveResult(file.Name + ",注释行数:" + GetNoteRowNum(file.Name)); 270 } 271 } 272 } 273 }
2.主类
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace WordCount 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 Console.Write("wc.exe -c file.c\t返回文件 file.c 的字符数\n" + 15 "wc.exe -w file.c\t返回文件 file.c 的单词总数\n" + 16 "wc.exe -l file.c\t返回文件 file.c 的总行数\n" + 17 "wc.exe -a file.c\t返回更复杂的数据(代码行/空行/注释行)\n" + 18 "wc.exe -o outputFile.txt\t将结果输出到指定文件outputFile.txt\n"+ 19 "wc.exe -e stopList.txt\t停用词表,统计文件单词总数时,不统计该表中的单词\n"+ 20 "wc.exe -s\t循环执行所有.c文件\n"); 21 WC wc = new WC(); 22 while(true) 23 { 24 Console.WriteLine("--------------------------"); 25 Console.WriteLine("输入命令:"); 26 string str = Console.ReadLine(); 27 wc.ExecutiveCommand(str); 28 } 29 } 30 } 31 }
六、测试用例
等价类分析
输入 | 有效等价类 | 无效等价类 |
执行文件 | wc.exe | 其他文件名 |
操作符 | -c | 其他任意字符串 |
-w | ||
-l | ||
-a | ||
-o | ||
-e | ||
-s | ||
被操作文件 | *.c *.txt | 其他文件名 |
测试用例
测试用例 | 预期结果 |
wc.exe -c file.c | file.c,字符数:[数字] |
wc.exe -w file.c | file.c,单词数:[数字] |
wc.exe -l file.c | file.c,总行数:[数字] |
wc.exe -c -w -l file.c |
file.c,字符数:[数字] file.c,单词数:[数字] file.c,总行数:[数字] |
wc.exe -a file.c |
file.c,代码行数:[数字] file.c,空行数:[数字] file.c,注释行数:[数字] |
wc.exe -o outputFile.txt | 已存入执行结果 |
wc.exe -s | 对所有.c文件执行所有操作 |
wc.exe -e stopList.txt | 存入所有禁用单词 |
wccff.exe sff dfsffgg...c | 无操作 |
outputFile.txt -c -w-s-l-w | 无操作 |
七、测试结果
八、测试分析
基本实现文件所有操作,在输入检测方面,没有做全面,在一些非法操作符输入时,并不能正确处理,还需完善。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类