合作——独木不成林

  • Github项目地址:https://github.com/Lin-000/WordCount.git
  • 结对伙伴的作业地址:https://www.cnblogs.com/lazy-bear/p/11650424.html
  • 作业链接: https://www.cnblogs.com/harry240/p/11524113.html

代码规范

  • 基本命名规范:
    =》在命名时需要使用有意义的名称
    =》优先使用英文,如果英文没有合适的单词,可以使用拼音,如城市名称等
    =》禁止使用中文命名
    =》命名不能使用缩写,如必须写成 person,不能写成 per
    =》变量采用驼峰命名法
    =》第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母,例如:myFirstName、myLastName。
  • 布局规范:
    =》使用 Tab 缩进,缩进大小为4。
    =》【Visual Studio 2017 中设置方法:菜单工具-选项-文本编辑器-C#-制表符,把制表符大小和缩进大小设置成4,选中“保留制表符”,点确定】
    =》左右花括号必须独占一行,括号内容为空时可在一行
    =》【Visual Studio 2017 中设置方法:菜单工具-选项-文本编辑器-C#-代码样式-格式设置-新行】
  • 注释:
    =》对于复杂难理解的代码,要加上详细的注释,便于理解代码以及后续的代码复审。

PSP表格

PSP2.1 Personal Software Process Stages 预计耗时(分钟) 实际耗时(分钟)
Planning 计划 1200 1450
Estimate 估计这个任务需要多长时间 1200 1450
Development 开发阶段 (以下从需求分析到具体编码过程) 120+60*4+360=720 150+80*2+70+80+400=860
Analysis 需求分析(包括新技术学习) 120 150
Design Spec 生成设计文档 60 80
Design Review 设计复审(和同学审核设计文档) 60 80
Coding Standard 代码规范(为目前的开发制定规范) 60 70
Design 具体设计 60 80
Coding 具体编码 360 400
Code Review 代码复审 100 110
Test 测试(自我测试、修改代码、代码提交) 130 140
Reporting 报告 100 120
Test Report 测试报告 60 90
Size Measurement 计算工作量 40 60
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 50 70
total 总计 1200 1450

