Word Count
github地址:https://github.com/imenist/WordCount
一.项目要求
1.wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数
2.实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。程序处理用户需求的模式为:wc.exe [parameter] [file_name]
3.基本要求:
wc.exe -c file.c //返回文件 file.c 的字符数
wc.exe -w file.c //返回文件 file.c 的词的数目
wc.exe -l file.c //返回文件 file.c 的行数
4.扩展功能:
-s 递归处理目录下符合条件的文件
-a 返回更复杂的数据(代码行 / 空行 / 注释行)。
5.高级功能:
-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
二.PSP表格
PSP2.1 | Personal Software Process Stages | 预估时间(分钟) | 实际耗时(分钟) |
Planning | 计划 | 10 | 10 |
-Estimate | -估计这个任务需要多少时间 | 265 | 400 |
Development | 开发 | 250 | 400 |
-Analysis | -需求分析(包括学习新技术) | 20 | 20 |
-Design Spec |
-生成设计文档 | 30 | 20 |
-Design Review | -设计复审(和同事审核设计文档) | 20 | 10 |
-Coding Standard | -代码规范(为目前得开发制定合适得规范) | 10 | 10 |
-Design | -具体设计 | 30 | 80 |
-Coding | -具体编码 | 90 | 200 |
-Code Review | -代码复审 | 30 | 10 |
-Test | -测试(自我测试,修改代码,提交修改) | 20 | 50 |
Reporting | 报告 | 50 | 60 |
-Test Report | -测试报告 | 30 | 40 |
-Size Measurement | -计算工作量 | 10 | 10 |
-Postmortem & Process Improvement Plan | -事后总结,并提出过程改进计划 | 10 | 10 |
合计 | 310 | 470 |
三.解题思路
1.基本要求:
- 统计字符数:一行一行地读取文件内容,然后统计各行的字符数,再累加。
- 统计单词数:一行一行读取文件,然后通过判断空格与字符的关系统计单词数,再累加。
- 统计行数:一行一行读取文件,直接累加
2.进阶功能
- 递归处理符合要求的文件:判断是否是文件还是文件夹,若是文件则返回,文件夹则继续递归直到找到文件,然后通过正则表达式筛选出符合要求的文件(一开始是想利用文件名的后缀名来进行简单的区分,然而这样不能够实现模糊搜索即匹配符,后来学习到使用正则表达式即可比较顺利的完成要求)
- 统计复杂数据(代码行 / 空行 / 注释行):一行一行的读取文件,设置布尔变量,若满足条件则累加
- 显示图形界面:调用java的Swing组建,进行控件布局的管理(一开始直接使用容器进行添加,发现运行的时候仅有最后一个添加的会显示出来,后来又找了许多文档以及查看了jframe的源码才找到问题所在,没有设置布局)
四.设计实现过程
1.主要类:
- main:项目的主函数
- wordCount:获得详细的数据,比如字符数,单词数等,作为对象返回
- readFile:读取文件
- travelFile:进行文件夹和文件的递归
- count:wordCount底下的方法,其中有多个方法进行数据的获取
- frameUI:进行gui界面的设计
2.程序运行流程图:
五.代码说明
1.返回字符数目
public int getCharNum(String str){ char[] cn = str.toCharArray(); return cn.length; }
2.返回单词数目
public int getWordNum(String str){ boolean flag = false; int num = 0; int length; char[] wn = str.toCharArray(); length = wn.length; for(int i=0;i<length;i++){ //当是一个新单词的时候才+1 if(((wn[i]>=65 && wn[i]<=90) || (wn[i]>=97 && wn[i]<=122)) && flag == false){ flag = true; num++; }else if((wn[i]>=65 && wn[i]<=90) || (wn[i]>=97 && wn[i]<=122)){ //如果不是新单词就跳过 continue; }else{ //一个单词结束时就设为false flag = false; } } return num; }
3.返回注释行数
public int getNoteLineNum(ArrayList<String> str){ int num = 0; boolean flag = false; for(int i=0;i<str.size();i++){ String temp = str.get(i).trim(); //单行注释直接+1 if(temp.startsWith("//")) num += 1; //多行注释,先+1并设置布尔变量,知道遇到*/才结束+1 else if(temp.startsWith("/*")){ num += 1; flag = true; } else if(temp.endsWith("*/")){ num += 1; flag = false; } else if(flag == true) num += 1; } return num; }
4.递归处理文件
ArrayList<String> pathsFile = new ArrayList<String>(); File file = new File(filesPath); //建立ft对象进行递归处理 fileTravel ft = new fileTravel(pathsFile,sy); ft.travel(file); int length = pathsFile.size(); //将得到的文件进行wordCount处理并输出 for(int i=0;i<length;i++){ String currentFile = pathsFile.get(i); wc.count(currentFile); System.out.println("文件:"+currentFile); switch (choose1){ case "-c" :System.out.println("文件字符数目:"+wc.getCharNum());break; case "-w" :System.out.println("文件单词数目:"+wc.getWordNum());break; case "-l" :System.out.println("文件行数:"+wc.getLineNum());break; case "-a" : System.out.println("文件字符数目:"+wc.getCharNum()); System.out.println("文件单词数目:"+wc.getWordNum()); System.out.println("文件行数:"+wc.getLineNum()); System.out.println("文件代码行数:"+wc.getCodeLine()); System.out.println("文件注释行数:"+wc.getNoteLine()); System.out.println("文件空行数:"+wc.getEmptyLine()); break; } } break; public class fileTravel { public ArrayList<String> filePaths; Matcher m ; String sy =null; public fileTravel(ArrayList<String> filePaths,String sy) { this.filePaths = filePaths; this.sy = sy; } public fileTravel(ArrayList<String> filePaths){ this.filePaths = filePaths; } public void travel(File file){ //通过正则表达式,进行通配符的查找并且筛选符合要求的文件(此处为txt文件) String sy1 = "^["+sy+"].*(.txt)$"; Pattern p = Pattern.compile(sy1); if(file == null) return; m = p.matcher(file.getName()); //当找到符合的文件时才将其放进文件的字符串数组中进行调用 if(m.find() || sy == null) filePaths.add(file.getAbsolutePath()); if(file.isDirectory()){ for (File files:file.listFiles()){ //当是文件夹时,继续进行递归 travel(files); } } } }
5.gui设计
public frameUI() { //获得Jframe对象 jFrame = new JFrame(); //设置标题 jFrame.setTitle("Word Count"); //设置窗口大小 jFrame.setBounds(600,600,800,100); jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE); //获得窗口对象进行编辑 jFrame.getContentPane().add(getContentPane()); this.setLayout(new FlowLayout()); //初始化窗口各控件参数 JLabel label = new JLabel(); label.setText("文件名称:"); JButton button = new JButton("选择文件"); JButton button1 = new JButton("选择文件夹"); JButton _c = new JButton("-c"); JButton _w = new JButton("-w"); JButton _l = new JButton("-l"); JButton _a = new JButton("-a"); JButton _s = new JButton("-s"); textField = new JTextField(20); //将各控件添加到窗口上 getContentPane().add(label); getContentPane().add(textField); getContentPane().add(button); getContentPane().add(button1); getContentPane().add(_c); getContentPane().add(_w); getContentPane().add(_l); getContentPane().add(_a); getContentPane().add(_s); //进行选择文件时,调用自带的fileChooser并获得文件对象,返回其路径于文本框中 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int i = fileChooser.showOpenDialog(getContentPane()); if(i == JFileChooser.APPROVE_OPTION){ selectedFile = fileChooser.getSelectedFile().getAbsoluteFile(); textField.setText(selectedFile.getName()); } } }); //选择_s函数时进行文件夹的递归,并自动将符合要求的文件以对话框的形式输出其数据 _s.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String filePaths = selectedFile.getAbsolutePath(); File currentFile = new File(filePaths); try { fileTravelUI(currentFile); } catch (Exception e1) { e1.printStackTrace(); } } });
六.测试运行
1.基本功能
- 空文件:
- 只有一个字符的文件:
- 只有一个单词的文件
- 只有一行的文件
- 一个典型的源文件
2.扩展功能(-a,-s)
3.高级功能(gui操作)
- 选择单个文件进行基本操作
- 选择文件夹进行递归
七.项目小结
第一次做个人项目,许多地方都不太熟练,光是理解题目就使用了不少的时间。在这个过程中我也学习到了许多以前不知道的知识
- 在文件筛选中,java的IO流搭配正则表达式可以处理绝大多数的文件筛选工作
- 在gui设计中,不同布局间的优劣也学习到了不少
- 在敲代码前,有一个PSP的计划表可以让我把时间利用得更好
- 通过自己一个人做项目也理解到了做项目不仅仅是敲代码,还有设计,思路等重要的工作
通过这一次的个人项目,我也了解到了自身的不足,会继续学习充实自我