软工作业1—java实现wc.exe

时间:2021-10-09 23:24:59

github项目地址

  https://github.com/liyizhu/wc.exe

WC 项目要求

  • 基本功能列表:  

    wc.exe -c file.c     //返回文件 file.c 的字符数(实现)

 

   wc.exe -w file.c    //返回文件 file.c 的词的数目  (实现)

 

   wc.exe -l file.c      //返回文件 file.c 的行数(实现)

  • 扩展功能:

 

     -s   递归处理目录下符合条件的文件。(实现)
     -a   返回更复杂的数据(代码行 / 空行 / 注释行)。(实现)

 

 

      [file_name]:  文件或目录名,可以处理一般通配符。(实现)

     空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

 

       代码行:本行包括多于一个字符的代码。

 

       注释行:本行不是代码行,并且本行包括注释。

 

 

 

  • 高级功能:

 

     -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,

  程序就会显示文件的字符数、行数等全部统计信息。(未实现)

PSP表格

 

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

20

20

· Estimate

· 估计这个任务需要多少时间

10

10

Development

开发

500

420

· Analysis

· 需求分析 (包括学习新技术)

150

120

· Design Spec

· 生成设计文档

30

40

· Design Review

· 设计复审 (和同事审核设计文档)

20

30

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

10

5

· Design

· 具体设计

30

10

· Coding

· 具体编码

200

300

· Code Review

· 代码复审

30

30

· Test

· 测试(自我测试,修改代码,提交修改)

60

90

Reporting

报告

120

120

· Test Report

· 测试报告

40

80

· Size Measurement

· 计算工作量

10

10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

30

30

合计

 

1250

1315

解题思路描述

功能:wc.exe -c file.c     //返回文件 file.c 的字符数

思路:逐行读取文件,去掉每行空字符后,统计个数,累加,直到文件读取完毕

 

功能:wc.exe -w file.c    //返回文件 file.c 的词的数目

思路:逐行读取文件,将非字母替换为空格,然后按空格切割字符串为字符串数组,累加字符串数组长度,直到文件读取完毕

 

功能:wc.exe -l file.c      //返回文件 file.c 的行数

思路:逐行读取文件,没读取一行,行数加一,知道文件读取完毕

 

功能:-a   返回更复杂的数据(代码行 / 空行 / 注释行)。

思路:逐行读取文件,判断是否存在//,/*,*/若存在,判定为注释行行数加一,判断是否只存在一个字符,或者为空,若是,判定为空行,若判断行中存在/*,则将标志域设置为true,直到读取到*/,将标志域设置为false,当标志域为true,判定为注释行,若非以上情况,判定为代码行

 

功能:[file_name]:  文件或目录名,可以处理一般通配符。

思路:将通配符*替换为\\.+表示多个任意字符,将通配符?替换为\\.表示一个任意字符,将文件名与该正则表达式匹配,若匹配,执行相应操作

 

功能:-s   递归处理目录下符合条件的文件。

思路:列举目录下的所有文件,若为目录,则递归调用函数,若为文件且符合文件格式,则执行相应操作,否则不作任何操作

设计实现过程

软工作业1—java实现wc.exe

  说明:

  一共有两个类:WcUtil是工具类,WcMain类中只有main方法,用于处理控制台输入的参数,解析,判断是否合法,

  并调用WcUtil类中相应的方法

 

代码说明

