基于Java实现wc工具

时间:2022-05-10 23:22:31

Github项目地址:https://github.com/Aliiiiiiiiiiiiiiiii/Handsome-boy

一.项目要求

  wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。

实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
  具体功能要求:
  程序处理用户需求的模式为:wc.exe [parameter] [file_name]

  基本功能列表:

  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

计划

 120  90

· Estimate

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

 30  60

Development

开发

 1440 1440

· Analysis

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

 120  120

· Design Spec

· 生成设计文档

 30  50

· Design Review

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

 20  30

· Coding Standard

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

 10  20

· Design

· 具体设计

 60  90

· Coding

· 具体编码

 50  100

· Code Review

· 代码复审

 600  780

· Test

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

 300  250

Reporting

报告

 150  150

· Test Report

· 测试报告

 60  90

· Size Measurement

· 计算工作量

 5  10

· Postmortem & Process Improvement Plan

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

 20  20

合计

   1305  1620

 

三.解题思路

  刚拿到题目的时候我并没有想到使用正则表达式去做匹配功能,后来跟同学讨论才知道的,看到对文件的操作就自然想到了学过的Java的输入输出流,对文件的操作也是比较了解的,所以选择了使用java去实现wc功能,至于这么多功能,我选择分模块去写代码,一个类实现一个功能,然后写一个main函数利用switch对用户输入的操作指令进行各项功能的实现,或许会有一些代码重复,但是思路直接,实现起来思路会清晰。统计字符使用正则表达式很容易就实现了,统计单词利用Pattern的split()方法把[^a-zA-Z]的分隔开,利用String[]存储再统计,行的统计就直接读一行就LineCount++。至于图形化界面,之前有学过相关的知识,所以是实现起来比较快,主要是输出文件的内容以及-c,-w,-l的实现。

 

四.设计实现过程

 通过用户的输入而进入不同的功能模块,每个功能为一个类,通过while循环包含着switch语句进行可重复的操作

   基于Java实现wc工具

 

五.代码说明

  主函数代码

package wc;

import java.io.IOException;
import java.util.Scanner;

public class Start {

    public static void main(String[] args) throws IOException {
        // TODO 自动生成的方法存根
        System.out.println("Welcome to wc.exe!\n");
        System.out.println("----------指令参考-----------");
        System.out.println("wc.exe -c   返回文件的字符数");
        System.out.println("wc.exe -w   返回文件的单词数");
        System.out.println("wc.exe -l   返回文件的行数");
        System.out.println("wc.exe -s   递归处理目录下符合条件的文件");
        System.out.println("wc.exe -a   返回代码行 / 空行 / 注释行");
        System.out.println("wc.exe -x   显示图形界面");
        System.out.println("wc.exe -exit   退出");
        System.out.println("-------------------------------------\n");
        while(true) {
            System.out.print("请输入指令: wc.exe -");
            Scanner s=new Scanner(System.in);
            String in= s.nextLine();
            switch(in) { //输入不同的指令打开不同的类,实现不同的功能
            case "c":
                CharCount cc=new CharCount();
                break;
            case "w":
                WordCount wc=new WordCount();
                break;
            case "l":
                LineCount lc=new LineCount();
                break;
            case "s":
                SCount sc=new SCount();
                break;
            case "a":
                ACount ac=new ACount();
                break;
            case "x":
                HighLevel hl=new HighLevel();
                break;
            case "exit":
                System.out.println("Good Bye!");
                System.exit(0);
            default:
                System.out.println("请输入正确的命令");
                
            }
        }
    }

}

 

CharChout    字符统计

package wc;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CharCount {
    String REGEX="\\S"; //非空白字符
    
    CharCount() throws IOException{
        Pattern p=Pattern.compile(REGEX);  //利用正则表达式Pattern类以及Matcher类
        System.out.println("请输入文件的绝对路径:");
        System.out.print("wc.exe -c ");
        Scanner inc=new Scanner(System.in);
        String path=inc.nextLine();
        BufferedReader fis=new BufferedReader(new FileReader(path));
        String s;
        int charcount=0;
        while((s=fis.readLine())!=null) {
            Matcher m=p.matcher(s);  //对正则表达式进行模式匹配
            while(m.find())
                charcount++;
        }
        System.out.println("该文件有"+charcount+"个字符\n\n");
        fis.close();
    }
}

 

WordCount  单词统计

public class WordCount {
    String REGEX="[^a-zA-Z]";
    
    WordCount() throws IOException{
        Pattern p=Pattern.compile(REGEX);
        System.out.println("请输入文件的绝对路径:");
        System.out.print("wc.exe -w ");
        Scanner inw=new Scanner(System.in);
        String path=inw.nextLine();
        BufferedReader fis=new BufferedReader(new FileReader(path));
        String s;
        int wordcount=0;
        while((s=fis.readLine())!=null) {
            if(s.isEmpty()==false) {   //要不是一行空行才进行下面的操作,不然要是有空行的话结果不对
            String[] letter=p.split(s);
            for(String word : letter)
                wordcount++;
               }
            }
        System.out.println("该文件有"+wordcount+"个单词\n\n");
           fis.close();
    }
}

 

LineCount   行数统计

public class LineCount {    
    LineCount() throws IOException{
        System.out.println("请输入文件的绝对路径");
        System.out.print("wc.exe -l ");
        Scanner inl=new Scanner(System.in);
        String path=inl.nextLine();
        BufferedReader fis=new BufferedReader(new FileReader(path));
        String s;
        int linecount=0;
        while((s=fis.readLine())!=null) {  //直接读到一行就+1
                linecount++;
        }
        System.out.println("该文件有"+linecount+"行\n\n");
           fis.close();
    }
}

 

Scount     递归处理目录下符合条件的文件

public class SCount {
    SCount() throws IOException{
        System.out.print("请输入要执行的操作:wc.exe -s -");
        Scanner control=new Scanner(System.in);
        String ct= control.nextLine();
        System.out.print("请输入要递归处理的目录路径:");
        Scanner in=new Scanner(System.in);
        String path= in.nextLine();
        System.out.print("请输入要递归处理的文件类型:wc.exe -s -"+ct+" *.");
        Scanner style=new Scanner(System.in);
        String st= style.nextLine();
        File file=new File(path);
        String[] name=file.list();
        String s;
        int count=0;
        switch(ct) {
            case "c":
                Pattern cp=Pattern.compile("\\S");
                for(String n:name) {
                    if(n.matches("\\S+."+st)) {  //找出目录下符合文件后缀的文件
                            BufferedReader fis=new BufferedReader(new FileReader(path+"\\"+n));
                            while((s=fis.readLine())!=null) {   //这里的操作跟前面的模块一样
                                Matcher m=cp.matcher(s);
                                while(m.find())
                                    count++;
                            }
                            System.out.println(n+"  中有"+count+"个字符");
                            count=0;
                            fis.close();
                    }
                }
            break;
            
            case "w":
                Pattern wp=Pattern.compile("[^a-zA-Z]");
                for(String n:name) {
                    if(n.matches("\\S+."+st)) {
                            BufferedReader fis=new BufferedReader(new FileReader(path+"\\"+n));
                            while((s=fis.readLine())!=null) {
                                if(s.isEmpty()==false) {
                                String[] letter=wp.split(s);
                                for(String word : letter)
                                    count++;
                                }
                            }
                            System.out.println(n+"  中有"+count+"个单词");
                            count=0;
                            fis.close();
                    }
                }
            break;
                
            case "l":
                for(String n:name) {
                    if(n.matches("\\S+."+st)) {
                            BufferedReader fis=new BufferedReader(new FileReader(path+"\\"+n));
                            while((s=fis.readLine())!=null) {
                                    count++;
                            }
                            System.out.println(n+"  中有"+count+"行");
                            count=0;
                            fis.close();
                    }
                }
            break;
            
            case "a":
                
        }
    }
}

 

 

ACount    返回更复杂的数据(代码行 / 空行 / 注释行)

public class ACount {
    int total=0;
    int EmptyLine=0;
    int DescribeLine=0;
    int CodeLine=0;
    int tag=0;  //设置一个标志,要tag=0,证明这一行还没扫描到“/*”,tag=1说明已经扫到了
    ACount() throws IOException{
        Pattern p1=Pattern.compile("//");
        Pattern p2=Pattern.compile("//*");
        Pattern p3=Pattern.compile("/*/");
        System.out.println("请输入文件的绝对路径:");
        System.out.print("wc.exe -a ");
        Scanner ina=new Scanner(System.in);
        String path=ina.nextLine();
        BufferedReader fis=new BufferedReader(new FileReader(path));
        String s;
        while((s=fis.readLine())!=null) {
            total++;
            if(tag==0) {     //根据tag的值进行不同的操作
            Matcher m1=p1.matcher(s);
            Matcher m2=p2.matcher(s);
            if(s.isEmpty()||(s.startsWith("{")&&s.endsWith("{")))  //只有tag=0时才计算空行,要是在多行注释里面出现的空行算入注释行而不算空行
                EmptyLine++;
            else if(m1.find())
                DescribeLine++;
            else if(m2.find()) {
                DescribeLine++;
                tag=1;
            }
            }
            else {
                DescribeLine++;
                Matcher m3=p3.matcher(s);
                if(m3.find())  //当匹配到“*/”的时候,说明多行注释结束,把tag置为0
                    tag=0;
            }
        }
        CodeLine=total-DescribeLine-EmptyLine;
        System.out.println("该文件有"+EmptyLine+"行空行");
        System.out.println("该文件有"+DescribeLine+"行注释行");
        System.out.println("该文件有"+CodeLine+"行代码行\n\n");
        fis.close();
    }
}

 

- x 显示图形界面的代码不在这里分析了,详细见Github源码

 

六.测试运行

  基于Java实现wc工具

基于Java实现wc工具

 

基于Java实现wc工具

 

基于Java实现wc工具

 

 基于Java实现wc工具

 

 

七.项目小结

         

  对于SCount以及ACount这两个类的语言逻辑,我出bug很多次了,总会存在一些小问题,后来发现自己的逻辑不够严谨,导致了运行结果的错误,而且整个程序还存在着或多或少的问题,有一些解决方法是我在上下学路上时候想到的,或许不是什么好的方法,但是这是我自己思考得出的方法,觉得通过这个项目的编程,我收获了不少,尽管最后做出来的程序有不足,但是通过自己思考和努力,锻炼了自己的编程能力,受益匪浅。