第三次作业-结对编程(wordcount)

GIT地址https://github.com/gentlemanzq/WordCount.git
GIT用户名 gentlemanzq
结对伙伴博客地址
博客地址 https://www.cnblogs.com/gentlemanzq/
作业链接https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2882

这一次结对编程,怎么说呢。带来了一次不一样的编程体验,很难说清楚。具体后面再说,先看作业


  • 一.结对过程

照片如下:(一直很疑惑为什么后台更改的照片,前端不会更改,百度了也没有解决办法。将就看吧)


  • 二.PSP表格

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

 30 20

· Estimate

· 估计这个任务需要多少时间

 30 20

Development

开发

 670 740

· Analysis

· 需求分析 (包括学习新技术)

 180 180

· Design Spec

· 生成设计文档

 20 10

· Design Review

· 设计复审 (和同事审核设计文档)

 20 20

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 30 30

· Design

· 具体设计

 60 60

· Coding

· 具体编码

180 200

· Code Review

· 代码复审

 60 80

· Test

· 测试(自我测试,修改代码,提交修改)

 120 160

Reporting

报告

 85 105

· Test Report

· 测试报告

 45 60

· Size Measurement

· 计算工作量

 20 15

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 20 30
 

合计

 785 865


  • 三.解题思路

  1.首先拿到题目仔细阅读,理清题意。大致需要完成的功能都是关于字符操作和计数排序的操作。根据这几点需求,我们决定使用泛型Dictionary来完成这一系列操作。

  2.关于如何解题,是根据作业要求来的,首先需要将文件读入成一个字符串,然后对其进行操作,如果是统计字符数量和行数,需要借助Regex函数通过正则表达式 ‘’.‘’来统计除换行符之外的字符,最后加上换行符。(此处要注意换行符是两个字符)

  3.判断是否是单词的时候,先使用for循环将大小写统一转换为小写,重新定义一个新的Dictionary,然后使用笨办法if语句进行判断单词长度是否超过4个并且前四个是否是英文,如果满足条件则重新赋给新的dictionary。

  4.输出频率最高的10个词,如果频率最高则按字典序输出这个地方。将新的dictionary先用frequencies函数进行统计判断,然后将结果首先按照value值进行排序,然后再按照key值进行排序

  5.对每一个功能项进行封装,方便后面增加功能。

  6.考虑到以上涉及的知识,所以我们在编码前,首先参考了字典的用法,如何进行单词判断,如何按照key值和value值进行排序(参考这两篇博客【1】【2】)。其次是关于regex,正则表达式的使用(参考这篇博客【3】)。

  【1】:https://www.cnblogs.com/wt-vip/p/5997094.html

  【2】:https://blog.csdn.net/ybhjx/article/details/69668442

  【3】:https://blog.csdn.net/u012102536/article/details/85160138


  • 四.代码设计及接口封装设计

  1.首先对于每一个功能大致设置一个类,初步设计六个类,将除了program类其余放入function文件夹中,具体关系后面说明(PS:增加功能之后再添加)

 

  2.类与类之间的调用关系具体为:program类中调用path,linescount,asccount类。在asccount类中会调用linescount参与部分计算。wordcount调用ynword进行判断

  3.启动主函数在program类里面,如果要计算有多少个字符就调用ascount里面的agelife方法,如果要统计有多少行,就调用linescount中的lines方法。同理其余都是一样。

  4.基础功能的难点在于判断是否是单词,并且需要按照次数,字典序排序,在wordcount函数中先进行是否单词判断,此处调用ynword。具体设计见流程图

  5.单元测试设计,主要测试function文件夹中的功能函数,类图如下 (PS:单元测试代码后见代码复审)

  6.接口设计及特色,由于功能都具有各自特色,相互影响性不高,故将每个功能都单独成块,抽离出来。功能都单独返回值,不会在功能中输出。并将有用的参数通过ref传出。

  7.算法设计关键:行数 总字符数都是通过正则表达式的方式进行统计,判断单词出现频率,调用字典的封装好的函数。在判断是否是单词时,将文本读成字符串,字符串再通过正则表达式拆分成字符串数组。


  • 五.代码规范

  1.   不要冗余无用代码,过于冗余的代码可以清理一下,一些已经注释掉的代码可以删除

  2、不变的值,尽量写个常量类。

  3、尽量使用if{}else,不要一直if去判断。

  4、减少循环调用方法;减少IO流的消耗资源。

  5.   当一行代码太长时,将其截断成两行写。

  6.   常用缩进和换行,使代码层次清晰,明了。

  7.   注释的量不应该少于代码量的三分之一。ps(变量统一使用例如/// <param name="s">文件读入路径</param>的注释方式)

  8.   定义变量名字和方法名字的时候尽量使用英文缩写,或者拼音缩写,便于识别。

  9.   对泛型进行循环时,都采用foreach而不使用for。

  11. 对于功能函数写入一个function文件夹中,便于以后功能升级。

  12. 一屏原则:一个方法体的代码幅应该在一屏比较和合理;逻辑复杂的代码可以抽离出方法体。


  • 六.代码复审及部分单元测试

  1.在没有封装功能前,我们各自对对方写的代码进行第一次互审。耗时:20min

  2.在进行封装之后,我们一起针对几个模块功能进行审查,首先针对逻辑上第一个调用的计算行数的功能模块linescount。经过二人的审查,觉得代码没有问题。为了测试正确,此处进行单元测试。

public class linescountTests
    {
        [TestMethod()]
        public void linesTest()
        {
            path.s = @"D:\se.txt";
            int x = 0;//第一次测试时输入5,第二次输入0
            Assert.AreEqual(x, linescount.lines());
           // Assert.Fail();
        }
    }

  测试结果如下:此处第一次在记事本中输入两行测试成功,但是在输入0行时测试失败,此处出现大问题,当没有输入文本时,行数没有进行判断,所以出现错误。

  3.审查asccount类(ps:功能为统计有多少字符),经过检查之后,并未发现问题,于是进行单元测试。

 public class asccountTests
    {
        [TestMethod()]
        public void asccountsTest()
        {
            path.s = @"D:\se.txt";
            int num = 8;
            Assert.AreEqual(num, asccount.asccounts());
            //Assert.Fail();
        }
    }

  测试结果如下:当定义num=0,文本不输入字符时,出现测试错误。反应过来依旧是没有判断为零情况,所以才会出现错误。

  4.根据逻辑思维,由于想要审查countword类必须要先审查ynword,保证其正确性,故先审查ynword功能模块,经过前两次错误,此次审查小心谨慎,依旧没有发现问题。故接着进行单元测试

 public void ynword1Test()
        {
            int w = 1;
            string[] n = { "word1" };
            string[] newword = { "word1" };
            string[] test = ynword.ynword1(n, ref w);
            Assert.AreEqual(newword[0],test[0] );
        }

  5.使用10个不同测试样例,重复以上操作

 

  6.代码测试覆盖率,由于这个是社区版,没有测试覆盖率。

 


  • 七.异常处理

  1.关于输入路径,输出路径异常处理(暂时只想到路径异常)

 try
                {
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (args[i] == "-i") path.s = args[++i];//-i 命令行
                        else if (args[i] == "-n") max = Convert.ToInt32(args[++i]);//-n 命令行
                        else if (args[i] == "-o") path.outputpath = args[++i];//-o 命令行
                        else if (args[i] == "-m")
                        {
                            len = Convert.ToInt32(args[++i]);
                        }
                    }
                }
                catch
                {
                    Console.WriteLine("输入或者输出的路径有误");
                }