main() 功能:循环处理命令行参数,解析,判断参数的合法性,调用相应的处理方法

 

 1 public class WcMain {
 2     /*
 3      *  主方法
 4      */
 5     public static void main(String[] args) {
 6         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 7         //当前命令
 8         String currentCommand = null;
 9         //当前命令切分后的数组
10         String[] currentCommandStrings = null;
11         while(true) {
12             try {
13                 //读取命令
14                  if((currentCommand=br.readLine())!=null) {
15                     currentCommandStrings = currentCommand.split(" ");
16                     //命令字符串数组长度小于二或者长度大于四,为错误命令
17                     if(currentCommandStrings.length<2||currentCommandStrings.length>4) {
18                         //空命令直接跳过
19                         if(currentCommandStrings.length==1&&"".equals(currentCommandStrings[0])) {
20                             
21                         }else {
22                             System.out.println("错误命令");
23                             System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
24                         }
25                         
26                     }else {
27                         //命令第一个字段必须为wc.exe
28                         if("wc.exe".equals(currentCommandStrings[0])){
29                             //查看具体命令
30                             if(currentCommandStrings.length==3) {
31                                 switch (currentCommandStrings[1]) {
32                                 case "-c":
33                                     WcUtil.charNumber(currentCommandStrings[2]);
34                                     break;
35                                 case "-w":
36                                     WcUtil.wordNumber(currentCommandStrings[2]);
37                                     break;
38                                 case "-l":
39                                     WcUtil.lineNumber(currentCommandStrings[2]);
40                                     break;
41                                 case "-a":
42                                     WcUtil.complexData(currentCommandStrings[2]);
43                                     break;
44                                 
45                                 default:
46                                     System.out.println("错误命令");
47                                     System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
48                                     break;
49                                 }
50                             }else if(currentCommandStrings.length==2) {
51                                 switch (currentCommandStrings[1]) {
52                                 case "help":
53                                 case "?":
54                                     WcUtil.showHelpDoc();
55                                     break;
56                                 default:
57                                     System.out.println("错误命令");
58                                     System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
59                                     break;
60                                 }
61                             }else if(currentCommandStrings.length==4&&"-s".equals(currentCommandStrings[1])) {
62                                 String currentDirectory = currentCommandStrings[2];
63                                 //路径是否存在
64                                 if(new File(currentDirectory).isDirectory()) {
65                                     String wildcardChar = currentCommandStrings[3].replaceAll("\\*","\\.+").replaceAll("\\?","\\.");
66                                     //System.out.println(wildcardChar);
67                                     WcUtil.recurseHandleAllFiles(currentDirectory,wildcardChar);
68                                     System.out.println("遍历结束");
69                                 }else {
70                                     System.out.println("错误:找不到指定路径");
71                                 }
72                             }else {
73                                 System.out.println("错误命令");
74                                 System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
75                             }
76                         }else {
77                             System.out.println("错误命令");
78                             System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
79                         }
80                     }
81                 }else {
82                     System.out.println("错误命令");
83                     System.out.println("输入\"wc.exe help\"或\"wc.exe ?\"查看帮助文档");
84                 }
85                 
86             } catch (IOException e) {
87                 e.printStackTrace();
88             }
89         }
90 
91     }
92 
93 }

 

lineNumber() 功能:计算文件行数

 

 1 public static void lineNumber(String fileName) {
 2         //判断文件是否存在且是否为c文件
 3         if(new File(fileName).isFile()&&!fileName.endsWith(".c")) {
 4             System.out.println("不支持该文件类型");
 5             return;
 6         }
 7         int lineNumber = 0;
 8         try {
 9             BufferedReader br = new BufferedReader(new FileReader(fileName));
10             while((br.readLine())!=null) {
11                 lineNumber++;
12             }
13             br.close();
14             System.out.println("文件:"+fileName+"  行数:"+lineNumber);
15         }catch (FileNotFoundException e1) {
16             System.out.println("错误:文件不存在");
17             return;
18             //e1.printStackTrace();
19         }catch(IOException e2) {
20             System.out.println("错误:文件读取出错");
21             //e2.printStackTrace();
22         }
23         
24     }

 

charNumber() 功能:计算文件字符数

 

 1 public static void charNumber(String fileName) {
 2         if(new File(fileName).isFile()&&!fileName.endsWith(".c")) {
 3             System.out.println("不支持该文件类型");
 4             return;
 5         }
 6         int charNumber = 0;
 7         try {
 8             BufferedReader br = new BufferedReader(new FileReader(fileName));
 9             String currentLine = null;
10             String[] currentLineStrings = null;
11             while((currentLine=br.readLine())!=null) {
12                 currentLineStrings = currentLine.trim().split("\\s+");
13                 for(int i=0;i<currentLineStrings.length;i++) {
14                     charNumber = charNumber+currentLineStrings[i].length();
15                     //System.out.println(currentLineStrings[i]+currentLineStrings[i].length());
16                 } 
17             }
18             br.close();
19             System.out.println("文件:"+fileName+"  字符数数:"+charNumber);
20         } catch (FileNotFoundException e1) {
21             System.out.println("错误:文件不存在");
22             return;
23             //e1.printStackTrace();
24         }catch(IOException e2) {
25             System.out.println("错误:文件读取出错");
26             //e2.printStackTrace();
27         }
28         
29     }

 

 wordNumber() 功能:计算文件单词数

 

 1 public static void wordNumber(String fileName) {
 2         if(new File(fileName).isFile()&&!fileName.endsWith(".c")) {
 3             System.out.println("不支持该文件类型");
 4             return;
 5         }
 6         //单词数
 7         int wordNumber = 0;
 8         try {
 9             BufferedReader br = new BufferedReader(new FileReader(fileName));
10             //当前行字符串
11             String currentLine = null;
12             //当前行切分后的数组
13             String[] currentLineStrings = null;
14             
15             Pattern p = Pattern.compile("[_a-zA-Z0-9]+");
16             
17             Matcher m = null;
18             while((currentLine=br.readLine())!=null) {
19                 //将当前字符串中非字母下划线的字符全部替换为空格
20                 currentLine = currentLine.replaceAll("[^_a-zA-Z]"," ");
21                 currentLineStrings = currentLine.trim().split("\\s+");
22                 for(int i=0;i<currentLineStrings.length;i++) {
23                     m = p.matcher(currentLineStrings[i]);
24                     if(m.matches()) {
25                         wordNumber++;
26                     }
27                     //System.out.println(currentLineStrings[i]);
28                 } 
29             }
30             br.close();
31             System.out.println("文件:"+fileName+"  单词数:"+wordNumber);
32         } catch (FileNotFoundException e1) {
33             System.out.println("错误:文件不存在");
34             return;
35             //e1.printStackTrace();
36         }catch(IOException e2) {
37             System.out.println("错误:文件读取出错");
38             //e2.printStackTrace();
39         }
40         
41     }

 

 

