Word Count (Java)

WordCount --java语言实现

由于GitHub网速问题(我在医院,没有wifi,只能开热点,上github速度过慢,难以将项目push到github上,因此,我的项目托管到了码云上)
gitee地址:!()[https://gitee.com/wangyuyong123/wordcloud]

1. 项目要求

1.1 题目描述

Word Count

  1. 实现一个简单而完整的软件工具(源程序特征统计程序)。
  2. 进行单元测试、回归测试、效能测试,在实现上述程序的过程中使用相关的工具。
  3. 进行个人软件过程(PSP)的实践,逐步记录自己在每个软件工程环节花费的时间。

1.2 功能列表

  1. 基本功能列表:
    wc.exe -c file.c //返回文件 file.c 的字符数
    wc.exe -w file.c //返回文件 file.c 的词的数目
    wc.exe -l file.c //返回文件 file.c 的行数

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

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

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

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

注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
} //注释

在这种情况下,这一行属于注释行。

  1. 高级功能:

-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

需求举例:
  wc.exe -s -a *.c

返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。

2. PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 20
· Estimate · 估计这个任务需要多少时间 350 312
Development 开发 290 252
· Analysis · 需求分析 (包括学习新技术) 80 60
· Design Spec · 生成设计文档 30 20
· Design Review · 设计复审 (和同事审核设计文档) 20 15
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 30 32
· Coding · 具体编码 50 55
· Code Review · 代码复审 30 25
· Test · 测试(自我测试,修改代码,提交修改) 30 25
Reporting 报告 60 60
· Test Report · 测试报告 20 20
· Size Measurement · 计算工作量 20 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 20
合计 370 332

3.关键代码与设计说明

3.1 总体设计

读入文件模块为ReadFileCls类实现
计数模块为WordCount类实现
程序启动后,程序将根据用户输入的参数判断是否合法,如果合法,将调用ReadFileCls类读入相应的文件,将文件存入内存后,只需要调用ReadFileCls的getContent方法即可获取文件内容的字符串,接着将文件内容的字符串传入WordCount类构成新的对象,根据用户输入的不同参数,调用wordcount不同的方法可以获得相应的结果(如,用户输入-c,则调用wordcount对象的getContentLength方法获取文件的字符数量)。
主函数的main方法如下:

import java.util.List;

public class Main {

    public static ReadFileCls read;

    public static WordCount wordCount;

    public static void main(String[] args) {
        if (args.length >= 3) {
            int i = 0;
            if (args[i].equals("-a") || args[++i].equals("-a")) {
                int j = 1 - i;
                if (args[j].equals("-c")) {
                    try {
                        operateAllFile(args[2], new Do() {
                            @Override
                            public void doSomething(String fileName, WordCount wordCount) {
                                System.out.println(fileName + "的字符数为:" + wordCount.getContentLength());
                            }
                        });
                    }catch (Exception e) {
                        showNoFile();
                    }
                }else if (args[j].equals("-w")) {
                    try {
                        operateAllFile(args[3], new Do() {
                            @Override
                            public void doSomething(String fileName, WordCount wordCount) {
                                System.out.println(fileName + "的单词数为:" + wordCount.getWordCount());
                            }
                        });
                    }catch (Exception e) {
                        showNoFile();
                    }
                }else if (args[j].equals("-l")) {
                    try {
                        operateAllFile(args[2], new Do() {
                            @Override
                            public void doSomething(String fileName, WordCount wordCount) {
                                System.out.println(fileName + "的行数为:" + wordCount.getContentLine());
                            }
                        });
                    }catch (Exception e) {
                        showNoFile();
                    }
                }else {
                    showError();
                }
            }else {
                showError();
            }
        } else if (args.length >= 2) {

            if (args[0].equals("-c")) {
                try {
                    init(args[1]);
                    System.out.println(args[1] + "字符数为:" + wordCount.getContentLength());
                }catch (Exception e) {
                    showNoFile();
                }
            }else if (args[0].equals("-w")) {
                try {
                    init(args[1]);
                    System.out.println(args[1] + "单词数:" + wordCount.getWordCount());
                }catch (Exception e) {
                    showNoFile();
                }

            }else if (args[0].equals("-l")) {
                try {
                    init(args[1]);
                    System.out.println(args[1] + "行数:" + wordCount.getContentLine());
                }catch (Exception e) {
                    showNoFile();
                }

            }else {
                showError();
            }
        } else {
            showError();
        }
    }

