软件工程:202103226-1 编程作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 作业链接
这个作业的目标 学习程序开发流程
学号 20188437

1.Gitee项目地址

2.PSP表格

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

3.解题思路

  • 需求分析

    • 1.输入参数为输入文本文件路径和输出文本文件路径。
    • 2.读取输入文本内容。
    • 3.统计文件的字符数。
    • 4.统计文件的单词总数。
    • 5.统计文件的有效行数。
    • 6.统计文件中各单词的出现次数。
    • 7.将统计结果输出到output.txt。
  • 解题思路

    • 1.输入参数从主函数变量中获取。
    • 2.用字节流读入文本数据转字符并设置编码格式。
    • 3.直接获取字符串长度。
    • 4.正则表达式匹配单词。
    • 5.正则表达式匹配换行符。
    • 6.用Map集合,改进4中的思路,将找到的单词放在Map中匹配,匹配失败则存储进Map中,匹配成功则相应key值+1。
    • 7.用打印流输出到ouput.txt文件。

4.代码规范

5.计算模块接口的设计与实现过程

  • Lib类
    • countLine()
Matcher m = Pattern.compile("(^|\n)\\s*\\S+").matcher(text);
    	lines = 0;
    	while (m.find())
    	{
    	    lines ++;
    	}

用正则表达式:(^|\n)\s*\S+ 匹配非空白字符的行累加统计。

  • countWord()
    调用setWordMap(),返回记录单词数量的变量的值。
  • setWordMap()
    用正则表达式:(|[A-Za-z0-9])([a-zA-Z]{4}[a-zA-Z0-9]*) 匹配符合题意的单词,如果该单词不存在于Map集合内,就要保存进去并计数。
  • getWordsTop10()
wordsMap =
    			wordsMap
                .entrySet()
                .stream()
                .sorted(Map.Entry.<String, Integer> comparingByValue() //按值降序
                        .reversed()
                        .thenComparing(Map.Entry.comparingByKey()))//按key字典序升序
                .limit(10)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new));

调用setWordMap(),对Map集合内的单词根据统计的数量进行降序排序,再对数量相同的单词进行字典序排序,用limit函数取前10个对象,最后返回Map集合。

  • countChar()
    直接用text.length()得到字符串长度并返回。

  • WordCount类

    • input()
FileInputStream in=new FileInputStream(file);
	        // size  为字串的长度 ,这里一次性读完
	        int size=in.available();
	        byte[] buffer=new byte[size];
	        in.read(buffer);
	        in.close();
	        this.text=new String(buffer,"UTF-8");

一次性读入,加快读取速度。

  • count()
    负责调用Lib类中的方法进行统计。
  • output()
    将统计结果输出到指定文件中。
  • main()
    主函数入口。

Map集合结构Map<String,Integer>

6.计算模块接口部分的性能改进

文件读取方式是影响程序速度的关键因素之一,对以下几种方式进行了测试。

测试样例:
characters: 19489429
words: 218
lines: 110406

1.按一次1024byte读

File file=new File(inputFileName);
        try
        {
            FileInputStream inStream=new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int length=-1;
            while( (length = inStream.read(buffer)) != -1)
            {
                bos.write(buffer,0,length);
            }
            bos.close();
            inStream.close();
            text=bos.toString();        
        }catch (Exception e) {
        	e.printStackTrace();
	}

平均运行时间:2400ms
2.按行读

File file=new File(inputFileName);
int len=0;
        StringBuffer str=new StringBuffer("");
        try {
            FileInputStream is=new FileInputStream(file);
            InputStreamReader isr= new InputStreamReader(is);
            BufferedReader in= new BufferedReader(isr);
            String line=null;
            while( (line=in.readLine())!=null )
            {
                if(len != 0)  // 处理换行符的问题
                {
                    str.append("\r\n"+line);
                }
                else
                {
                    str.append(line);
                }
                len++;
            }
            in.close();
            is.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        text=str.toString();

平均运行时间:2800ms
3.缓存流

BufferedReader inputBfd = null;   

        try {
            inputBfd = new BufferedReader(new InputStreamReader(new FileInputStream(inputFileName), "UTF-8"));  

            int charIndex = 0;
            StringBuilder stringBuilder = new StringBuilder();   
            while ((charIndex = inputBfd.read()) != -1) {
                stringBuilder.append((char) charIndex);
            }
            text = stringBuilder.toString();   
        }
        catch (Exception e)
        {
            System.out.print(e.getMessage());
            System.out.print("\n文件读出错!");
        }
        finally
        {
            if (inputBfd != null)
                inputBfd.close();   
        }

平均运行时间:2700ms
4.一次读完

File file=new File(inputFileName);
	    try {
	        FileInputStream in=new FileInputStream(file);
	        // size  为字串的长度 ,这里一次性读完
	        int size=in.available();
	        byte[] buffer=new byte[size];
	        in.read(buffer);
	        in.close();
	        this.text=new String(buffer,"UTF-8");
	    } catch (IOException e) {
	        e.printStackTrace();
	    }

平均运行时间:2200ms
根据测试结果可知,一次读完性能最优。

7.计算模块部分单元测试展示

统计文件的字符数(对应输出第一行):
只需要统计Ascii码,汉字不需考虑
空格,水平制表符,换行符,均算字符

测试样例:

测试结果:

统计文件的单词总数(对应输出第二行),单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
英文字母: A-Z,a-z
字母数字符号:A-Z, a-z,0-9
分割符:空格,非字母数字符号
例:file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词

测试样例:

测试结果:

统计文件的有效行数(对应输出第三行):任何包含非空白字符的行,都需要统计。

测试样例:

测试结果:

统计文件中各单词的出现次数(对应输出接下来10行),最终只输出频率最高的10个。
频率相同的单词,优先输出字典序靠前的单词。
例如,windows95,windows98和windows2000同时出现时,则先输出windows2000
输出的单词统一为小写格式

测试样例:

测试结果:

测试样例:

测试结果:

8.计算模块部分异常处理说明

  • 读文件错误处理

9.心路历程与收获

  • 学习了git相关的知识
  • 开发程序前的分析设计工作是非常重要的。
  • PSP表格是一种新的接触到的开发文档。它能提高我们开发的效率。
  • 了解了很多读写文件的方式,合理选择可以提高程序性能。
  • 意识到了正则表达式的重要性,学到了一些正则表达式的语法。
  • 先思考自己的解题思路,再去网上看看,说不定会有意想不到的技术供我使用学习。
  • 要养成良好的编程习惯,规范代码。
posted @ 2021-03-29 21:46  hlywww  Views(158)  Comments(0Edit  收藏  举报