合作者:201631062507  201631062526(学号)

代码地址:https://gitee.com/WordCountMC/WordCountTeam

本次作业链接:https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188

1.结对项目PSP编写


    我们的项目于10月11日正式开始,在开始编写代码之前,我们先对我们如何完成项目以及对老师布置的作业等进行再一次的商定和讨论。并结合我们平时上课的时间以及项目外等因素,约定了我们一起进行结对编程的时间和地点。最后一起完成了PSP表格的填写:

PSP2.1

PSP阶段

预估耗时(分钟)

实际耗时(分钟)

Planning 计划  30  30
· Estimate · 估计这个任务需要多少时间  30  30
Development 开发  620  945
· Analysis · 需求分析 (包括学习新技术)  30  40
· Design Spec · 生成设计文档  20  30
· Design Review · 设计复审 (和同事审核设计文档)  30  60
· Coding Standard · 代码规范 (为目前的开发制定合适的规范)  30  40
· Design · 具体设计  40  45
· Coding · 具体编码  350  500
· Code Review · 代码复审  60  100
· Test · 测试(自我测试,修改代码,提交修改)  60  130
Reporting 报告  80  80
· Test Report · 测试报告  30  30
· Size Measurement · 计算工作量  20  10
· Postmortem & Process Improvement Plan .事后总结并提出改进计划  30  40
  合计  730  1055

总结分析:这次在项目完成后,发现预估时间和实际耗时相差比较大,其主要表现在开发阶段。由于我们在代码自审和互审阶段,都发现了编码所存在的不规范,所以花了更多的时间去修改代码。还有就是在编码的时候,我们要完成的内容比我们想象得要困难一点,所以在编码的时候花了更多的时间。最后就是测试,这次项目开发采用了TDD,我们要先编写测试代码,再实现接口,这与我们之间采用的方式也不同,所以也花了更多的时间。

2.代码互审


    2.1总体情况分析

        在审查之后发现,队友的代码已经根据了我们一起编写的小组编程规范进行了修改。修改后的代码风格简洁明了,非常容易理解和阅读。但是仍需注意的地方是,方法里的代码注释要写在对应代码的上面而不是后面,这样会使代码阅读更加清晰。除此之外,在互审之后,发现代码存在一个小bug需要进行改正。

   2.2 问题

        出现问题的模块在CountUtil类中的returnWords方法。

        问题是在测试时发现:当一个文件为空的时候,它会返回单词数为1,而且当有两个文件同时测试时,如果第一个文件的单词数比第二个文件的单词数多的话,只显示第一个的单词数。

   2.3  解决方法

        在问题提出后,我和队友一起解决了问题,发现问题出在每次统计单词数目所要用的StringBuffer没有进行清空的操作。

3.设计


   3.1 结构设计

         功能类:主函数类(WordCount类) 接口类(CountUtil类)

        系统分析与设计结对项目——WordCount

 

         WordCount类:

         系统分析与设计结对项目——WordCount

        CountUtil类:

       系统分析与设计结对项目——WordCount

    3.2 类间关系

    系统分析与设计结对项目——WordCount

   3.3 WordCount类的流程图

       系统分析与设计结对项目——WordCount

 

 

