Welcome To iris's Blog

路漫漫其修远兮,吾将上下而求索。
扩大
缩小
……

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

这个作业属于哪个课程 2020春|W班 (福州大学)
这个作业的要求在哪里 寒假作业(2/2)——疫情统计
这个作业的目标 Git命令、Github Desktop使用,开发一个疫情统计程序
作业正文 寒假作业(2/2)
其他参考文献

Github仓库地址

giraffe28

PSP表格

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

我的解题思路

  • 首先,看了好几遍作业的要求。
  • 自己理解一下,就是:在命令行输入 $ java InfectStatistic list -date 2020-01-22 -log D:/log/ -out D:/output.txt
    其中,java InfectStatistic表示执行主类InfectStatistic,list为命令,
    程序从D:/log/目录下读取所有2020-01-22之前(包括2020-01-22)的日志文件,经过处理后将结果输出到D:/output.txt文件。
  • 程序流程图

设计实现

Province//保存排好序的各个省份
Parameters//保存参数信息
Regular//对应语句的正则表达式
Result//一个省份对应一个Result
ResultList//由Result组成

函数

parseOption//解析命令行传入的参数
getLogFiles//获得相关所有日志的文件路径
parseLog//解析一篇日志
getIpResult//使某省感染患者+n
getSpResult//使某省疑似患者+n
getCureResult//使某省治愈患者+n
getDeadResult//使某省死亡患者+n
getIpMoveResult//使省1感染患者+n,省2感染患者-n
getSpMoveResult//使省1疑似患者+n,省2疑似患者-n
getSpToIpResult//使某省疑似患者-n,感染患者+n
getSpClearResult//使某省疑似患者-n
mergeList//合并相同省份数据
outPut//将结果输出到-out指定文件

关键代码

1. Province类

public static class Province{
        public static String[] province= {"全国", "安徽", "澳门" ,"北京", "重庆", "福建","甘肃",
                "广东", "广西", "贵州", "海南", "河北", "河南", "黑龙江", "湖北", "湖南", "吉林",
                "江苏", "江西", "辽宁", "内蒙古", "宁夏", "青海", "山东", "山西", "陕西", "上海",
                "四川", "台湾", "天津", "西藏", "香港", "新疆", "云南", "浙江"};
        public static String getByIndex(int index){
            return province[index];
        }
    }

2. Parameters类

static class Parameters {
        String log;
        String out;
        String date;
        ArrayList<String> type;
        ArrayList<String> province;
        String[] args = null;
        String str1 = null;
        String str2 = null;
        String str3 = null;
        int i = 0;
        //仅为单元测试使用
        public Parameters(){
            log = null;
            out = null;
            date = null;
            type = null;
            province = null;
        }
        public  Parameters(String log,String out,String date,ArrayList<String> type,ArrayList<String> province){
            this.log = log;
            this.out = out;
            this.date = date;
            this.type = type;
            this.province = province;
        }
        public void setArgs(String[] args){
            this.args = args;
        }
        public String getArgsString(){
            String argsStr = "";
            for (String arg:args
                 ) {
                if(!arg.equals(null))
                    argsStr += arg + " ";
            }
            return argsStr;
        }
        public String getParameterString() {
            if(date != null) {
                str1 = "log: " + log + " " + "out: " + out + " " + "date: " + date + " ";
            }
            else{
                 str1 = "log: " + log + " " + "out: " + out + " " + "date: ";
            }
            for(i = 0,str2 = "type: ";i < type.size();i++){
                str2 += type.get(i).toString() + " ";
            }
            for(i = 0,str3 = "province: ";i < province.size();i++){
                str3 += province.get(i).toString() + " ";
            }
            str1+=str2 + str3;
            return str1;
        }
    }

3. Regular类