//---------------------------------------------------------
 try
                {
                    Console.WriteLine("不输入参数,请手动输入读入文件路径");
                    string s = Console.ReadLine();
                    path.s = s;
                    max = 10;
                    Console.WriteLine("请手动输入输出路径");
                    string s1 = Console.ReadLine();
                    path.outputpath = s1;
                }
                catch
                {
                    Console.WriteLine("输入或者输出的路径有误");
                }

 

  未处理:

 

  处理后:

 


 

  • 八.改进代码

  1.改进所用时间:45min+。

  2.刚开始结对编程的时候,第一时间想用数组,字符串数组来写的,但是在进行一定的编码后,觉得数组太麻烦,实在是不适合,故最后决定使用字典泛型。

  3.使用字典编程之后,刚开始所有功能模块都写在一起,代码耦合性太差了,后由于要增加功能,并且要进行封装接口,故把所有的功能模块都抽离出来,写入function文件夹

  4.刚开始统计行数和字符总数时,用的另外的方法,后面改进使用正则表达式的方式,提高效率。

  5.见效率分析图及最耗时函数

 


 

  • 九.部分代码展示

  1.统计行数展示:ps:需要注意0行的情况

 public static int lines()//统计文件中的行数
        {
            string str = File.ReadAllText(@path.s);
            int nr = Regex.Matches(str, @"\r").Count ;
            if (nr != 0)
                nr = nr + 1;
            return nr;
        }

  2.统计总字符个数展示:ps:需要注意换行符是/r/n两个字符。“.”只能统计/r不能统计/n故加上行数。需注意0个字符的情况。

 public static int asccounts()//打开文件并统计字符个数
        {
            string str = File.ReadAllText(@path.s);
            int num = Regex.Matches(str, @".").Count;
            if (linescount.lines() == 0)
                return num + linescount.lines();
            else
                return num + linescount.lines() - 1;
        }

  3.统计单词个数展示:ps:在这里统计单词数需要对每一个进行判断,调用了ynword,此处不展示,用的笨办法if多次判断

