第一次作业:Word Count

1. 项目需求说明

刚拿到题目时,我先看了题目需求,并列出主要要实现的功能:
1. 读取文件内容
2. 计算字符数
3. 计算单词数
4. 计算行数
5. 向文件写入内容
经过主要的功能分析后,我决定用我比较熟悉的java语言来完成这个题目。

举例:

wc.exe –c file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 字符数: 50

wc.exe –w file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 单词数: 30

wc.exe –l file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 行数: 10

wc.exe –l –c file.c,则统计file.c中的字符数和行数,输出结果保存在result.txt中,内容格式如下:
file.c, 字符数: 50
file.c, 行数: 10

2. 编码过程

  • PSP表格
**PSP2.1 ** PSP阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 1
· Estimate · 估计这个任务需要多少时间 10 1
Development 开发 170 535
· Analysis · 需求分析 (包括学习新技术) 10 5
· Design Spec · 生成设计文档 30 40
· Design Review · 设计复审 (和同事审核设计文档) 10 0
· Coding · 代码规范 (为目前的开发制定合适的规范) 10 0
· Code Review · 具体设计 10 5
· Test · 具体编码 60 410
Reporting · 代码复审 10 5
· Test Report 报告 30 40
· Size Measurement · 测试报告 30 10
· Postmortem & Process · 计算工作量 5 10
Improvement Plan · 事后总结, 并提出过程改进计划 10 120
合计 210 650
  • 小总结:

本次计划时间和实际花费的时间有很大的差异,从表格中可以分析出,
我在自己评估自己在具体编码的时间太乐观,这个项目看起来需求简单,
但由于我单java的字符IO流把握不是很熟悉,我也在使用正则表达式的
时候,出现了问题,导致在调试过程中花费了很多的时间。
其他也有出现偏差的地方,如:估计这个任务需要多少时间,
代码规范, 事后总结, 并提出过程改进计划等。由于我第一次通过
规范的软件设计过程的方法完成这次作业,对该过程缺少实践,所以
不能对时间把握的很好,希望能够在下一次做得更好。

2. 1 解题思路

我分析了用java语言完成该题目主要需要运用的知识是:文件的IO流部分的知识。
于是我复习了我自己学习java IO字符流模块的知识和笔记,相关笔记如下:


/*
------------|   Reader    抽象类    输入字符流的基类
-----------------------|   FileReader    读取文件的输入字符流

FileReader的步骤:

	1. 找到目标文件
	2. 建立数据输入字符流通道
	3. 读取数据

*/
public class Demo1 {
       public static void main(String[] args) throws IOException {
             read1();
             read2();
       }
       public static void read1() throws IOException {
             File file = new File("E:/作业/Java/文件/b.txt");
             FileReader fileReader = new FileReader(file);
             int content = 0;
             while((content = fileReader.read()) != -1){//每次读一个字符
                    System.out.print((char)content);
             }
             fileReader.close();
       }
       public static void read2() throws IOException {
             File file = new File("E:/作业/Java/文件/b.txt");
             FileReader fileReader = new FileReader(file);
             //建立缓冲字符数组
             char[] buf = new char[1024];
             int length = 0;
             while((length = fileReader.read(buf)) != -1)
             {
                    System.out.println(new String(buf, 0, length));
             }
       }
}



/*
--------------|    Write    抽象类    输出字符流的基类
--------------------------|    FileWriter    向文件数据输出数据的输出字符流

FileWriter 的使用步骤:

	1. 找到目标文件
	2. 建立字符输出流通道
	3. 输出数据
	4. 关闭文件

注意:

	1. filewriter底层维护了一个1024的字符数组,写的数据先存在该数组中,当调用flush或close方法或填满了数组才会保存到硬盘上。
	2. new FileWriter(file);    如果目标文件不存在,会自动创建。
	3. new FileWriter(file);默认先清空数据。如果要直接添加数据,使用FileWriter(File,true)。

*/
public class Demo2 {
       public static void main(String[] args) throws IOException {
             write();
       }
       public static void write() throws IOException {
             File file = new File("E:/作业/Java/文件/b.txt");
             FileWriter fileWriter = new FileWriter(file);
             String data = "今天很开心";
             fileWriter.write(data);
             fileWriter.close();
       }
}