static class Regular{
        String regularOne = "\\W+ 新增 感染患者 \\d+人";
        String regularTwo = "\\W+ 新增 疑似患者 \\d+人";
        String regularThree = "\\W+ 感染患者 流入 \\W+ \\d+人";
        String regularFour = "\\W+ 疑似患者 流入 \\W+ \\d+人";
        String regularFive = "\\W+ 死亡 \\d+人";
        String regularSix = "\\W+ 治愈 \\d+人";
        String regularSeven = "\\W+ 疑似患者 确诊感染 \\d+人";
        String regularEight = "\\W+ 排除 疑似患者 \\d+人";
    }

4. Result类

 static class Result{
        String province;
        int ip;
        int sp;
        int cure;
        int dead;
        boolean isRefer;
        public Result(){
            this.province = null;
            this.ip = 0;
            this.sp = 0;
            this.cure = 0;
            this.dead = 0;
            this.isRefer = false;
        }
        public void setProvince(String province){
            this.province = province;
        }
        public void setIp(int ip){
            this.ip += ip;
        }
        public void setSp(int sp){
            this.sp += sp;
        }
        public void setCure(int cure){
            this.cure += cure;
        }
        public void setDead(int dead){
            this.dead += dead;
        }
        public void setRefer(boolean bool){
            this.isRefer = bool;
        }
        //得到指定类型输出
        public String getResultString() {
            return province + " " + "感染患者" + ip + "人" + " " + "疑似患者" + sp + "人" + " " +"治愈" + cure + "人" + " " + "死亡" + dead + "人";
        }
        public String getAssignResultString(Parameters parameters){
            String result = province + " ";
            for (String type:parameters.type
                 ) {
                if(type.equals("ip")){
                    result += " " + "感染患者" + ip + "人";
                }
                else if(type.equals("sp")){
                    result += " " + "疑似患者" + sp + "人";
                }
                else if(type.equals("cure")){
                    result += " " + "治愈" + cure + "人";
                }
                else if(type.equals("dead")){
                    result += " " + "死亡" + dead + "人";
                }
            }
            return result;
        }
    }

5. ResultList类

 static class ResultList{
        List<Result> resultList = new ArrayList<Result>();
        ResultList(){
             for(int i = 0;i < 35;i++){
                 Result result = new Result();
                 result.setProvince(Province.getByIndex(i));
                 resultList.add(result);
             }
        }
        /**
         *@描述  合并相同省份的数据
         *@参数  List<Result> currentResultList,Parameters parameters
         *@返回值  List<Result>
         *@创建人  221701101林露
         *@创建时间  2020/2/15
         */
        public  List<Result> mergeList(List<Result> currentResultList,Parameters parameters){
            for (Result currentResult:currentResultList
                 ) {
                for(int i = 0;i < 35;i++ ){
                    if(currentResult.province.equals(resultList.get(i).province)){
                        resultList.get(i).setIp(currentResult.ip + resultList.get(i).ip);
                        resultList.get(i).setSp(currentResult.sp + resultList.get(i).sp);
                        resultList.get(i).setCure(currentResult.cure + resultList.get(i).cure);
                        resultList.get(i).setDead(currentResult.dead + resultList.get(i).dead);
                        resultList.get(i).setRefer(currentResult.isRefer||resultList.get(i).isRefer);
                    }
                }
            }
            if(parameters.province.size() == 0)
                resultList.get(0).setRefer(true);
            else {
                for (String province:parameters.province
                     ) {
                    if(province.equals("全国"))
                        resultList.get(0).setRefer(true);
                }
            }
            return resultList;
        }
    }

6. parseOption()函数

