1.要求地址


2.PSP表格

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

3.解题思路描述

这次的项目是建立在上一次作业的项目的基础上,在功能上,主要有两个新增的地方:

  • 词组统计:能统计文件夹中指定长度的词组的词频
  • 自定义输出:能输出用户指定的前n多的单词与其数量

然后在设计上则是新增了GUI界面

词组统计的话,是使用了多重循环,分层进行判断,在存储方面也是使用了Map进行存储。

自定义输出的解题思路:戳这里戳这里戳这里

GUI界面使用了netbeans以及web来实现。

我对于GUI界面是使用了netBeans来实现,使用了文本框控件,菜单控件等来实现处理文件以及字符处理,通过给不同按钮添加相应事件,以此来实现不同的功能。

web界面的解题解题思路:戳这里戳这里戳这里


4.设计实现过程

一、相关类设计

  • WordDeal类,用于存放统计字符数、行数、单词数、词频等方法。
  • FileDeal类作为文件处理类,用于读取文件内容以及写入文件。
  • Test类,用于进行单元测试。​

二、相关函数设计

  1. FIleDeal类中的方法
    • FileToString方法实现读取一个文件,并且返回文件内容,保存在一个字符串中。
    • WriteToFile方法实现把统计结果写入指定文件。
  2. WordDeal类中的方法
    • getCharCount()方法实现统计字符数。
    • getLineCount()方法实现计算行数。
    • getWordCount()方法实现计算单词数。
    • getWordFreq()方法实现统计每一个单词的词频。
    • sortMap()方法实现对Map中的数据进行排序,先按词频数后按字典顺序。
    • ListToArray()方法实现取出词频数前十的数据。
    • getWordGroupFreq(int num)方法用于统计长度为num的词组
  3. ScDeal类中的方法
    • 初始化函数scDeal()
    • 判断输入函数judge()
    • ideal()是-i的处理函数
    • mdeal()是-m的处理函数
    • ndeal()是-n的处理函数
    • odeal()输出到文件函数
    • judge()判断各自输入然后调用不同的处理函数

三、GUI界面设计

  1. netBeans版本:
    • wGUI包下的Main类,使用netBeans设计其相关界面布局等。
  2. Web版本:
    • Main.jsp页面,用于基本界面的设计实现
    • show.jsp页面,用于表单提交处理界面的实现

5.代码说明

1.getWordGroupFreq(int num)函数

这个函数实现了统计指定长度的词组的词频信息,通过传入词组长度,然后遍历整个文件内容,先判断单词,再进行词组的判断。最后的存储还是使用Map来进行存储,以便于统计输出。