代码思路分析

  • 统计字符串中所有字符总数函数:用CharactersNum()函数,把文档中所有的字符串作为参数传入CharactersNum()函数,依次匹配字符串中的每个字符,对\s进行匹配,可利用 Matches()方法来逐个记录,最后返回字符串中所有字符总数
  • 统计字符串中所有单词总数函数:需要利用集合的思想,在集合中保存满足条件的单词,即至少由4个字母组成的单词,利用正则,匹配[A-Za-z]{4}[A-Za-z0-9]*(\W|$,最后返回满足这些条件的集合,
  • 统计字符串中文本行数函数:把文本内容即字符串作为函数的参数传入,对\r进行匹配,即换行符,利用正则的思想,Matches()中传入 \r,依次记录文本中 \r 的数量
  • 统计一个集合中单词出现的频率函数:在统计完字符串中所有单词之后,再依次遍历集合中每个单词,把单词保存在集合中,匹配的过程中,如果出现相同 的单词,就把单词对应的数量+1,没有相同的,就先把单词放入到集合中,最后返回记录的单词以及该单词对应出现的次数的集合
  • 找出单词字典中出现频率最高的n个单词函数:在完成统计一个集合中单词出现的功能之后,把返回值作为参数传入到该函数中,利用下标依次遍历,选择出符合条件的n个单词,并同时输出它们出现的次数
  • 将字符串写入文件函数:这部分是参考CSDN上面的,利用FileStream()来new一个对象,指定输入的文件,利用StreamWriter()所创建的对象,来把运行结果写入文件
  • 输出指定长度的单词词组(这里我们输出的词组中所有的单词的均满足要求:至少以4个英文字母开头):定义一个返回类型为字典的函数,接受已经筛选单个单词长度的返回结果List 集合和指定长度(WordNum)的参数,然后开始遍历接受的List 集合,把每WordNum个词组存到一个字典中。在把词组存入到字典之前,首先判断字典中是否存在该词组,若已经存在,则只把该词组的频率(该词组对应的值)+1,否则把该词组添加到字典中(同时,设定该词组的频率设为1)。
  • 声明:初次拿到题目时,就考虑到应该用正则表达式来匹配,然后去找了C#关于正则的相关API,知道了使用方式,代码中用到了很多正则知识。对于在命令行运行程序,并通过命令行输入字符串作为参数传递给 program.cs 这个问题,百度搜索。

流程图

  • 输出频率最高的num个单词:num为要输出的单词个数,dic.Count为要查找的字典的元素个数,x为临时变量

合作——独木不成林_第1张图片 合作——独木不成林_第2张图片

关键代码

  • 根据要求,我们将统计字符串中所有单词的总数( WordsNum.cs )、找出单词字典中出现频率最高的n个单词( MaxFrequence.cs )、统计字符串中所有字符总数 ( CharactersNum.cs ),这三个函数独立封装了起来,其中 program.cs 为主函数, programTests.cs 为单元测试函数。

合作——独木不成林_第3张图片

  • 统计字符串中所有单词的总数的函数 WordsNum.cs

 public class GetWordsNum
    {
        public static List WordsNum(string text)
        {
            List words = new List();
            MatchCollection matches = Regex.Matches(text, @"[A-Za-z]{4}[A-Za-z0-9]*(\W|$)"); // 利用正则实现匹配
            foreach (Match match in matches)
            {
                words.Add(match.Value);
            }
            return words;                                                                                                                 // 返回一个储存了所有单词的集合(包括重复的单词)
        }
    }
  • 找出单词字典中出现频率最高的n个单词 MaxFrequence.cs
 public class GetMaxFrequence   
    {

        /* 找出单词字典中出现频率最高的n个单词  */
        public static Dictionary MaxFrequence(Dictionary dic, int n)
        {
            // dic储存单词及出现频率的字典 n为需要输出单词个数
            Dictionary d = new Dictionary();
            int x = 0;
            // 判断需要的单词个数是否超出总单词个数
            if (n <= dic.Count)
            {
                x = n;
            }
            else
            {
                x = dic.Count;
            }
            while (d.Count < x)
            {
                List l = new List();    // 多个单词有相同频率时储存至这个临时集合中按字典顺序排序
                int maxValue = dic.Values.Max(); ;    // 单词的最高频率
                foreach (string s in dic.Keys)
                {
                    if (dic[s] == maxValue)                 // 获取拥有最高频率的单词
                    {
                        l.Add(s);                                   // 添加到临时集合中
                    }
                }
                foreach (string s in l)                       // 将单词从原来的字典中删除 准备下一次查找
                {
                    dic.Remove(s);
                }
                l.Sort(string.CompareOrdinal);
                foreach (string s in l)
                {
                    d.Add(s, maxValue);
                    if (d.Count >= x)                         // 获取到10个单词后就退出
                        break;
                }
            }
            return d;
        }
    }
  • 统计一个集合中单词出现的频率的函数

public static Dictionary WordFrequence ( List wordList )
        { 
            Dictionary dictionary = new Dictionary();
            foreach (string word in wordList)            // 遍历集合中每个单词
            {
                int value;
                if (dictionary.TryGetValue(word, out value))
                {
                    //  存在,则+1
                    dictionary[word] += 1;
                }
                else
                {
                    // 不存在,则添加到集合中
                    dictionary.Add(word, 1);
                }
            }
            return dictionary;
}
  • 统计满足 -m 功能的词组频率函数 CountPhrase.cs
public  class CountPhrase
{
        // wordList 为已经筛选后的四个字母以上的单词集合,wordGroupNum为长度
        public static Dictionary WordsGroups(List wordList, int wordGroupNum)
        {
            // 创建字典用于保存 -m 功能的字符数组
            Dictionary wordsGroup = new Dictionary();
            int i;
            int j = 0;
            // 循环判断 -m 后输入的数字,截取对应长度的词组
            for (i = 0; i <= wordList.Count - wordGroupNum; i++)
            {
                // str 用来临时存储当前单词个数为 wordGroupNum 的词组
                string str = "";
                for (j = i; j < wordGroupNum + i; j++)
                {
                    str += wordList[j];
                }
                // 对词组频率进行统计
                if (wordsGroup.ContainsKey(str))
                {
                    // 如果词组已经存在,则频率 +1
                    wordsGroup[str] += 1;
                }
                else
                {
                    // 否则加入新的字典中
                    wordsGroup.Add(str, 1);
                }
            }
            return wordsGroup;
        }
}
  • 统计字符串中所有字符总数的函数 CharactersNum.cs
public static int CharactersNum(string text)      // text为要统计的字符串
{
            int num = 0;
            num = Regex.Matches(text, @"[\S| ]").Count;
            return num;                                          // 返回字符总个数
}

代码复审

  • 部分函数功能内部的语句有的可以简化,然后我针对部分函数中的语句做了修改,在代码简洁的同时保证了功能的正确实现。(下面的性能测试图,是在最开始的代码基础上,改进之后做的分析。由于之前第一次完成性能测试时,没有及时截图,便对代码做了重新的优化,所以性能分析是最终优化后的)

  • 我们起初计划的是各自负责几个功能函数,最后把函数引入合并,在需要的地方调用函数。初步实现各自的功能函数之后,就开始把代码合并,复审的过程中,出现的大多问题是和命名规范相关的,这些问题导致合并的过程会被绕晕,很慢,然后我就重新统一命令规范,愉快的完成了代码合并,成功的实现了功能。

  • 当我把代码发给我的同伴时,检测在不同的环境下程序是否能够侦正常运行,当她在命令行输入之后,出现了以下问题

合作——独木不成林_第4张图片

  • 错误分析:提示显示 input.txt 文件和 output.txt 文件的路径有问题

  • 解决方法:原因是输入输出文件的路径不对,应该指定正确的路径,然后她按照我的文件路径新建对应的 input.txt 和 output .txt 文件,然后就可以正常运行啦。(路径是一个不能忽视的很重的小细节!!!)

代码实现过程(测试、分析)

  • 测试计算字符串中字符总数函数

合作——独木不成林_第5张图片

  • 测试计算字符串中行数总数函数(主要针对 \r )

合作——独木不成林_第6张图片

  • 测试计算字符串中、出现频率最高的10个单词总数函数

合作——独木不成林_第7张图片

  • 可点击【此结果的其他输出】 ,来查看测试结果,点击如下图:

合作——独木不成林_第8张图片

  • 测试统计指定长度的词组的频率函数

合作——独木不成林_第9张图片

  • 测试完成

合作——独木不成林_第10张图片

  • 初步性能分析图

合作——独木不成林_第11张图片

  • 详细性能分析

合作——独木不成林_第12张图片

  • 创建了多个测试用例

合作——独木不成林_第13张图片

  • 运行效果

=》待检测的文件 input.txt:

合作——独木不成林_第14张图片

=》命令行输入方式以及对应结果

合作——独木不成林_第15张图片

合作——独木不成林_第16张图片

=》命令行输入方式以及对应结果

合作——独木不成林_第17张图片

合作——独木不成林_第18张图片

=》命令行输入方式以及对应结果

合作——独木不成林_第19张图片

合作——独木不成林_第20张图片

收获 感受

  • 我负责的是基本功能中的统计某个单词的出现频率(只输出出现字数最高的10个)、接口封装、以及新增功能中的 -i 参数设定读入的文件路径和-n参数设定输出的单词数量和 -o 参数设定生成文件的存储路径,这次作业相对内容比较多,做的时间也很长,涉及到正则、封装、接口等知识,以及合并代码,PSP表格计划时间,做性能分析等过程,如果一个人完成的话,可能会延时比较长,进度会很慢,但这次两人合作结对编程,就进行的很顺利,我们合理的分配了任务,然后各自根据自己的空闲时间来安排进度,及时的沟通和交流,总体感觉很棒,在交流的同时,不仅解决了测试、以及封装等问题,也让我对Visual Studio 2017的使用更加熟悉了,知道了设置布局规范的快捷方式,创建单元测试的方式,以及把某个类独立出来,然后与主类建立一定的联系,再调用的方式,让我感受到了合作的力量。

你可能感兴趣的:(合作——独木不成林)