public static Parameters parseOptions(String[] args) {
        Parameters parameters = new Parameters();
        parameters.setArgs(args);
        ArrayList<String> typeList = new ArrayList<>();
        ArrayList<String> provinceList = new ArrayList<>();
        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("-log")) {
                parameters.log = args[i + 1];
                i++;
            } else if (args[i].equals("-out")) {
                parameters.out = args[i + 1];
                i++;
            } else if (args[i].equals("-date")) {
                if (i == args.length - 1)
                    continue;
                else {
                    if (args[i + 1].substring(0, 1).equals("-"))
                        continue;
                    else {
                        parameters.date = args[i + 1];
                        i++;
                    }
                }
            } else if (args[i].equals("-type")) {
                for (int j = i+1; j < args.length; j++) {
                    if(!args[j].substring(0, 1).equals("-")) {
                        typeList.add(args[j]);
                        i++;
                    }
                    else
                        break;
                }
            } else if (args[i].equals("-province")) {
                for (int j = i+1; j < args.length; j++) {
                    if(!args[j].substring(0, 1).equals("-")) {
                        provinceList.add(args[j]);
                        i++;
                    }
                    else
                        break;
                }
            }
        }
        parameters.type = typeList;
        parameters.province = provinceList;
        return parameters;
    }

7. getLogFiles()函数

public static List<String> getLogFiles(Parameters parameters){
        File file = new File(parameters.log);
        File[] fileList = file.listFiles();
        String fileName = null;
        String latest = fileList[0].getName().substring(0,10);
        List<String> logFiles = new ArrayList<String>();
        try{
            for (int i = 0; i < fileList.length; i++) {
                fileName = fileList[i].getName();
                if(fileName.substring(0,10).compareTo(latest) > 0)
                    latest = fileName.substring(0,10);
                if(parameters.date != null){
                    if (fileName.substring(0,10).compareTo(parameters.date) <= 0) { //如果该文件的日期小于指定日期
                        logFiles.add(parameters.log + "\\" + fileName);
                    }
                }
            }
        }catch(NullPointerException e){
            e.printStackTrace();
        }
        if(parameters.date == null)
            parameters.date = latest;
        return logFiles;
    }

8. parseLog()函数

