zoukankan      html  css  js  c++  java
  • 软件工程作业二

    码云项目地址

    https://gitee.com/holmec/PersonalProject-Java

    PSP表格

    PSP2.1 个人开发流程 预估耗费时间(分钟) 实际耗费时间(分钟)
    Planning 计划 20 15
    · Estimate 明确需求和其他相关因素,估计每个阶段的时间成本 20 15
    Development 开发 350 390
    · Analysis 需求分析 (包括学习新技术) 40 35
    · Design Spec 生成设计文档 20 15
    · Design Review 设计复审 20 15
    · Coding Standard 代码规范 20 10
    · Design 具体设计 30 50
    · Coding 具体编码 120 180
    · Code Review 代码复审 40 15
    · Test 测试(自我测试,修改代码,提交修改) 60 70
    Reporting 报告 90 90
    · 测试报告 40 40
    · 计算工作量 20 20
    · 并提出过程改进计划 30 30

    解题思路描述

    • 刚看到题目的时候先分析了一下这道题的需求:
    1. 统计文本的字符数
    2. 统计合法的单词数
    3. 统计合法行数
    4. 统计最多的10个单词及其词频
    • 可见要统计首先得先从文件中获取数据,因为考虑到需要统计合法行数,所以我是想按行读取数据,而不是全部读取再来判断换行符之类的。按行读取数据后存储在ArrayList中,以便后续统计时调用,防止多次打开关闭文件造成不必要的异常。
    • 统计文本字符数:遍历列表,转换成字符串再转换成字符数组,遍历字符数组,判断是否是合法字符。
    • 统计合法单词数:遍历列表,转换成字符串,先判断字符串长度是否大于等于4(如果小于4,那肯定不是单词),通过split方法分割每行字符串。遍历分割后的字符串,定义一个标识符来标识是否合法,判断前四个字符串是否是英文字母,若为合法单词,添加到map里。
    • 统计合法行数:遍历列表,转换成字符串,判断字符串长度是否大于0,若大于0则为合法行。
    • 统计最多的10个单词及其词频:利用比较器进行排序。

    设计实现过程

    一、相关类的设计

    • File类:读取文件数据,写入数据到文件
    • Count类:统计函数的实现
    • Main类:其他类和函数的调用

    二、相关函数的设计

    1. File类:

    • readfile函数:从文件中按行读取数据并保存到ArrayList中
    • writefile函数:将统计得到的结果写入文件中

    2. Count类:

    • CountChars函数:统计文本字符数
    • CountWords函数:统计文本合法单词数
    • CountLine函数:统计文本合法行数
    • WordTop函数:统计最多的10个单词及其词频

    代码说明

    1. CountChars函数:

    public int CountChars(){ //统计文本字符数
    		int count=0;
    		for(int i=0;i<line.size();i++){ //遍历文本数据
    			String str=line.get(i); 
    			for(int j=0;j<str.length();j++){ //遍历每行字符串
    				char c=str.charAt(j);  //转换成字符
    				if(('A'<=c&&c<='Z')||('a'<=c&&c<='z')||c=='
    '||c=='
    '||c=='	'){
    					count++; //若为合法字符则计数
    				}
    			}	
    		}
    		return count;
    	}
    

    2. CountWords函数:

    public int CountWords(){ //统计文本合法单词数
    		int count=0;		
    		for(int i=0;i<line.size();i++){ //遍历文本数据
    			String str=line.get(i);
    			if(str.length()>=4){ //若该行字符串长度大于等于4,则该行可能存在合法单词
    				String[] words=str.split("[^a-zA-Z0-9]+"); //通过正则表达式匹配分隔符来分割字符串
    				for (String word:words){ //遍历分割后的字符串数组
    					int flag=0; //标识符标识是否为合法单词
    					char[] w=word.toCharArray();
    					for(int j=0;j<4;j++){ //遍历字符串数组的前四个字符
    						if(!(('A'<=w[j]&&w[j]<='Z')||('a'<=w[j]&&w[j]<='z'))){
    							flag=1;
    							break; //若不为英文字母则标识符赋值为1并跳出循环
    						}
    					}
    					if(flag==0){ //若为合法单词						
    						if(!map.containsKey(word)){ //该单词第一次出现
    							count++; //单词数加1
    							map.put(word, 1); //将键、值添加进map中
    						}
    						else{
    							int num=map.get(word); //该单词已出现过
    							map.put(word, ++num); //单词词频加1
    						}
    					}
    				}
    			}
    		}
    		return count;
    	}
    

    3. CountLine函数:

    public int CountLine(){ //统计文本合法行数
    		int count=0;
    		for(int i=0;i<line.size();i++){ //遍历文本数据
    			String str=line.get(i);
    			if(str.length()>0){ //若该行字符串长度大于0,则计数
    				count++;
    			}
    		}
    		return count;
    	}
    

    4. WordTop函数:

    public ArrayList WordTop(int count){ //统计最多的10个单词及其词频
    		ArrayList<Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet()); //定义一个list来存放排序后的单词及其词频
    		Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() { //重写比较器的排序函数
    
                @Override
                public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
                    if (o1.getValue() == o2.getValue()) {
                        return o1.getKey().compareTo(o2.getKey());
                    }
                    return o2.getValue() - o1.getValue();
                }
    
            });
    		if(count<=10){ //若单词数不大于10,则直接返回排序后的list
    			return list;
    		}
    		else{ //若单词数大于10,则将第10位以后的单词从list中移除再返回list
    			for(int i=list.size();i>=10;i--){
    				list.remove(i);
    			}
    			return list;
    		}
    	}
    

    单元测试

    设计了10个测试点:

    • 测试文件不存在
    • 测试空白行
    • 测试字母大小写是否区别
    • 测试长度小于4的行是否合法
    • 测试空白文件
    • 测试纯中文文件
    • 测试无合法单词
    • 测试合法单词数不大于10
    • 测试合法单词数大于10
    • 测试特殊分隔符

    测试代码

    package Test;
    
    import static org.junit.Assert.*;
    
    import java.util.ArrayList;
    
    import org.junit.Test;
    
    import WordCount.Count;
    import WordCount.File;
    
    public class CountTest {
    	String NoExist="D:\java练习\PersonalProject-Java\201621123033\NoExist.txt";
    	String test1="D:\java练习\PersonalProject-Java\201621123033\test1.txt";
    	String Blank="D:\java练习\PersonalProject-Java\201621123033\blank.txt";
    	String Chinese="D:\java练习\PersonalProject-Java\201621123033\test2.txt";
    	String NoWord="D:\java练习\PersonalProject-Java\201621123033\noword.txt";
    	String more10="D:\java练习\PersonalProject-Java\201621123033\test3.txt";
    
    	@Test
    	public void testreadfile() {
    		File file=new File();
    		ArrayList<String> line1=new ArrayList<>();
    		line1=file.readfile(NoExist);
    		boolean test1=(line1.equals(null));
    		assertEquals(test1,true);
    	}
    	
    	@Test
    	public void testCountChars() {
    		File file=new File();
    		ArrayList<String> line1=new ArrayList<>();
    		ArrayList<String> line2=new ArrayList<>();
    		
    		line1=file.readfile(Chinese);
    		line2=file.readfile(Blank);
    		
    		Count count1=new Count(line1);
    		Count count2=new Count(line2);
    		
    		int CountChars1=count1.CountChars();
    		int CountChars2=count2.CountChars();
    		
    		assertEquals(CountChars1,0);
    		assertEquals(CountChars2,0);
    	}
    
    	@Test
    	public void testCountWords() {
    		File file=new File();
    		ArrayList<String> line=new ArrayList<>();
    		
    		line=file.readfile(test1);
    		
    		Count count=new Count(line);
    		
    		int CountWords=count.CountWords();
    		int CountLine=count.CountLine();
    		
    		assertEquals(CountWords,5);
    		assertEquals(CountLine,5);
    		
    	}
    
    	@Test
    	public void testCountLine() {
    		File file=new File();
    		ArrayList<String> line=new ArrayList<>();
    		
    		line=file.readfile(test1);
    		
    		Count count=new Count(line);
    		
    		int CountLine=count.CountLine();
    		
    		assertEquals(CountLine,5);
    	}
    
    	@Test
    	public void testWordTop() {
    		File file=new File();
    		ArrayList<String> line=new ArrayList<>();
    		
    		line=file.readfile(more10);
    		
    		Count count=new Count(line);
    		int CountWords=count.CountWords();
    		
    		int WordTop=count.WordTop(CountWords).size();
    		
    		assertEquals(WordTop,10);
    	}
    
    }
    
    

    结果出现了error

    检查代码发现

    1.CountWords函数没有考虑到字符数小于4的字符串的情况↓

    更改后↓

    2.还有WordTop函数

    更改后↓

    3.还有大小写也有问题

    更改后↓

    4.增加了文件不存在时的提示信息

    再次测试

    分支覆盖率

    效能分析

    下了JProfiler,然而并不会用...再研究一下

    心得小结

    以前写代码的时候都没有太注意代码规范,命名类、函数、变量等都很随意,一开始写倒还好,写到后面就很容易忘记这个类、函数、变量是什么含义。这次按照要求,命名时规范化了,思路清晰了很多,就算不是一次性写完这个程序,后面再继续写的时候也很容易就能回忆起前面的内容。其实这个程序从实现上来说不难,但是后面测试的时候发现了很多逻辑上错误的地方。以前没有使用过测试工具来进行测试,也没有特别去想一些测试点来测试,这次学习了后觉得测试真的作用还是挺大的。还有之前写代码的时候都是直接大概有个思路就开始写,没有像老师作业要求里说的那样按步骤来写程序,这次按着步骤写程序,感觉确实比较有条理性,甚至感觉写出来的代码都比以前更有条理了。

  • 相关阅读:
    NSDate
    Info.plist字段列表详解
    面向对象编程思想以及强、弱引用总结
    分类(类别/Category)与 类扩展(Extension)
    UIAlertView
    SQLite3的运用
    快速创建单例
    C++ 常用设计模式
    I2S 总线学习:2-I2S驱动WM8978
    设计模式的七大原则
  • 原文地址:https://www.cnblogs.com/holmec/p/9663687.html
Copyright © 2011-2022 走看看