软件工程作业二

码云项目地址

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,然而并不会用...再研究一下

心得小结

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

原文地址:https://www.cnblogs.com/holmec/p/9663687.html