public Map getWordGroupFreq(int num) // 统计词组词频(单词:以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。)
{
    wordGroupFreq = new HashMap<String, Integer>();
    String t = text;

    String[] spWord = t.split("\\s+"); // 对字符串进行分词操作
    for (int i = 0; i < spWord.length - num + 1; i++) {
        String wordG = "";
        int isWG = 1;
        for (int j = i; j < i + num; j++) {
            if (spWord[j].length() < 4) { // 判断是否是单词,若不是,则直接不用考虑这个词组
                isWG = 0;
                break;
            } else {

                int flag = 1; // 判断字符串的前四位是否是英文字母
                char c;

                for (int k = 0; k < 4; k++) {
                    c = spWord[j].charAt(k);

                    if (!(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
                        flag = 0;
                    }
                }
                if (flag == 0) {
                    isWG = 0;
                    break;
                } else {
                    wordG = wordG + spWord[j] + " ";
                }
            }
        }

        if (isWG == 1 && wordG.trim().length() != 0) {
            if (wordGroupFreq.get(wordG.trim()) == null) { // 判断之前Map中是否出现过该词组
                wordGroupFreq.put(wordG.trim(), 1);
            } else {
                wordGroupFreq.put(wordG.trim(), wordGroupFreq.get(wordG.trim()) + 1);
            }

        }

    }

    return wordGroupFreq;
}

2.GUI界面主要函数

  1. 打开文件

    该函数用于实现菜单控件中打开文件的功能实现。通过选取文件,将文件内容显示到相应的地方。

        private void openFileActionPerformed(java.awt.event.ActionEvent evt) {                                         
            f = new Frame("my window");// 创建窗体对象
            f.setBounds(300, 100, 650, 600);// 设置窗体位置和大小
            open = new FileDialog(f, "打开", FileDialog.LOAD);
    
            open.setVisible(true);//显示打开文件对话框
    
            String dirpath = open.getDirectory();//获取打开文件路径并保存到字符串中。
            String fileName = open.getFile();//获取打开文件名称并保存到字符串中
    
            if (dirpath == null || fileName == null)//判断路径和文件是否为空
            {
                return;
            } else {
                text.setText(null);//文件不为空,清空原来文件内容。
            }
            File file = new File(dirpath, fileName);//创建新的路径和名称
    
            try {
                //BufferedReader bufr = new BufferedReader(new FileReader(file));//尝试从文件中读东西
                BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file), "gb2312"));
                String line = null;//变量字符串初始化为空
                while ((line = bufr.readLine()) != null) {
                    text.append(line + "\r\n");//显示每一行内容
                }
                bufr.close();//关闭文件
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }                                        
    
  2. 保存文件

    该函数用于将结果框中的内容保存为文件。

       private void saveFileActionPerformed(java.awt.event.ActionEvent evt) {           
            save = new FileDialog(f, "保存", FileDialog.SAVE);
    
            save.setVisible(true);//显示保存文件对话框
            String dirpath = save.getDirectory();//获取保存文件路径并保存到字符串中。
            String fileName = save.getFile();////获取打保存文件名称并保存到字符串中
    
            if (dirpath == null || fileName == null)//判断路径和文件是否为空
            {
                return;//空操作
            } else {
                file = new File(dirpath, fileName);//文件不为空,新建一个路径和名称
            }
            try {
                BufferedWriter bw = new BufferedWriter(new FileWriter(file));
    
                String text = result.getText();//获取文本内容
                bw.write(text);//将获取文本内容写入到字符输出流
    
                bw.close();//关闭文件
            } catch (IOException e1) {
                //抛出IO异常
                e1.printStackTrace();
            }
        }      
    
  3. 功能函数的调用

    这一类的方法是根据点击的不同按钮,对应实现不同的方法,并将结果进行展示。

        private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
            // TODO add your handling code here:
            String t = text.getText();
            WordDeal wd = new WordDeal(t);
            // 调用类中的方法获取相应的数值
            int charNum = wd.getCharCount();
            int wordCount = wd.getWordCount();
            int ValidLine = wd.getLineCount();
            Map<String, Integer> wordFreq = wd.getWordFreq();
    
            List sortMap = wd.sortMap(wordFreq);
    
            String[] wFreq = wd.ListToArray(sortMap);
    
            String w = "字符总数:" + charNum + "\r\n" + "单词总数" + wordCount + "\r\n" + "有效行数" + ValidLine + "\r\n词频统计:\r\n";
            for (int i = 0; i < wFreq.length; i++) {
                w = w + wFreq[i] + "\r\n";
            }
            result.setText(w);	//写入到相应的控件之中
    
    
        }        
    

