码云地址:https://gitee.com/lzc396732672/WordCountTeam
作业地址:https://edu.cnblogs.com/campus/xnsy/2018softwaretest2398/homework/2116
学号:201631062332 201631062331
一:代码自审
本次作业过程中,修正了上次作业中代码的不规范性,同时扩充了WordCount中的功能:包括统计空行数量、注释行以及代码行。更为重要的是,在审查过程中,相互学习,将主程序与方法体分开实现更好地代码管理。另外针对有些命名、格式上的问题,参考阿里巴巴公司 java 规范的官方网站、谷歌的C++ 代码风格规范进行了调整。
二:代码互审
代码互审中,发现了设计缺陷和后门代码,而且让团队成员相互学习相互磨砥。本次互审过程中发现,大错误的比较相似,尤其是代码规范问题上,对于变量命名、缩进以及注释问题上很明显;另外在互审中发现队友中的一些小bug,例如有些注释行判断出错,面对多行注释无法检测等问题。另外,程序的稳定性不足,面对一些胡乱操作程序容易崩塌。
三 :功能扩充
在本次作业当中,我们结对编程,在以前的基础上补充了很多功能。包括递归处理目录下符合条件的文件; 返回更复杂的数据(代码行 / 空行 / 注释行),统计选择文件的信息。
//统计.C文件的信息
public void CountData(string filename) { int linesNumber = 0; //行数 int wordNumber = 0; //单词数 int charNumber = 0; //字符数 int nullNumber = 0; //空行数 int notesNumber = 0; //注释行数 List<string> word = new List<string>(); //停用词组 if (fileName != null) { if (File.Exists(fileName)) { FileStream fs = new FileStream(fileName, FileMode.Open); //打开待统计文件 StreamReader sr = new StreamReader(fs); if (StopList != null && File.Exists(StopList)) //当使用了停用词表 { FileStream f = new FileStream(StopList, FileMode.Open); //打开停用词表文件 StreamReader s = new StreamReader(fs); string buf; while ((buf = s.ReadLine()) != null) { string[] Str = buf.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < Str.Length; i++) { word.Add(Str[i]); //将停用词读入停用词组 } } } string line; //定义一个字符数组 char[] symbol = { ‘ ‘, ‘\t‘, ‘,‘, ‘.‘, ‘?‘, ‘!‘, ‘:‘, ‘;‘, ‘\‘‘, ‘\"‘, ‘\n‘, ‘{‘, ‘}‘, ‘(‘, ‘)‘, ‘+‘, ‘-‘, ‘*‘, ‘=‘ }; while ((line = sr.ReadLine()) != null) { linesNumber++; //统计行数 string[] str = line.Split(symbol, StringSplitOptions.RemoveEmptyEntries); wordNumber += str.Length; //统计单词数 for (int i = 0; i < str.Length; i++) { foreach (string s in word) { if (str[i] == s) { wordNumber--; //除去停用词表的单词数 break; } } } if (line.Length == 0) { nullNumber++; //统计空行数 } else { if (line.Contains("//")) //统计注释行数 { notesNumber++; } charNumber += line.Replace(" ", "").Length; //统计字符数 } } sr.Close(); LinesNumber = linesNumber; WordNumber = wordNumber; CharNumber = charNumber; NullNumber = nullNumber; NotesNumber = notesNumber; } else { Console.WriteLine("待统计文件不存在,请重新输入文件地址"); fileName = Console.ReadLine(); CountData(fileName); } } }
//执行命令
public void ExecutiveCommand(string[] str, int n) { bool isc = false; //是否执行“-c”命令 bool isw = false; //是否执行“-w”命令 bool isl = false; //是否执行“-l”命令 bool isa = false; //是否执行“-a”命令 bool iss = false; //是否执行“-s”命令 foreach (string s in str) { switch (s) //判断是否执行某命令 { case "-c": isc = true; break; case "-w": isw = true; break; case "-l": isl = true; break; case "-a": isa = true; break; case "-o": iso = true; break; case "-s": iss = true; List<string> list = new List<string>(); string[] strC = Directory.GetFiles(fileName.Remove(fileName.LastIndexOf("\\")), "*.c", SearchOption.AllDirectories); //获取目录下.c或.cs文件集合 string[] strCS = Directory.GetFiles(fileName.Remove(fileName.LastIndexOf("\\")), "*.cs", SearchOption.AllDirectories); foreach(string C in strC) { list.Add(C); } foreach (string CS in strC) { list.Add(CS); } FileName = list.ToArray(); //将检索到的文件导入FileName中 break; case "-x": OpenFileDialog openFile = new OpenFileDialog(); if (openFile.ShowDialog() == DialogResult.OK) //打开可是界面选择文件 fileName = openFile.FileName; CountData(fileName); //统计选定的文件信息 //返回所以统计信息 isc = true; isw = true; isl = true; isa = true; iso = true; break; default: break; } } //按固定格式输出统计信息 if (isc) Console.WriteLine(fileName + ",字符数:" + CharNumber); if (isw) Console.WriteLine(fileName + ",单词数:" + WordNumber); if (isl) Console.WriteLine(fileName + ",行数:" + LinesNumber); if (isa) Console.WriteLine(fileName + ",代码行/空行/注释行:" + "{0}/{1}/{2}", LinesNumber, NullNumber, NotesNumber); //递归处理目录下所有文件 if (iss) { if (n < FileName.Length) { Console.WriteLine(); fileName = FileName[n]; CountData(fileName); ExecutiveCommand(str, n); n++; } } // 按指定格式保存信息 if (iso) { if (isc) content.Add(fileName + ",字符数:" + CharNumber.ToString()); if (isw) content.Add(fileName + ",单词数:" + WordNumber.ToString()); if (isl) content.Add(fileName + ",行数:" + LinesNumber.ToString()); if (isa) content.Add(fileName + ",代码行/空行/注释行:" + LinesNumber.ToString() + "/" + NullNumber.ToString() + "/" + NotesNumber.ToString()); } }
//保存信息
public void Save() { if (iso) { if (OutfileName == null) OutfileName = "result.txt"; FileStream aFile = new FileStream(OutfileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); StreamWriter sw = new StreamWriter(aFile); foreach (string str in content) { sw.WriteLine(str); } sw.Close(); //释放文件 aFile.Close(); sw.Dispose(); //释放资源 aFile.Dispose(); Console.WriteLine("保存成功"); } }
//检测命令
public string[] Check(string[] str) { if (str.Length == 0) //未输入命令时输入命令 { str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); } if (str.Length == 1) { if (str[0] != "-x") //未正确输入“-x”命令 { Console.WriteLine("格式输入错误,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } else return str; } else { int i = 0; //所检测到的命令位置 foreach (string s in str) { i++; if (s.Contains(".c") || str.Contains(".cs")) //获取待统计文件 { fileName = s; } else if (s == "-x") //未正确输入“-x”命令 { Console.WriteLine("“-x”命令应独立使用,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } else if (s != "-c" && s != "-w" && s != "-l" && s != "-a" && s != "-s" && s != "-e" && s != "-o" && !s.Contains(".txt")) //检测是否为正确命令 { Console.WriteLine("{0}为非法命令,请重新输入", s); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } else if (s == "-o") //检测“-o”命令格式是否输入正确 { try { if (str[i].Contains(".txt")) //“-o”命令格式输入正确 OutfileName = str[i]; //获取输出文件 else //“-o”命令格式输入不正确 { Console.WriteLine("“-o”命令后应该接输出文件名,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } } catch //“-o”命令格式输入不正确 { Console.WriteLine("“-o”命令后应该接输出文件名,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } } else if (s == "-e") //检测“-e”命令格式是否输入正确 { try { if (str[i].Contains(".txt")) //“-e”命令格式输入正确 StopList = str[i]; //获取停用词表 else //“-e”命令格式输入不正确 { Console.WriteLine("“-e”命令后应该接停用词表文件名,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } } catch //“-e”命令格式输入不正确 { Console.WriteLine("“-e”命令后应该接停用词表文件名,请重新输入"); str = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return Check(str); } } } if (fileName == null) //检测是否输入待统计文件 { Console.WriteLine("请输入待统计文件"); fileName = Console.ReadLine(); while (!fileName.Contains(".c") && !fileName.Contains(".cs")) //检测文件格式是否正确 { Console.WriteLine("待统计文件应该为.c文件或.cs文件,请重新输入文件"); fileName = Console.ReadLine(); } } return str; } }
四:单元测试
五:系统测试结果
//基本功能
//拓展功能
六:性能测试
七:总结
结对编程虽然能够提高软件质量,但是在实施的过程中,出现了许多的矛盾冲突,我感受到结对编程和一个人的编程的有很多不同不同的。单人编程的时候不需要考虑代码的风格友好性和通用性。在审查同伴的代码中,我也发现了很严重的代码风格的问题,导致代码合并时非常困难,甚至出现了大量重构的情况。希望在下一次作业中,能够更融洽的发挥多人协作编程的优势,能够让1+1大于2。
参考文献
- 邹欣老师在讲义“现代软件工程讲义 3 代码规范与代码复审”中所讨论的有关代码规范与代码复审的内容。内容短小精炼,适合快速入门。
- 阿里巴巴公司 java 规范的官方网站:https://github.com/alibaba/p3c
- 谷歌的C++ 代码风格规范:https://google.github.io/styleguide/cppguide.html
- C++ 发明者主导的规范:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
- C# 语言的规范:简版, 讨论版
- Python 语言的规范: https://www.python.org/dev/peps/pep-0008/