public  static List<Result> parseLog(String logPath,List<Result> resultList){// ,String date
        Regular regular = new Regular();
        List<Result> list = new ArrayList<Result>();
        File file = new File(logPath);
        if(file.isFile()){
            BufferedReader reader = null;
            try{
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
                String currentLine = null;
                while((currentLine = reader.readLine()) != null){
                   // 1、<省> 新增 感染患者 n人
                    if(currentLine.matches(regular.regularOne)){
                        getIpResult(currentLine,resultList);
                    }
                   // 2、<省> 新增 疑似患者 n人
                    else if(currentLine.matches(regular.regularTwo)){
                        getSpResult(currentLine,resultList);
                    }
                    //3、<省1> 感染患者 流入 <省2> n人
                    else if(currentLine.matches(regular.regularThree)){
                        getIpMoveResult(currentLine,resultList);
                    }
                    //4、<省1> 疑似患者 流入 <省2> n人
                    else if(currentLine.matches(regular.regularFour)){
                       getSpMoveResult(currentLine,resultList);
                    }
                    //5、<省> 死亡 n人
                    else if(currentLine.matches(regular.regularFive)){
                       getDeadResult(currentLine,resultList);
                    }
                    //6、<省> 治愈 n人
                    else if(currentLine.matches(regular.regularSix)){
                        getCureResult(currentLine,resultList);
                    }
                    //7、<省> 疑似患者 确诊感染 n人
                    else if(currentLine.matches(regular.regularSeven)){
                        getSpToIpResult(currentLine,resultList);
                    }
                    //8、<省> 排除 疑似患者 n人
                    else if(currentLine.matches(regular.regularEight)){
                       getSpClearResult(currentLine,resultList);
                    }
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return list;
    }

9. getIpResult()函数

其他 getSpResult()、getCureResult()、getDeadResult()、getIpMoveResult()、getSpMoveResult()、getSpToIpResult()、getSpClearResult()函数的代码也类似。

public static List<Result> getIpResult(String currentLine,List<Result> provincesResult){
        Pattern pattern1 = Pattern.compile("(.*) 新增");
        Pattern pattern2 = Pattern.compile("感染患者 (.*)人");
        Matcher matcher1 = pattern1.matcher(currentLine);
        Matcher matcher2 = pattern2.matcher(currentLine);
        if(matcher1.find()&&matcher2.find()){
            for (Result provinceResult:provincesResult
                 ) {
                if(provinceResult.province.equals(matcher1.group(1))) {
                    provinceResult.setIp(Integer.parseInt(matcher2.group(1)));
                    provinceResult.setRefer(true);
                }
            }
            provincesResult.get(0).setIp(Integer.parseInt(matcher2.group(1)));
        }
        return provincesResult;
    }

10. outPut()函数

public static void outPut(ResultList list,Parameters parameters) throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(parameters.out)),"UTF-8"));
        try {
                for (Result result : list.resultList
                ) {
                    //没有指定省份
                    if(parameters.province.size() == 0){
                        list.resultList.get(0).setRefer(true);
                        //在日志中出现
                        if(result.isRefer == true) {
                            //没有指定类型
                            if(parameters.type.size() == 0)
                                bw.write(result.getResultString());
                            //指定类型
                            else
                                bw.write(result.getAssignResultString(parameters));
                            bw.write("\n");
                        }
                        else
                            continue;;
                }
                    //指定省份
                    else{
                        for (String pro: parameters.province
                        ) {
                            //找到相应省份
                            if(pro.equals(result.province)){
                                //没有指定类型
                                if(parameters.type.size() == 0)
                                    bw.write(result.getResultString());
                                //指定类型
                                else
                                    bw.write(result.getAssignResultString(parameters));

                                bw.write("\n");
                            }
                        }
                    }
            }
            bw.write("// 该文档并非真实数据,仅供测试使用\n");
            bw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

关于单元测试

1. 解析日志函数测试(通过)

2. 新增感染患者函数测试(通过)

3.新增疑似患者函数测试(通过)

4.治愈患者函数测试(通过)

5.死亡患者函数测试(通过)

6.感染患者移动函数测试(通过)

7.疑似患者移动函数测试(通过)

8.疑似患者确诊函数测试(通过)

9.排除疑似患者函数测试(通过)

10.解析参数函数测试(通过)

11.main函数测试

12.测试用例














单元测试覆盖率优化/性能测试


我的代码规范

链接

心路历程与收获

虽然是一个简单的程序,但我只能说自己太菜了,只怪之前基础打的不够牢。除了认识JAVA,这次作业里的内容我真的……(都是什么鬼?)虽然一开始很艰难,但是最后也慢慢磨出来了,慢慢在黑暗之中看见了光明。这次的作业,我最大的收获就是get了单元测试!对我这种漏洞百出的代码简直就是仙丹啊!!只要试上几个测试用例就知道错在哪里了,特别是编程到最后,明明在IDEA上运行好好的,在命令行执行程序结果就不一样了,来几个测试用例…原来是编码问题啊…获益良多,以后必须养成写单元测试的好习惯。然后就是性能测试……什么东东?看来自己还是读书太少,只能说再接再厉吧!

WEB前端相关的5个仓库

1.VUE相关

vue-native-core
简介:Vue Native是一个使用JavaScript构建跨平台原生移动应用程序的框架继react-native之后,vue社区诞生了weex,之后又来个vue native

2.React相关

wired-elements
简介:一系列具有手绘外观的基本UI元素。这些可用于线框,模型,或只是有趣的手绘外观。

3.小程序相关

taro
简介:- 京东多端统一开发框架,支持用 React 的开发方式编写一次代码,生成能运行在微信小程序、H5、React Native 等的应用。

4.小程序相关

didi
简介:模仿滴滴打车微信小程序,持续更新中,有兴趣的小伙伴可以加入一起沟通交流噢。实现了主要的业务流程,数据封装和请求,本小程序仍会不断的更新...

5.桌面应用

proton-native
简介:有和react native一样的语法;可以与与现有的react redux库一起使用;跨平台;原生的组件,不再使用electron;与正常的node包兼容

posted @ 2020-02-18 02:24  a长  阅读(240)  评论(2编辑  收藏  举报