complexData() 功能:计算文件更复杂的数据(代码行,空行,注释行)

 

 1 public static void complexData(String fileName) {
 2         if(new File(fileName).isFile()&&!fileName.endsWith(".c")) {
 3             System.out.println("不支持该文件类型");
 4             return;
 5         }
 6         //代码行
 7         int codeLineNumber = 0;
 8         //空行
 9         int blankLineNumber = 0;
10         //注释行
11         int annotationLine = 0;
12         //记录多行注释是否结束
13         boolean annotationBegin = false;
14         try {
15             BufferedReader br = new BufferedReader(new FileReader(fileName));
16             String currentLine = null;
17             while((currentLine=br.readLine())!=null) {
18                 if(annotationBegin) {
19                     annotationLine++;
20                     //多行注释结束
21                     if(currentLine.contains("*/")) {
22                         annotationBegin = false;
23                     }
24                     //多行注释开始
25                 }else if(currentLine.contains("/*")){
26                     annotationLine++;
27                     annotationBegin = true;
28                 }else if(currentLine.contains("//")) {
29                     annotationLine++;
30                 }else if(currentLine.trim().length()>1) {
31                     codeLineNumber++;
32                 }else {
33                     blankLineNumber++;
34                 }
35                 
36             }
37             br.close();
38             System.out.print("文件:"+fileName+"  ");
39             System.out.println("代码行:"+codeLineNumber+" 空行:"+blankLineNumber+" 注释行:"+annotationLine);
40         }catch (FileNotFoundException e1) {
41             System.out.println("错误:文件不存在");
42             return;
43             //e1.printStackTrace();
44         }catch(IOException e2) {
45             System.out.println("错误:文件读取出错");
46             //e2.printStackTrace();
47         }
48         
49     }

 

recurseHandleAllFiles() 功能:递归处理目录下的所有文件

 1 public static void recurseHandleAllFiles(String directory,String wildcardChar) {
 2         Pattern p = Pattern.compile(wildcardChar);
 3         Matcher m = null;
 4         File file = new File(directory);
 5         if(file.isDirectory()) {
 6             if(file.listFiles()!=null) {
 7                 for(File item:file.listFiles()) {
 8                     if(item.isDirectory()) {
 9                         recurseHandleAllFiles(directory+"\\"+item.getName(),wildcardChar);
10                     }else {
11                         m = p.matcher(item.getName());
12                         if(m.matches()&&item.getName().endsWith(".c")) {
13                             complexData(directory+"\\"+item.getName());
14                         }
15                     }
16                 }
17             }
18         }
19     }

showHelpDoc() 功能:显示帮助文档

1 public static void showHelpDoc() {
2         System.out.println("本程序仅支持c程序文件,即.c文件");
3         System.out.println("wc.exe -c file.c 返回文件 file.c 的字符数");
4         System.out.println("wc.exe -w file.c 返回文件 file.c 的单词数");
5         System.out.println("wc.exe -l file.c 返回文件 file.c 的行数");
6         System.out.println("wc.exe -a file.c 返回文件 file.c 的代码行数、空行数、注释行数");
7         System.out.println("wc.exe -s directory *.c (支持通配符,*代表多个任意字符,?代表一个任意字符) 返回directory路径下所有符合条件的文件的代码行数、
        空行数、注释行数"); 8 System.out.println("wc.exe -x 显示图形界面,选取单个文件,显示文件的字符数、行数等全部统计信息"); 9 }

测试运行

运行测试

软工作业1—java实现wc.exe

 

软工作业1—java实现wc.exe

单元测试

软工作业1—java实现wc.exe

 

代码覆盖率

软工作业1—java实现wc.exe

 

项目小结

1、首次使用软件工程的方法,虽然前期花费的时间稍多,但是后面编码思路更加清晰,改善过程不需要大幅度修改代码

2、首次使用JUnit进行单元测试,回归测试,单元测试覆盖率检测,认识到单元测试的重要性

3、重新学习了git和github的使用,更加熟悉git的各种操作

4、学习了exe4j的使用