然后,我又思考发现,在计算单词数的时候,可以通过正则表达式来截取字符串的方式计算单词数量,
所有我又复习了正则表达式的相关用法,相关示例如下:

	范围词

            [abc]          出现的只能是abc其中的一个
            [^abc]         出现的只能是除了abc 的一个任意字符
            [a-z1-9&$] 出现的只能是两头字母包括在内的字符(即:a~z  或1~9 或&或$)

2. 2 程序设计实现过程

在实际编码中,我使用了四个类,其类名和相关用途如下:
BaseCount:解析用户输入的命令行、调用JudgeOption类
相关方法:
wordCountMain()

BaseFunc:实现计算字符数、单词书、行数这三个方法
相关方法:
count_charsNum(String path)
count_wordsNum(String path)
count_linesNum(String path)

JudgeOption:判断用户输入参数,调用BaseFunc中对应的相关方法
相关方法:
judge(String arg, String readPath, String writePath)

WriteCount:把计算后的结果写出到指定文件
相关方法:
writeCount(String str, String path)
initFile(String path):如果写出的文件存在,将文件内容清空

2. 3 代码说明

BaseFunc 类


public class BaseFunc {
        //计算字符数
	public static int count_charsNum(String path){
		int count = 0;
		try {
			FileReader fileReader = new FileReader(path);
			char[] buf = new char[1024];
			int length = 0;
			while( (length = fileReader.read(buf)) != -1){
				count += length;
			}
			fileReader.close();
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return count;
	}
	//计算单词数
	public static int count_wordsNum(String path) {
		int count = 0;
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
			  while(br.read()!=-1) 
			  {
			   String s = br.readLine();
			   
			   for(int i=0; i<s.split("[^a-zA-Z]").length; i++){//通过非英文字符对字符串进行截取
				   
				   if( !s.split("[^a-zA-Z]")[i].isEmpty()){//去掉两个连续非英文字符 所截取的空字符串
					   count ++;
				   }
			   }
			   
			   
			  }
			  br.close(); 
		}  catch (Exception e) {
			System.out.println(e);
		}
		
		
		return count;
		
	}
        //计算行数
	public static int count_linesNum(String path) {
		int count = 0;
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
			while(br.read()!=-1) 
			{
				String s = br.readLine();//每次读取一行,行数加一
				
				count++;
			}
			br.close(); 
		}  catch (Exception e) {
			System.out.println(e);
		}
		
		
		return count;
		
	}
}


JudgeOption 类



public class JudgeOption {
        //判断用户输入的参数,调用相关方法
	public static void judge(String arg, String readPath, String writePath) {
		int count = 0;
		String str = "";
		
		switch (arg) {
		case "-c":
		case "—c":
			count = BaseFunc.count_charsNum(readPath);
			str = readPath.split("/")[ (readPath.split("/").length-1) ];
			str += ", 字符数:";
			str += count;
			WriteCount.writeCount(str, writePath);
			break;
			
		case "-w":
		case "—w":
			count = BaseFunc.count_wordsNum(readPath);
			str = readPath.split("/")[ (readPath.split("/").length-1) ];
			str += ", 单词数:";
			str += count;
			WriteCount.writeCount(str, writePath);
			break;
			
		case "-l":
		case "—l":
			count = BaseFunc.count_linesNum(readPath);
			str = readPath.split("/")[ (readPath.split("/").length-1) ];
			str += ", 行数:";
			str += count;
			WriteCount.writeCount(str, writePath);
			break;
			
		}
	}
}


2. 4 测试设计过程

我总共设计了10个测试用例,其中7个为用户输入命令测试,3个为文件内容测试。

  • 设计思路

对于用户输入命令的测试:由于我的主函数中有一行代码,即:用来调用我所有的项目方法,没有功能代码,因此可以确保其正确性。
其他所有函数中,若出现错误均将错误抛出,我使用MTest类来实现测试方法,当主程序中有异常抛出时,则捕捉并进行处理,即:输出异常,终止程序。
并添加代码:把预期结果用字符串数组保存,用if语句与实际结果判断,如果不符合,就assert(判断)

对于文件内容的测试,则需要手动将文件内容进行修改。

输入命令测试

  • wc.exe -c f.c
    输出结果:

  • wc.exe -w f.c
    输出结果:

  • wc.exe -l f.c
    输出结果:

  • wc.exe -c -w -l f.c
    输出结果:

  • wc.exe -s f.c
    输出结果:

  • wc.exe
    输出结果:

  • wc.exe -w f.txt
    输出结果:

其中,f.c的内容如下:


count = BaseFunc.count_charsNum(readPath);
			str = readPath.split("/")[ (readPath.split("/").length-1) ];
			str += ", 字符数:";
			str += count;
			WriteCount.writeCount(str, writePath);
			break;

文件内容测试

  • 文件为空
    结果:

  • 文件1

aaaaaaaaa

结果:

  • 文件2
public static void main(String[] args) {
		String[] options = "-c -w -l src/file.c".split(" ");
//		System.out.println(options.length);
		
		/*for(int i=0; i<options.length; i++){
			System.out.println(options[i]);
		}*/
//		wordCountMain(options);
		
		
		wordCountMain(args);
}

结果:

其中,输入命令为:
wc.exe -c -w -l f.c

  • - 测试代码如下:.
//该代码为判断程序是否出错的测试,而判断输出结果是否正确的测试代码这里不给出
public class MTest {
	public void mtest(){
		try {
			ArrayList<String[]> list = new ArrayList<String[]>();
			String[] options1 = "-c f.c".split(" ");
			String[] options2 = "-w f.c".split(" ");
			String[] options3 = "-l f.c".split(" ");
			String[] options4 = "-c -w -l f.c".split(" ");
			String[] options5 = "-s f.c".split(" ");
			String[] options6 = " ".split(" ");
			String[] options7 = "-w f.txt".split(" ");
			list.add(options1);
			list.add(options2);
			list.add(options3);
			list.add(options4);
			list.add(options5);
			list.add(options6);
			list.add(options7);
			
			for(int i=0; i<7; i++){
				BaseCount.wordCountMain(list.get(i));
			}
			
		} catch (Exception e) {
			System.out.println(e);
			assert(false);
		}
		
	}
}

3. 总结反思:


   通过这次完成WordCount作业的过程,我学到了很多:
1. 如何使用git对我的项目进行管理。
2. 如何使用博客,并写一篇自己的博文。
3. 复习、加深了对java字符IO流的使用。
4. 通过正则表达式的正确使用,可以帮我们轻松的编码,并实现自己想要的结果。
5. 如何通过Myeclipse来自动生成UML类图。
6. 如何使用将java程序导出为jar包,并转化为exe文件。
7. 如何编写设计一个测试用例
这项目实现的过程中也遇到了很多问题,但由于自己的坚持不懈,
通过在网上查询资料和同学的热心帮助将作业完成,并在作业的完成过程中不断的
反思和改进,使得自己在解决错误和问题中不断的提升。

4. 致谢

本次作业的顺利完成,主要参考老师提供的一些优秀的文章:
(地址:
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
http://www.cnblogs.com/xinz/archive/2011/10/22/2220872.html
http://www.cnblogs.com/xinz/archive/2011/11/20/2255830.html
http://www.cnblogs.com/math/p/se-tools-001.html

和自己通过上网搜索到的一些参考资料:
(地址:
https://blog.csdn.net/limuzi13/article/details/52912625
https://blog.csdn.net/honjane/article/details/40739337

在此,对老师和上述资料的贡献者表示忠心的感谢。

posted @ 2018-09-22 17:41  lu0526  阅读(232)  评论(10编辑  收藏  举报