public static Dictionary<string, int> Countword()
        {
            
            string str = File.ReadAllText(@path.s);
            Dictionary<string, int> frequencies = new Dictionary<string, int>();
            string[] words = Regex.Split(str, @"\W+");
            int k = 0;
            string[] newwords = ynword.ynword1(words,ref k);
            string[] newwords1 = new string[k];
            for (int i = 0; i < k; i++)
            {
                newwords1[i] = newwords[i];
            }
            foreach (string word in newwords1)
            {

                if (frequencies.ContainsKey(word))
                {
                    frequencies[word]++;
                }
                else
                {
                    frequencies[word] = 1;
                }
            }
            return frequencies;
        }

  4.主函数展示: ps:此处由于增加功能,通过查阅资料,知道了命令行输入是存入args中的,故通过这种方式进行操作。

  static void Main(string[] args)
        {
            int temp = 0;
            int max = 0;
            int len = 0;
       //如果命令行有参数执行
if (args.Count() != 0) { for (int i = 0; i < args.Length; i++) { if (args[i] == "-i") path.s = args[++i];//-i 命令行 else if (args[i] == "-n") max = Convert.ToInt32(args[++i]);//-n 命令行 else if (args[i] == "-o") path.outputpath = args[++i];//-o 命令行 else if (args[i] == "-m") { len = Convert.ToInt32(args[++i]); } } if (path.s == null || path.outputpath == null)//路径为空则不存在 { Console.WriteLine("路径不正确,文件不存在"); } }
       //命令行无参数,执行
else { Console.WriteLine("不输入参数,请手动输入读入文件路径"); string s= Console.ReadLine(); path.s = s; max = 10; Console.WriteLine("请手动输入输出路径"); string s1 = Console.ReadLine(); path.outputpath = s1; } Dictionary<string, int> frequencies = function.wordcount.Countword();//调用wordcount中方法统计单词 Dictionary<string, int> dic1Asc = frequencies.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);//按照字典序进行排序 int sum = function.wordcount.sum1(dic1Asc);//计算出单词总数量 Console.WriteLine("字符数:"+asccount. asccounts());//计算出字符数量 Console.WriteLine("单词总数:" + sum); Console.WriteLine("行数:"+linescount. lines());//计算出行数 //先按照出现次数排序,如果次数相同按照字典序排序 Dictionary<string, int> dic1Asc1 = frequencies.OrderByDescending(o => o.Value).ThenBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value); foreach (KeyValuePair<string, int> entry in dic1Asc1) { if (temp == max) break; string word = entry.Key; int frequency = entry.Value; temp++; Console.WriteLine("{0}:{1}", word, frequency); } Console.ReadKey(); }

  • 十.总结

刚开始觉得结对编程没有太大的用处,但是通过这次结对编程的经历之后,感觉了结对编程的好处,1+1还真是大于2的。由于刚开始陷入了误区,纠结了许多小问题,通过搭档的提醒,一下子豁然开朗,一个人的主观思维是不完美的,只有通过和他人的合作,才能使得代码趋紧无错,满足所有情况。有了一个实时搭档,在编码时在旁边指出自己的不足和思维漏洞,这样提高了效率,降低了检查时重来的时间。此次收获良多。

 

转载于:https://www.cnblogs.com/gentlemanzq/p/10647267.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值