4.代码说明


 

    4.1扩展功能:

      (1)当输入-e时,后面跟停用词表stoplist.txt

         首先解析停用词表中的单词:

    /**
     * 用来解析停用词表中单词
     * **/
    public String[] stoplistWord(String stopList)
    {
        String lineString = null;
        String[] stopListBuffer = null;
        File sl = new File(stopList);
            try {
                BufferedReader br = new BufferedReader(new FileReader(sl));
                while((lineString = br.readLine())!=null) {
//当遇到空格的时候,就为一个单词
                    stopListBuffer = lineString.split("\\s+");
                }
                br.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
                
        return stopListBuffer;
    }

         然后判断文件中的单词是否是停用词表中的单词:

    /***
     * 
     * 判断该词是否存在于停用词表内
     * */
    public static boolean inStop(String str, String[] fileBuffer)
    {
        int count = 0;
        for(int i = 0;i<fileBuffer.length;i++) {
//将获得的单词,与停用词表中的单词一个一个的与进行比较
if(str.equals(fileBuffer[i])) { count++; } } if(count > 0) { return true; }else return false; }

       (2)当输入-a时,查询文件中的代码行数、注释行数、空行数

             getCodeLines() 函数:

        /**
	 * 查询文件的代码行数
	 * @param filePaths 所有有效文件的集合
	 * @return String类型 查询结果
	 */
	public String getCodeLines(Set<String> filePaths) {
		// 结果字符串
		String result = "";
		// 缓存变量
		String tmp = "";
		// 统计次数
		int count = 0;
		// 得到输入流
		FileInputStream is = null;
		InputStreamReader ist = null;
		BufferedReader br = null;
		try {
			for (String filePath : filePaths) {
				is = new FileInputStream(filePath);
				ist = new InputStreamReader(is);
				br = new BufferedReader(ist);
				while((tmp = br.readLine())!=null) {
					// 去除读取的空格,方便识别内容类型
					tmp = tmp.replace(" ", "");
					// 改行不为空,则计数+1
					if (!"".equals(tmp)&&!tmp.startsWith("//")&&tmp.indexOf("//")!=1) {
						count++;
					}
				}
				// 拼接结果字符串
				result+=filePath+CODE_LINES+count+SPACE;
				// 重置count计数变量
				count = 0;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				// 关闭输入流
				is.close();
				ist.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		return result;
 	}

            getEmptyLines() 函数:

        /**
	 * 查询文件的空行数
	 * @param filePaths 所有有效文件的集合
	 * @return String类型 查询结果
	 */
	public String getEmptyLines(Set<String> filePaths) {
		// 结果字符串
		String result = "";
		// 缓存变量
		String tmp = "";
		// 统计次数
		int count = 0;
		// 得到输入流
		FileInputStream is = null;
		InputStreamReader ist = null;
		BufferedReader br = null;
		try {
			for (String filePath : filePaths) {
				is = new FileInputStream(filePath);
				ist = new InputStreamReader(is);
				br = new BufferedReader(ist);
				while((tmp = br.readLine())!=null) {
					// 改行不为空,则计数+1
					if ("".equals(tmp)) {
						count++;
					}
				}
				// 拼接结果字符串
				result+=filePath+EMPTY_LINES+count+SPACE;
				// 重置count计数变量
				count = 0;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				// 关闭输入流
				is.close();
				ist.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		return result;
	}

            getNoteLines() 函数:

        /**
	 * 查询文件的注释行数
	 * @param filePaths 所有有效文件的集合
	 * @return String类型 查询结果
	 */
	public String getNoteLines(Set<String> filePaths) {
		// 结果字符串
		String result = "";
		// 缓存变量
		String tmp = "";
		// 统计次数
		int count = 0;
		// 得到输入流
		FileInputStream is = null;
		InputStreamReader ist = null;
		BufferedReader br = null;
		try {
			for (String filePath : filePaths) {
				is = new FileInputStream(filePath);
				ist = new InputStreamReader(is);
				br = new BufferedReader(ist);
				while((tmp = br.readLine())!=null) {
					// 去除读取的空格,方便识别内容类型
					tmp = tmp.replace(" ", "");
					// 改行不为空,则计数+1
					if (!"".equals(tmp)&&tmp.startsWith("//")||tmp.indexOf("//")==1) {
						count++;
					}
				}
				// 拼接结果字符串
				result+=filePath+NOTE_LINES+count+SPACE;
				// 重置count计数变量
				count = 0;
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				// 关闭输入流
				is.close();
				ist.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		return result;
	}

    (3)当输入-s时,递归处理目录下符合条件的文件

    /**
     * 得到输入文件中指定文件和指定文件夹下符合条件的文件
     * @param names 输入文件的集合
     * @param condition 文件夹下的筛选条件
     * @return Set<String>类型 所有指定文件和指定文件夹下符合条件的文件
     */
    public Set<String> getAllFileWithCondition(Set<String> names,String condition) {
        // 存储输入文件和输入文件夹下符合指定条件的文件的集合
        Set<String> filePaths = new HashSet<String>();
        for (String name : names) {
            File file = new File(name);
            if (file.isFile()) {
                filePaths.add(name);
            }else if (file.isDirectory()) {
                // 调用处理文件夹下查询符合指定条件的文件
                filePaths.addAll(getDirectoryFilesWithCondition(file, condition));
                }
            } 
        return filePaths;
    } 

    4.2高级功能:

      当输入-x的时候,打开图形化界面操作,调用getUI()方法

/**
     * 获得图形界面
     */
    public void getUI() {
        JFileChooser jFileChooser = new JFileChooser();
        JFrame jFrame = new JFrame("文件数据查询");
        Container container = jFrame.getContentPane();
        container.setLayout(null);
        
        JLabel hint = new JLabel("选择文件",Label.RIGHT);
        hint.setBounds(10,10,100,30);
        
        JTextField name = new JTextField();
        name.setBounds(80,10,190, 30);
        name.setEditable(false);
        name.setFont(new Font("dialog", 1, 15));
        name.setBackground(Color.WHITE);
        
        JLabel hint1 = new JLabel("输入停用词",Label.RIGHT);
        hint1.setBounds(10,58,100,30);
        
        JTextField wordList = new JTextField();
        wordList.setBounds(80,58,190, 30);
        wordList.setFont(new Font("dialog", 1, 15));
        wordList.setBackground(Color.white);
        
        JLabel hint3 = new JLabel("(单词之间用空格隔开)");
        hint3.setBounds(85,85,150,30);
        
        JButton confirm = new JButton("确定");
        confirm.setBounds(280,58,80,30);
        
        JButton choose = new JButton("选择...");
        choose.setBounds(280,10,80,30);
        
        JLabel hint2 = new JLabel("结果如下:");
        hint2.setBounds(10,100,190,30);
        
        JTextArea contents = new JTextArea();
        contents.setBounds(43,140,300,280);
        
        choose.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                int returnVal = jFileChooser.showOpenDialog(null);
                if(JFileChooser.APPROVE_OPTION == returnVal) {
                    filePaths.add(jFileChooser.getSelectedFile().getAbsolutePath());
                    name.setText(jFileChooser.getSelectedFile().getName());
                    contents.setText(performOperation());
                }
            }
        });
        
        confirm.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                CountUtil.USE_STOP = true;
                CountUtil.putInFile(wordList.getText()+" ", stopListPath);
                STOPLIST_FILE = stopListPath;
            }
        });
        container.add(hint);
        container.add(name);
        container.add(choose);
        container.add(contents);
        container.add(wordList);
        container.add(hint1);
        container.add(confirm);
        container.add(hint2);
        container.add(hint3);
        jFrame.setSize(400, 500);
        jFrame.setVisible(true);
        
    }
getUI()方法代码

相关文章: