系统分析与设计个人作业:WordCount
本次作业gitee地址:https://gitee.com/ackary/WordCount
一、项目简介
1.基础功能
基础功能部分主要实现的功能是统计一个程序设计语言源文件的字符数、单词数、行数,之后将统计结果输出到result.txt文件。可执行程序为wc.exe,实现形式如下:
wc.exe -c file.c //返回文件file.c的字符数
wc.exe -w file.c //返回文件file.c的单词数
wc.exe -l file.c //返回文件file.c的代码行数
wc.exe -o result.txt //将统计结果输出到文件result.txt
2.拓展功能
拓展功能部分实现的功能是递归处理目录下符合条件的.c源文件、返回每个文件对应的代码行/空行/注释行、建立一个停用词表stopList,使得在统计.c源文件的单词总数时,不统计该表中的单词。可执行程序为wcc.exe,实现形式如下:
wc.exe -c -w -l -s *.c //递归处理所有的.c源文件,返回对应的字符数,单词数,总行数
wc.exe -a -s *.c //递归处理所有的.c源文件,返回每个文件的“代码行/空行/注释行”
wc.exe -w -s *.c -e stopList.txt //递归处理所有的.c源文件,返回每个文件中除去停用词表中的单词数
二、PSP表格
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
30 |
70 |
· Estimate |
· 估计这个任务需要多少时间 |
600 |
840 |
Development |
开发 |
500 |
820 |
· Analysis |
· 需求分析 (包括学习新技术) |
100 |
130 |
· Design Spec |
· 生成设计文档 |
||
· Design Review |
· 设计复审 (和同事审核设计文档) |
||
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 |
50 |
· Design |
· 具体设计 |
40 |
30 |
· Coding |
· 具体编码 |
400 |
450 |
· Code Review |
· 代码复审 |
30 |
40 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
90 |
150 |
Reporting |
报告 |
30 |
50 |
· Test Report |
· 测试报告 |
||
· Size Measurement |
· 计算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
40 |
合计 |
560 |
940 |
三、解题思路
我实现了本项目的基础功能和拓展功能部分。由于基础功能部分实现起来较为容易,因此我直接将所有代码全部写在一个类basicCount中,按功能划分主要有统计功能模块(由函数wordCount()实现)、结果输出模块(在main()主函数中实现);至于拓展功能,我写了两个类,一个是wordCount主函数类,这个类对输入的命令进行解析,并调用outputCount中的方法,输出相应的结果;另一个是outputCount类,其中的方法实现统计功能,供主函数类调用。
1、基础功能
(1)、统计功能模块
该模块主要实现字符统计、单词统计、行数统计这三个基本功能,算法相对简单,基本思路就是使用Java IO流的知识逐字符的读取源文件file.c,通过readline()方法返回每一行字符的长度就是该行字符的个数;每次读完一行,对应的行数加1;当读取到 “ ,与 空格” 后对应的单词数加1。
(2)、结果输出模块
该模块就是通过获取对应指令然后输出对应的统计结果,‘-c’输出统计的字符总数,‘-w’输出统计的单词总数,‘-l’输出统计的文件总行数,‘-o’指定对应的输出文件。
2、拓展功能
(1)、停用词表的实现
对代码行、注释行、空行的判断这三个拓展功能的实现还是费了不少时间的,因为我需要根据这三种内容行的不同特征识别出相应的类型。这个部分我花了不少时间去网上寻找算法,同时也学习了正则表达式的内容,我实际开发时间与预估时间的差距大概就是在这个地方,总之费了我不少时间。最后找到了正则表达式如何匹配读取内容,详细见代码部分。
(2)、遍历文件目录
在读取用户命令的时候,会遇到-s命令,这时就需要递归检索当前目录下所有后缀为.c的文件。这里我采用的是在指定路径下递归匹配含特定字符的字符串的算法,大致原理如下:找到一个目录下的所有文件,然后再逐一和用户给定的文件名进行匹配,最后把匹配成功的文件名、文件路径存放在一个存储缓冲区里。这样,就实现了对当前目录下相同类型文件的读取。
四、程序设计
1、基础功能
(1)、命令处理及判断
要求程序处理的命令模式为:wc.exe [parameter] [input_file_name],代码如下:
public static void main(String[] args) throws IOException{
basicCount WC=new basicCount();
String inputFile="file.c";
String outputFile="result.txt"; for(int i=0;i<args.length;i++){
if(args[i].endsWith(".c"))
inputFile=args[i];
if(args[i].equals("-o"))
outputFile=args[i+1];
}
WC.wordCount(inputFile); for(int i=0;i<args.length;i++)
{
switch(args[i]){
case "-c":{
System.out.println("字符个数:" + charNum);
break;
}
case "-w":{
System.out.println("单词个数:" + wordNum);
break;
}
case "-l":{
System.out.println("文件总行数:" + lineNum);
break;
}
case "-o":{
String resultTxt="";
for(int j=0;j<args.length;j++){
if(args[j].equals("-c"))
resultTxt=resultTxt+"\r\n"+"字符个数:" + charNum;
if(args[j].equals("-w"))
resultTxt=resultTxt+"\r\n"+"单词个数:" + wordNum;
if(args[j].equals("-l"))
resultTxt=resultTxt+"\r\n"+"文件总行数:" + lineNum;
}
break;
}
}
}
}
(2)、文件读取和计数
public void wordCount(String inputFile) throws IOException{
String lineString = null;
String[] buffer;
File infile=new File(inputFile);
BufferedReader bf = new BufferedReader(new FileReader(infile));
while((lineString=bf.readLine())!=null){
buffer=lineString.split(",| "); //当读取到“ ,与 空格”后,结束赋值
for(int i=0;i<buffer.length;i++){
if(!buffer[i].equals(""))
wordNum++;
}
lineNum++;
charNum+=lineString.length();
}
bf.close();
}
(3)、输出结果到指定文件
File outfile = new File(outputFile);
outfile.createNewFile(); // 创建新文件
BufferedWriter bw = new BufferedWriter(new FileWriter(outfile));
bw.write(resultTxt);
bw.flush(); // 将缓存区内容压入文件
bw.close(); //关闭文件
2、拓展功能
(1)、实现统计功能的函数模块
public static void count(String inputFile,String stopFile) throws IOException {
String lineString = null;
String[] buffer;
String[] buffer1=null;
File infile = new File(inputFile);
BufferedReader bf = new BufferedReader(new FileReader(infile));
if(isStop){
File file=new File(stopFile);
BufferedReader bff = new BufferedReader(new FileReader(file));
while((lineString=bff.readLine())!=null){
buffer1=lineString.split(",| ");
}
bff.close();
} lineString=null;
// 定义匹配每行的正则匹配器
Pattern notePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",
Pattern.MULTILINE + Pattern.DOTALL); // 注释匹配器(匹配单行、多行、文档注释)
Pattern emptyPattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回车、tab键、空格) try {
while ((lineString = bf.readLine()) != null) {
buffer = lineString.split(",| "); //当读取到“ ,与 空格”后,结束赋值
for (int i = 0; i < buffer.length; i++) {
if(isStop) {
if (!buffer[i].equals("")&&!inStopList(buffer[i], buffer1))
wordNum++;
}
}
lineNum++;
charNum += lineString.length(); if (notePattern.matcher(lineString).find()) {
noteNum++;
}
if (emptyPattern.matcher(lineString).find()) {
emptyNum++;
} else {
codeNum++; // 除空白行和注释行外,其余皆为代码行
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bf.close(); // 关闭文件输入流并释放系统资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)、判定停用词和遍历文件模块
/*判断读取内容是否在停用表内,即读取单词是否为停用词*/
public static boolean inStopList(String str,String[] buffer){
int count=0;
for(int i=0;i<buffer.length;i++){
if(str.equals(buffer[i])){
count++;
}
}
if(count>0)
return true;
else
return false;
} /*遍历文件内容*/
public static List<File> getFile(File dir) {
List<File> files = new ArrayList<File>();
File[] subs = dir.listFiles(); //读取当前文件下的所有文件、文件夹
for (File file : subs) {
if (file.isFile() && file.getName().endsWith(endString)) {
files.add(file);
} else if (file.isDirectory())
files.addAll(getFile(file)); //若读取到目录,就对当前目录递归读取
}
return files;
}
(3)、wordCount主函数
public class wordCount {
public static void main(String[] args) throws IOException {
outputCount WC = new outputCount();
String inputFile = "file1.c";
String stopFile = "stopList.txt";
String outputFile = "result.txt"; for (int i = 0; i < args.length; i++) {
if (args[i].endsWith(".c"))
inputFile = args[i];
if (args[i].equals("-o"))
outputFile = args[i + 1];
if (args[i].equals("-e")){
outputCount.isStop=true;
if((i!=(args.length-1))&&args[i+1].endsWith(".txt"))
stopFile=args[i+1];
}
} boolean flag=false;
for(int i=0;i<args.length;i++){
if(args[i].equals("-s"))
flag=true;
}
if(flag){
for (int i = 0; i < args.length; i++) {
if ((args[i].indexOf("*") != -1)) {
outputCount.endString = args[i].substring(args[i].lastIndexOf("*") + 1, args[i].length());
outputCount.getPath = args[i].substring(0, args[i].lastIndexOf("*"));
if (outputCount.getPath.equals(""))
outputCount.getPath = ".";
}
}
File dir = new File(outputCount.getPath);
List<File> files = outputCount.getFile(dir);
for (File file : files) {
outputCount filesWC = new outputCount();
String filePath = file.getAbsolutePath();
filesWC.count(filePath, stopFile);
filesWC.output(args, filePath, outputFile, filesWC);
outputCount.lineNum=outputCount.wordNum=outputCount.charNum=outputCount.codeNum=outputCount.emptyNum=outputCount.noteNum=0;
}
}
else{
WC.count(inputFile, stopFile);
WC.output(args, inputFile, outputFile, WC);
}
}
}
五、代码测试
1、基础功能测试
(1)、字符统计测试
输入:wc.exe –c file.c
期望输出:字符个数:244
实际输出:字符个数:244
分析:符合预期
(2)、单词统计测试
输入:wc.exe –w file.c
期望输出:单词个数:49
实际输出:单词个数:49
分析:符合预期
(3)、行数统计测试
输入:wc.exe –l file.c
期望输出:文件总行数:19
实际输出:文件总行数:19
分析:符合预期
(4)、输出文件测试
输入:wc.exe -c -w -l file.c -o result.txt
期望输出:
字符个数:244
单词个数:49
文件总行数:19
实际输出:
字符个数:244
单词个数:49
文件总行数:19
分析:符合预期
2、拓展功能测试
(1)、停用词表的测试
输入:wcc.exe -w -s file1.c -e stopList.txt
(源文件file1.c中有49个单词,停用词表中有两个相同单词,故除去停用词表的单词,应该输出的单词数为47)
分析:符合预期
(2)、打印“代码行/空行/注释行”的测试
输入:wcc.exe -a file1.c
分析:符合预期
(3)、遍历文件并打印计数结果的测试
输入:wcc.exe -c -w -l -s -a *.c -e stopList.txt
分析:符合预期
六、参考文献链接
使用exe4j将java文件打成exe文件运行详细教程:https://blog.csdn.net/zzzgd_666/article/details/80756430
FileInputStream、InputStreamReader和BufferedReader几种读取文件的区别:https://blog.csdn.net/pkx1993/article/details/80991812
Java中main方法参数String args[]的使用:https://www.cnblogs.com/xy-hong/p/7197725.html
正则表达式详解:https://www.cnblogs.com/crystaltu/p/5883955.html
七、项目总结
总的来说,我个人认为我这次的项目还存在一定的不足之处,我虽然实现了基础功能和拓展功能,但是对于代码框架的架构还有不足,有些功能的实现过程也不够简洁。同时呢,本次的项目让我还是有较大的收获。首先,通过本次作业,我对于Java的知识有了进一步的了解,因为我本身对Java的了解不是很多,而这次的作业我之所以选择用Java语言来编写,最主要还是想要通过实际的编程来提高我对这门语言的了解,结果我还是比较满意的,我确实收获了许多有关Java的知识,特别是Java IO部分的知识,这对于我的学习非常有用;其次呢,通过本次作业,我也对《系统分析与设计》这门课程理解更深了,作为程序员,我们不仅要有良好的编程基础,还要熟练掌握对代码的测试能力,更要有对一个项目的整体把控能力,我认为这次填写的PSP表格就是对于我们有关这方面的很好训练,我也会在今后的项目过程中不断强调自己这样去做,这是我们所需要具备的能力。
系统分析与设计个人作业:WordCount的更多相关文章
- 系统分析与设计结对项目——WordCount
结对项目完成WordCount 合作者:201631062507 201631062526(学号) 代码地址:https://gitee.com/WordCountMC/WordCountTeam ...
- 结队第二次作业——WordCount进阶需求
结队第二次作业--WordCount进阶需求 博客地址 051601135 岳冠宇 博客地址 051604103 陈思孝 博客地址 Github地址 具体分工 队友实现了爬虫功能,我实现了wordco ...
- 系统分析与设计lesson6
| 分类 作业 | 1.用例建模 a. 阅读 Asg_RH 文档,绘制用例图. 按 Task1 要求,请使用工具 UMLet,截图格式务必是 png 并控制尺寸 b. 选择你熟悉的定旅馆在线服务系统 ...
- FPGA最小系统分析与电路设计
<FPGA最小系统分析与电路设计> 部分节选自<FPGA应用开发入门与典型.pdf > FPGA最小系统包括:FPGA芯片.下载电路.外部时钟.复位电路和电源. 如果使用NIO ...
- 文献综述十六:基于UML的中小型超市管理系统分析与设计
一.基本信息 标题:基于UML的中小型超市管理系统分析与设计 时间:2016 出版源:Journal of Xiangnan University 文件分类:uml技术系统的研究 二.研究背景 开发一 ...
- WordCount系统分析与设计作业
Gitee项目地址 https://gitee.com/gitdq/homework psp表 PSP2.1 PSP阶段 预估耗时 (分钟) 实际耗时 (分钟) Planning 计划 10 10 · ...
- 系统分析与设计——WordCount
成果: https://gitee.com/ZMLJZ/codes/0k19q4upgmrfde265l7vx36 作业要求: 根据WordCount的需求描述,先编程实现,再编写单元测试,最后撰写博 ...
- 第二周个人作业WordCount
1.Github地址 https://github.com/JingzheWu/WordCount 2.PSP表格 PSP2.1 PSP阶段 预估耗时 (分钟) 实际耗时 (分钟) Planning ...
- 福州大学软件工程1816 | W班 第6次作业WordCount成绩排名
作业链接 WordCount进阶需求 评分细则 本次个人项目分数由两部分组成(博客分满分40分+程序得分满分60分) 博客评分细则(满分60,最终折算为40分) 在文章开头给出结对同学的博客链接.本作 ...
随机推荐
- 用寄快递模拟数据在网络中的传送过程,发送一个ip数据报到接受这个ip数据报经历的过程
发送一个ip数据报到接受这个ip数据报经历的过程 好比寄一个快递的过程 这个包裹一共有三层, 这个包裹的最里面是数据,数据 第二层写着目的ip地址和源ip地址,即收件人和发件人的姓名 第三层也就是最外 ...
- 16.1 解决SecureCRT的Home+End+Del不好用使用方法
有些时候 securecrt 的快捷键 与我们使用习惯不一致时,可以自己动手修改下映射文件. SecureCRT菜单 :工具→键映射编辑器,在弹出的键盘中点击“home”,会弹出一个窗口,在“发送字符 ...
- java-log4j日志打印
参考路径: https://blog.csdn.net/edward0830ly/article/details/8250412 https://www.cnblogs.com/ITtangtang/ ...
- 备份恢复工具xtrabackup安装和使用的记录
一.安装 下面的方法是在测试环境可以上网的情况下安装的: 提供的是在centos7上安装的方法: 包下载: wget https://www.percona.com/downloads/percona ...
- 新手尝试Android studio连接mumu调试程序
由于Android studio本身虚拟机比较卡在安装as的时候就没有安装.于是自己安装了一款手机模拟器mumu模拟器.我想真机可以调试那么摸仪器应该也可以,于是就从网上找资料,其实连接很简单. 1. ...
- webpack打包vue -->简易讲解
### 1. 测试环境: 推荐这篇文章:讲的很细致 https://www.cnblogs.com/lhweb15/p/5660609.html 1. webpack.config.js自行安装 { ...
- YARN简述
YARN(Yet Another Resource Negotiator)是Hadoop的集群资源管理系统.YARN提供请求和使用集群资源的API,但这些API很少直接用于用户代码.相反,用户代码中用 ...
- bzoj5110: [CodePlus2017]Yazid 的新生舞会
Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- MFC 编辑框输入16进制字符串转换为16进制数或者10进制数据计算
1.编辑框添加变量,并选择变量类型为CString. 2. 使用“_tcstoul”函数将Cstring 类型转换为16进制/10进制数进行计算.
- hustOJ 添加 golang 支持
hustOJ 支持Go1.7.1 是否为docker环境不重要,此处所有内容均为docker中执行,普通主机手动安装则更加如此 建议在docker中执行,因为OJ为严控恶意权限,judge_clien ...