    public static void init(String filePath) throws Exception{
        read = new ReadFileCls(filePath);
        wordCount = new WordCount(read.getContent());
    }

    public static void showError() {
        System.out.println("参数不规范");
    }

    public static void showNoFile() {
        System.out.println("没有找到该文件");
    }

    public static void operateAllFile(String directory, Do operator)throws Exception{
        read = new ReadFileCls(directory,true);
        List<String> fileContents = read.getAllContent();
        List<String> fileName = read.getAllFileName();
        for (int i = 0; i < fileContents.size(); i++) {
            wordCount = new WordCount(fileContents.get(i));
            if (operator != null) {
                operator.doSomething(fileName.get(i),wordCount);
            }
        }
    }
}

3.2 ReadFileCls类的设计

该类有两个构造方法,第一个构造方法只带一个参数,传入文件名,之后调用getContent即可获取该文件内容的字符串(String),该类会将此字符串保留起来,如果下次再次调用,则直接将该字符串返回,无需在读取文件。第二个构造方法带两个参数,第一个是一个文件夹名称,第二个是布尔变量,表示是否递归处理该文件夹,使用该构造函数构造对象后,调用getAllContent方法,可以获取该目录夹下所有文件的内容,并返回一个字符串数组。
该类中,对文件的读写操作流程如下:

该类具体代码如下:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ReadFileCls {

    private File file;

    private boolean isAll;

    private String content;

    public ReadFileCls(String filePath) {
        this.file = new File(filePath);
    }

    public ReadFileCls(String filePath, boolean isAll) {
        this.file = new File(filePath);
        this.isAll = isAll;
    }

    /**
     * 如果是文件夹,则递归获取文件夹内的所有内容
     * 如果是文件,则获取该文件的内容
     * @return 字符串数组
     * @throws Exception 若该文件不存在,则抛出异常。
     */
    public List<String> getAllContent() throws Exception{
        List<String> allContent = new ArrayList<>();
        if (isAll) {
            if (file.exists()) {
                if (file.isFile()) {
                    allContent.add(getContent());
                }else {
                    File[] fileSon = file.listFiles();
                    if (fileSon != null) {
                        for (int i = 0; i < fileSon.length; i++) {
                            List<String> temp = new ReadFileCls(fileSon[i].getAbsolutePath(), true).getAllContent();
                            allContent.addAll(temp);
                        }
                    }
                }
            }else {
                throw new FileNotFoundException("没有此文件");
            }
        }else {
            allContent.add(getContent());
        }

        return allContent;
    }

    /**
     * 如果是文件夹,则递归获取文件夹内的文件的名字
     * 如果是文件,则获取该文件的名字
     * @return 字符串数组
     * @throws Exception 若该文件不存在,则抛出异常。
     */
    public List<String> getAllFileName() throws Exception{
        List<String> allFileName = new ArrayList<>();
        if (isAll) {
            if (file.exists()) {
                if (file.isFile()) {
                    allFileName.add(file.getName());
                }else {
                    File[] fileSon = file.listFiles();
                    if (fileSon != null) {
                        for (int i = 0; i < fileSon.length; i++) {
                            List<String> temp = new ReadFileCls(fileSon[i].getAbsolutePath(), true).getAllFileName();
                            allFileName.addAll(temp);
                        }
                    }
                }
            }else {
                throw new FileNotFoundException("没有此文件");
            }
        }else {
            allFileName.add(file.getName());
        }

        return allFileName;
    }

    /**
     * 获取文件内容
     * @return String 文件内容(若返回值为null,说明文件中没有内容)
     * @throws Exception 若该文件不存在,则抛出异常
     */
    public String getContent() throws Exception{

        BufferedReader reader = null;
        StringBuilder builder = new StringBuilder();

        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            String temp = null;
            while ((temp = reader.readLine()) != null) {
                builder.append(temp + "\n");
            }
            content = builder.toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        return content;
    }
}