6.回归测试

  1. 对原有函数的回归测试

    package junitTest;
    
    import static org.junit.Assert.*;
    import java.io.IOException;
    import java.util.*;
    import org.junit.Before;
    import org.junit.Test;
    import wCount.*;
    
    public class WordDealTest {
    
    	@Before
    	public void setUp() throws Exception {
    		
    	}
    
    	@Test
    	public void testGetCharCount() throws IOException {//统计字符数量测试
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");	
    		String text2 = fd.FileToString("text/text2.txt");	
    		String text3 = fd.FileToString("text/text3.txt");
    		String text4 = fd.FileToString("text/text4.txt");
    	
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		WordDeal wd3 = new WordDeal(text3);
    		WordDeal wd4 = new WordDeal(text4);
    
    		int cn1 = wd1.getCharCount();
    		int cn2 = wd2.getCharCount();
    		int cn3 = wd3.getCharCount();
    		int cn4 = wd4.getCharCount();
    		
    		assertEquals(0, cn1);
    		assertEquals(0, cn2);
    		assertEquals(80, cn3);
    		assertEquals(73, cn4);
    	
    	}
    	
    	@Test
    	public void testGetWordCount() throws IOException {//统计单词数量测试
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");
    		String text2 = fd.FileToString("text/text4.txt");
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		
    		int wn1 = wd1.getWordCount();
    		int wn2 = wd2.getWordCount();
    		
    		assertEquals(0, wn1);
    		assertEquals(3, wn2);
    	}
    
    	@Test
    	public void testGetWordFreq() throws IOException {//统计词频测试
    		Map<String,Integer> ans1 = new HashMap<String,Integer>();
    		Map<String,Integer> ans2 = new HashMap<String,Integer>();
    	
    		ans2.put("coverage", 1);
    		ans2.put("yizhishuijiao", 2);
    		
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");
    		String text2 = fd.FileToString("text/text4.txt");
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		
    		Map<String,Integer> wf1 = wd1.getWordFreq();
    		Map<String,Integer> wf2 = wd2.getWordFreq();
    		
    		assertEquals(ans1, wf1);
    		assertEquals(ans2, wf2);
    	}
    
    	@Test
    	public void testSortMap() throws IOException {//词频排序测试
    		
    		
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");
    		String text2 = fd.FileToString("text/text4.txt");
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		
    		Map<String,Integer> wf1 = wd1.getWordFreq();
    		Map<String,Integer> wf2 = wd2.getWordFreq();
    		
    		List lis1 = wd1.sortMap(wf1);
    		List lis2 = wd2.sortMap(wf2);
    		
    		//assertEquals(ans1, wf1);
    		//assertEquals(ans2, wf2);
    	}
    
    	@Test
    	public void testGetLineCount() throws IOException {//统计有效行数测试
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");
    		String text2 = fd.FileToString("text/text4.txt");
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		
    		int wn1 = wd1.getLineCount();
    		int wn2 = wd2.getLineCount();
    		
    		assertEquals(0, wn1);
    		assertEquals(4, wn2);
    	}
    
    	@Test
    	public void testListToArray() throws IOException {
    		
    		
    		FileDeal fd = new FileDeal();
    		String text1 = fd.FileToString("text/text1.txt");
    		String text2 = fd.FileToString("text/text4.txt");
    		String text3 = fd.FileToString("text/text5.txt");
    		
    		WordDeal wd1 = new WordDeal(text1);
    		WordDeal wd2 = new WordDeal(text2);
    		WordDeal wd3 = new WordDeal(text3);
    		
    		Map<String,Integer> wf1 = wd1.getWordFreq();
    		Map<String,Integer> wf2 = wd2.getWordFreq();
    		Map<String,Integer> wf3 = wd3.getWordFreq();
    		
    		List lis1 = wd1.sortMap(wf1);
    		List lis2 = wd2.sortMap(wf2);
    		List lis3 = wd3.sortMap(wf3);
    		
    		String[] s1 = wd1.ListToArray(lis1);
    		String[] s2 = wd2.ListToArray(lis2);
    		String[] s3 = wd3.ListToArray(lis3);
    	}
    
    }
    

    测试结果:

    软件工程 作业三

  2. 对新增函数的测试

    测试用例:
    软件工程 作业三

    测试代码:

    	@Test
    	public void testGetWordGroupFreq() throws IOException {//统计词组测试
    	
    		FileDeal fd = new FileDeal();
    		String text6 = fd.FileToString("text/text6.txt");
    		WordDeal wd6 = new WordDeal(text6);
    		Map<String,Integer> wf6 = wd6.getWordGroupFreq(3);	
    	}
    

    测试结果:
    软件工程 作业三


7.单元测试

  1. 对命令行版本项目的单元测试
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三

  2. 对web版本项目的单元测试

软件工程 作业三
软件工程 作业三
软件工程 作业三
软件工程 作业三
软件工程 作业三
软件工程 作业三
软件工程 作业三

  1. 对netBeans版本项目的单元测试
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三

8.效能测试

  1. 对命令行版本项目的效能测试
    软件工程 作业三

  2. 对web版本项目的效能测试

软件工程 作业三
软件工程 作业三
软件工程 作业三

  1. 对netBeans版本项目的效能测试
    软件工程 作业三
    软件工程 作业三
    软件工程 作业三

9.结对心得

这次的结对编程是针对一个项目进行的改进,因为这次的要求,命令行输入和GUI界面的实现是两个相对独立的版本,所以经过讨论以后,我们的分工基本还是由我写完新增函数以后,由每个人来实现一个版本,相对来说除了在调用函数方面,其他部分还是比较独立的,所以其实并没有很多结对的感觉,但是在最开始讨论的时候,每个人都还没有很清晰的认识这个过程,导致对这个项目各有各的看法,然后讨论的效率还是比较低,花了很长时间才得到的统一。所以这次编程并没有很多的感受到1+1>2的效果


相关文章: