寒假作业(2/2)-疫情统计

这个作业属于哪个课程 2020春|W班(福州大学)
这个作业要求在哪里 寒假作业(2/2)
这个作业的目标 学习使用GIthub、编写疫情统计代码、了解PSP
作业正文  
其他参考文献 ...
GIthub仓库地址 https://github.com/pb-xxxx/InfectStatistic-main

 

一、对于《构建之法》的心得

第一章:概述

通过对第一章内容的阅读,了解到了计算机科学与软件工程的主要不同,在之前只是简单的了解不同区别在于实践与理论,阅读《构建之法》后了解到了更加细致的区别。

在书中提到“不再纠结科学和工程的问题,而是在不同的学习与工作阶段,投入到最适合的项目类型中”,当明白这些问题时,在接下来的学习中就更加明白自己的学习方向。

第二章:个人技术和流程

在第二章中了解到了PSP表格,了解了一些对整体项目的研发时各个过程的时间占比,接触到了单元测试,原来以为就是对程序不同模块的测试,通过单元测试可以对程序性能进行更深的优化,。

对于代码编程来说越来越实用的技巧和方法的了解,有益于代码的编写,对于原先的基础认知有了一些新的改变。

第三章:软件工程师的成长

了解了软件工程师的思维误区,一种是想要弄清楚所有细节,分析麻痹,一种是不分主次,想要解决所有以来问题,过于积极和过于依赖的两种思维误区,对不同思维误区的阅读发现作为一个软件工程师所需要的能力以及认知都需要达到一定的高度,总之发现软件工程师是一个很牛又很难的工作。

对于软件工程师的职业发展更是认识到了很多,自己距离软件工程师还有很远的一段距离。

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 80
Estimate 估计这个任务需要多少时间 900 1000
Development 开发 300 360
Analysis 需求分析 (包括学习新技术) 60 60
Design Spec 生成设计文档 60 120
Design Review 设计复审 60 40
Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 40
Design 具体设计 180 200
Coding 具体编码 300 420
Code Review 代码复审 60 80
Test 测试(自我测试,修改代码,提交修改) 120 100
Reporting 报告 120 150
Test Report 测试报告 120 150
Size Measurement 计算工作量    
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 50 70
合计   2480 2970

二、解题思路

1、了解并明白需求

需要你的程序能够列出全国和各省在某日的感染情况

命令行(win+r cmd)cd到项目src下,之后输入命令:

$ java InfectStatistic list -date 2020-01-22 -log D:/log/ -out D:/output.txt

会读取D:/log/下的所有日志,然后处理日志和命令,在D盘下生成ouput.txt文件列出2020-01-22全国和所有省的情况(全国总是排第一个,别的省按拼音先后排序)

全国 感染患者22人 疑似患者25人 治愈10人 死亡2人
福建 感染患者2人 疑似患者5人 治愈0人 死亡0人
浙江 感染患者3人 疑似患者5人 治愈2人 死亡1人
// 该文档并非真实数据,仅供测试使用

list命令 支持以下命令行参数:

  • -log 指定日志目录的位置,该项必会附带,请直接使用传入的路径,而不是自己设置路径

  • -out 指定输出文件路径和文件名,该项必会附带,请直接使用传入的路径,而不是自己设置路径

  • -date 指定日期,不设置则默认为所提供日志最新的一天。你需要确保你处理了指定日期之前的所有log文件

  • -type 可选择[ip: infection patients 感染患者,sp: suspected patients 疑似患者,cure:治愈 ,dead:死亡患者],使用缩写选择,如 -type ip 表示只列出感染患者的情况,-type sp cure则会按顺序【sp, cure】列出疑似患者和治愈患者的情况,不指定该项默认会列出所有情况。

  • -province 指定列出的省,如-province 福建,则只列出福建,-province 全国 浙江则只会列出全国、浙江

注:java InfectStatistic表示执行主类InfectStatistic,list为命令,-date代表该命令附带的参数,-date后边跟着具体的参数值,如2020-01-22。-type 的多个参数值会用空格分离,每个命令参数都在上方给出了描述,每个命令都会携带一到多个命令参数。

2、理清代码思路

首先,需要解析输入的命令行,所以需要一个命令行类,用于解析命令行文件,使用字符串数组将命令行储存并进行处理,其中注意到命令行的识别,对于错误的命令行输入要有报错以及提示。比如输入日志文件的地址不符合文件地址的标准,不是list命令等等。

其次,需要处理日志文件,对于传入的日志文件地址下的日志文件的处理,读取日志文件内容并进行处理后输出,所以需要一个日志文件类,其中大概包括以下方法:日志文件的读取、日志文件的处理和日志文件的输出。在日志文件的处理中要对不同的命令下的数组处理,输出按照需求规格输出等等。

最后列出一个各个类执行的顺序图。

三、实现过程

1、定义基本参数
public String logpath;//输入日志文件
public String outpath;//输出日志文件
public int[] type;//感染类型,为0不输出,为1输出
public String[] type_str={"感染患者","疑似患者","治愈","死亡"};
​
public int[] province;统计各省是否需要输出
public String[] province_str={"全国","安徽","北京","重庆","福建","甘肃",
        "广东","广西","贵州","海南","河北","河南","黑龙江","湖北",
        "湖南","吉林","江苏","江西","辽宁","内蒙古","宁夏","青海",
        "山东","山西","陕西","上海","四川","天津","西藏", "新疆",
        "云南","浙江","澳门","香港","台湾"};//各省名称
public int[][] per=new int[35][4];//各省不同类型患者人数统计
public String date_now;//将当前时间转换为固定格式
2、命令行处理

建立命令行类

class cmd{}

分解不同的方法:

首先建立public boolean cmd_e()方法对输入的命令行进行处理,将命令行装入字符串数组,数组每个单元代表不同的命令或数值,其中分为对不同命令-log-date-out的处理,分别判断是否符合并进行处理。get_logget_outget_dateget_type方法获得命令,默认命令输出,若判断失误则进行警告处理。

3、日志文件处理

建立文件处理类

class file_handle

分解不同的方法:

首先建立get_list方法对输入的命令行中的日志路径进行处理,将文件目录装入字符串数组,数组每个单元代表不同的文件,根据不同的文件读取文件内容,分别对文件内容进行处理public void deal_txt(String line),在方法中分别有对确证病例、疑似病例、治愈病例等的处理,对不同的省的不同病例进行管理。最后写日志文件,输出per`数组,得到最终的日志文件。

四、代码说明

  • cmd类(处理命令行)

    分解命令行,对不同的参数进行处理

    public boolean cmd_e()//对命令行不同的参数进行处理
    {
        int i;
        if (!cmd_str[0].equals("list")) {//判断是否是list命令
            System.out.println("命令行非list错误");
            return false;
        }
        for (i = 1; i < cmd_str.length; i++) {
            if (cmd_str[i].equals("-log")) {//读取-log参数
                i++;
                i = get_log(i);
                if (i == -1) {
                    System.out.println("log参数出错");
                    return false;
                }
            } else if (cmd_str[i].equals("-out")) {//读取-out参数
                i++;
                i = get_out(i);
                if (i == -1) {
                    System.out.println("out参数出错");
                    return false;
                }
            } else if (cmd_str[i].equals("-date")) {//读取date参数
                i++;
                i = get_date(i);
                if (i == -1) {
                    System.out.println("date参数出错");
                    return false;
                }
            } else if (cmd_str[i].equals("-type")) {//读取type参数
                i++;
                i = get_type(i);
                if (i == -1) {
                    System.out.println("type参数出错");
                    return false;
                }
            } else if (cmd_str[i].equals("-province")) {//读取province参数
                i++;
                i = get_province(i);
                if (i == -1) {
                    System.out.println("province参数出错");
                }
            }
        }
        
        return true;
    }
    ​
  • 其中方法的细化为:
    public int get_log(int m)
    public int get_log(int m)//获取日志文件的位置
    {
        if (m < cmd_str.length) {
            if (cmd_str[m].matches("^[A-Z]:\\\\(.+?\\\\)*$")) {//判断是否符合文件路径的正则表达式
                logpath = cmd_str[m];
            } else
                return -1;//如果不符合则会报错
        } else
            return -1;
        return m;
    }

    获取日志输出路径

    public int get_out(int m)
    public int get_out(int m) {//获取输出日志位置
        if (m < cmd_str.length) {
            if (cmd_str[m].matches("^[A-z]:\\\\(\\S+)+(\\.txt)$")) {//判断是否符合文件路径的正则表达式
                outpath = cmd_str[m];
            } else
                return -1;
        } else
            return -1;
        return m;
    }

    获取日期命令

    public int get_date(int m)
    public int get_date(int m)//获取日期
    {
        if (m < cmd_str.length) {
            if (date_now.compareTo(cmd_str[m]) >= 0) {//判断输入日期是否超过当前日期
                date_now = cmd_str[m] + ".log.txt";
            } else
                return -1;
        } else
            return -1;
        return m;
    }

    获取类型命令

    public int get_type(int m)
    public int get_type(int m)//获取类型
    {
        int n;
        n = m - 1;
        if (m < cmd_str.length) {
            for (int i = 0; i < 4; i++)//将type输出默认为不输出
            {
                type[i] = 0;
            }
            while (m < cmd_str.length) {
                if (cmd_str[m].equals("ip")) {//判断type后的参数
                    type[0] = 1;
                    m++;
                } else if (cmd_str[m].equals("sp")) {//疑似病例
                    type[1] = 1;
                    m++;
                } else if (cmd_str[m].equals("cure")) {//治愈
                    type[2] = 1;
                    m++;
                } else if (cmd_str[m].equals("dead")) {//死亡
                    type[3] = 1;
                    m++;
                } else
                    break;
            }
            m--;
        }
    ​
        if (n == m) {//表示type后面没有参数
            for (int i = 0; i < 4; i++) {
                type[i] = 1;//默认全部输出
            }
        }
        return m;
    }

    获取省份命令

    public int get_province(int m)
    public int get_province(int m) {//获取省份类型代码
        int n = m;
        if (m < cmd_str.length) {
            province[0] = 1;
            while (m < cmd_str.length) {
                for (int i = 0; i < province_str.length; i++) {//根据省份输出 使该省为可输出状态
                    if (cmd_str[m].equals(province_str[i])) {
                        province[i] = 1;
                        m++;
                        break;
                    }
                }
            }
        }
        if (n == m)
            return -1;
        return (m - 1);
    }
  • file_handle类(文件处理类)

    获取文本路径后读取文本内容

    public void read_txt(String log)
    public void read_txt(String log)//读取文本
    {
        try{
            BufferedReader br;
            FileReader pr=new FileReader(log);
            br=new BufferedReader(new InputStreamReader(
                    new FileInputStream(new File(log)), "UTF-8"));
            String contentLine;//按行读取
            while((contentLine=br.readLine())!=null){
                if (!contentLine.startsWith("//")){
                    deal_txt(contentLine);//对每行文件进行处理
                }
            }
        }catch(IOException ioe){
            ioe.printStackTrace();
        }
    }

    处理文本内容

    public void deal_txt(String line)
    public void deal_txt(String line)//对文本进行处理
    {
        String str1="(\\S+) 新增 感染患者 (\\d+)人";
        String str2="(\\S+) 新增 疑似患者 (\\d+)人";
        String str3="(\\S+) 感染患者 流入 (\\S+) (\\d+)人";
        String str4="(\\S+) 疑似患者 流入 (\\S+) (\\d+)人";
        String str5="(\\S+) 死亡 (\\d+)人";
        String str6="(\\S+) 治愈 (\\d+)人";
        String str7="(\\S+) 疑似患者 确诊感染 (\\d+)人";
        String str8="(\\S+) 排除 疑似患者 (\\d+)人";
    ​
        if(line.matches(str1))//确证患者增加
        {
            String[] txt_str=line.split(" ");//将文本按空格存入数组
            txt_str[3]=txt_str[3].replace("人","");
            int int1;
            int1=Integer.valueOf(txt_str[3]);//将数字字符转换为数字
            for(int i=0;i<province_str.length;i++)
            {
                if(txt_str[0].equals(province_str[i]))
                {
                    per[i][0]+=int1;//该省确诊人数增加
                    per[0][0]+=int1;//全国确诊人数增加
                    break;
                }
            }
        }
        else if (line.matches(str2))//疑似患者增加
        {
            ...
        }
        else if (line.matches(str3))//感染患者从省1流入省2
        {
            for(int i=0;i<province_str.length;i++)
            {
                if (txt_str[3].equals(province_str[i])) {//省2
                    per[i][0] += int3;
                    break;
                }
            }
            for(int j=0;j<province_str.length;j++)
            {
                if(txt_str[0].equals(province_str[j])){//省1
                    per[j][0]-=int3;
                    break;
                }
            }
        }
        else if(line.matches(str4))//疑似患者从省1流入省2
        {
           ...
        }
        else if (line.matches(str5))//死亡人数
        {
            ...
            for(int i=0;i<province_str.length;i++)
            {
                if(txt_str[0].equals(province_str[i]))
                {
                    per[i][3]+=int5;//该省死亡人数增加
                    per[i][0]-=int5;//该省感染人数减少
                    per[0][3]+=int5;//全国死亡人数增加
                    per[0][0]-=int5;//全国感染人数减少
                    break;
                }
            }
        }
        else if(line.matches(str6))//治愈人数
        {
            ...
        }
        else if (line.matches(str7))//疑似患者确诊感染
        {
           ...
        }
        else if (line.matches(str8))//排除疑似患者
        {
            ...
        }
    }

    输出日志文件

    public void write_txt()
    public void write_txt()
    {
        ...
            for(int i=0;i<province_str.length;i++)
            {
                if(province[i]==1)
                {
                    file_write.write(province_str[i]+" ");
                    for(int j=0;j<type.length;j++)
                    {
                        if(type[j]==1)
                        {
                            file_write.write(type_str[j]+per[i][j]+"人 ");//按省输出
                        }
                    }
                    file_write.write("\n");
                }
            }
    ...
    }

五、单元测试截图

  • 基础测试:只有基本的日志文件路径和日期,且日期为第一日

  • 扩大日期,检测是否全部统计

  • 增加省份数

  • 增加type命令,type命令无参数,检测是否会全部输出

  • type命令添加参数

  • 分别检测各个参数

  • type命令多个参数

  • 多个参数检测

  • 增加日期,增加文件数

六、代码规范链接

https://github.com/pb-xxxx/InfectStatistic-main/blob/master/221701303/codestyle.md

七、心路历程与收获

通过这次项目第一次接触到单元测试,同时也第一次学习性能测试,并且发现自己的代码有许多不规范的编写方式,仍然需要改进,发现自己还有许多学习的地方,在阅读《构建之法》后来了解了对于软件工程师还有自己专业的一些新的认知,自己在许多方面还不够了解,所以需要在接下来的学习中更加认真。

八、技术路线图相关的5个仓库

链接 简介
https://github.com/dypsilon/frontend-dev-bookmarks 一个巨大的前端开发资源清单
https://github.com/AlloyTeam/Mars 腾讯移动web前端知识库
https://github.com/justjavac/awesome-wechat-weapp 小程序开发资源汇总
https://github.com/necolas/normalize.css 一个可定制的css文件,使浏览器呈现的所有元素,更一致和符合现代标准。支持IE8+
https://github.com/sass/node-sass 动态CSS预编语言, 并有拥有强大sass compass的生态圈

猜你喜欢

转载自www.cnblogs.com/bo-box/p/12322972.html