3.3 wordcount类的设计

wordcount类代码如下:

import java.util.List;

/**
 * 获取字符串的各种信息
 */
public class WordCount {

    private String content;

    /**
     * 所有行
     */
    private int allLine = -1;

    /**
     * 空格
     */
    private int space = -1;

    /**
     * 空行
     */
    private int spaceLine = -1;

    /**
     * 代码行
     */
    private int codeLine = -1;

    /**
     * 注释行
     */
    private int NoteLine = -1;

    private static final String ILLEGAL_CHARACTERS_REX = "[^a-zA-Z]";

    private static final String BLANK_REX = " +";

    private static final String NOTE_REX = "((//.*\\n)|(/\\*[.\\n]*\\*/))";

    public WordCount(String content) {
        this.content = content;
    }

    /**
     * 获取字符串字符的数量
     * @return 数量
     */
    public int getContentLength() {
        if (content != null) {
            return content.length();
        }else {
            return 0;
        }
    }

    /**
     * 获取内容的行数
     * @return 行数
     */
    public int getContentLine() {
        if (allLine == -1) {
            if (content != null) {
                String[] lines = content.split("\n");
                if (lines.length == 1 && lines[0].equals("")) {
                    allLine = 0;
                    return allLine;
                }
                allLine = lines.length;
                return allLine;
            } else {
                allLine = 0;
                return allLine;
            }
        }else {
            return allLine;
        }
    }

    /**
     * 获取空行
     * @return 空行数量
     */
    public int getSpaceLine() {
        if (spaceLine == -1) {
            if (content != null) {
                int num = 0;
                String[] fileLinse = content.split("\n");
                for (int i = 0; i < fileLinse.length; i++) {
                    if (fileLinse[i].equals("")) {
                        num++;
                    }
                }
                spaceLine = num;
                return spaceLine;
            }else {
                spaceLine = 0;
                return spaceLine;
            }
        }else {
            return spaceLine;
        }
    }

    /**
     * 获取注释行
     * @return 注释行行数
     */
    public int getNoteLine() {
        List<String> notes = new RexUtil(NOTE_REX,content).getRexString();
        int lines = 0;
        for (int i = 0; i < notes.size(); i++) {
            String note = notes.get(i);
            System.out.println(note);
            if (note != null) {
                String[] tip = note.split("\n");
                lines += tip.length;
            }
        }
        return lines;
    }

    /**
     * 获取单词数目
     * @return 单词数目
     */
    public int getWordCount() {
        //用正则表达式去除非法字符
        if (content != null) {
            String temp = content.replaceAll(ILLEGAL_CHARACTERS_REX, " ");
            String[] words = temp.split(BLANK_REX);
            if (words.length == 1 && words[0].equals("")) {
                return 0;
            }
            return words.length - 1;
        }else {
            return 0;
        }
    }
}

4.运行测试

将代码通过命令行编译后:

创建测试文件test.c

此时文件为空文件
在命令行输入分别输入
java Main -c test.c
java Main -w test.c
java Main -l test.c
结果如下:

向test.c中输入内容:

测试结果:

递归处理测试:
创建test文件夹:



empty.c内容为空,其他文件都有一定的内容
测试结果:

5.项目总结

  1. 因为时间较赶,部分功能还未完成(相应的功能模块已经编写好了,但存在这一些bug还没来得及修复,因此并没有完成此功能)。
  2. 抽象能力有待提高,代码维护性有待提高。
  3. 期待下一次的项目。

猜你喜欢

转载自www.cnblogs.com/handsomeyong/p/12555837.html
今日推荐