• 软件工程 作业三


    软件工程 作业三


    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 + "
      ");//显示每一行内容
                  }
                  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 + "
      " + "单词总数" + wordCount + "
      " + "有效行数" + ValidLine + "
      词频统计:
      ";
              for (int i = 0; i < wFreq.length; i++) {
                  w = w + wFreq[i] + "
      ";
              }
              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的效果


  • 相关阅读:
    CRC全套算法 CRC4,CRC5,CRC7,CRC8,CRC16,CRC32,CRC32 mpeg-2
    ubuntu18.04使用vscode报pylint is not install错误
    [转]C结构体之位域(位段/位域)
    获取gcc和clang的内置宏定义
    Win10下使用MinGW到指定路径编译C-C++文件
    【YM】ssh命令 远程登录Linux
    Linux环境下搭建Qt5.9开发环境
    WSL-Ubuntu-更换apt源为阿里源
    git常用命令
    Lucene的基本使用
  • 原文地址:https://www.cnblogs.com/cxf1404445126/p/9750858.html
Copyright © 2020-2023  润新知