• 个人项目作业



    博客地址: :https://github.com/HandsomeLuoYM/WC


    PSP表格
    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 4-5天 5天
    -Estimate 估计这个任务需要多少时间 4-5天 5天
    Development 开发 385 360
    -Analysis 需求分析 (包括学习新技术) 60 50
    -Design Spec 生成设计文档 30 20
    -Design Review 设计复审 (和同事审核设计文档) 15 10
    -Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 40
    -Design 具体设计 20 25
    -Coding 具体编码 200 180
    -Code Review 代码复审 30 35
    Test 测试(自我测试,修改代码,提交修改) 200 220
    -Reporting 报告 120 150
    -Test Report 测试报告 60 50
    -Size Measurement 计算工作量 10 5
    -Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 10 15
    合计 585 580

    解题思路

    • 首先确定编程语言,由于之前C语言未学到操作文件的相关操作,所以选择了比较熟悉的 java 语言降低学习成本
    • 其次,确定可能给使用到的技术,由于需要操作文件,所以需要用到IO流和文件操作相关知识。然后涉及到大量的判断操作,所以打算用正则匹配相关方法。最后加上日志相关操作
    • 最后,对项目代码需要用到GitHub远程仓库进行代理。

    设计实现过程

    • 首先,确定基本架构,由于只是一个简单的小程序,所以用普通的项目结构即可,也不需要拆分成太多类。
    • 其次就是设计方法,首先根据指令长度,拆分成简单操作方法递归操作方法,而简单方法中含有拓展相关操作,故还需一个拓展的方法
    • 最后就是建立一个bat文件,方便最后测试后面的环节


    代码说明


    • 正则表达式以及日志输出等数据的声明
        //拆分单词的正则表达式
        private static final String SPILT_LINE_TO_WORD_REGEX = "\s+|\(|\)|,|\.|\:|\{|\}|\-|\+|;|\?|\/|\\|/";
        //匹配单词的正则表达式
        private static final String WORD_REGEX = "[\w]+";
        //判断单行注释的正则表达式
        private static final String SINGLE_EXPLAIN_REGEX = "\s*(\{|\})?//.*";
        //判断多行注释行
        private static final String MULTIPLE_ROWS_EXPLAIN_REGEX_HEAD = "\s*/\*.*";
        private static final String MULTIPLE_ROWS_EXPLAIN_REGEX_TAIL = ".*\*/";
        //空白行正则表达式
        private static final String BLANK_CODE_REGEX = "(\{|\})?\s*";
        //文件路径格式正则表达式
        private static final String FILE_REGEX = "[a-zA-Z]:(\\([a-zA-Z0-9_]+.[a-zA-Z0-9_]{1,16}))+";
        //错误日志输出
        private static final Logger log = Logger.getLogger("Wc");
        //简单封装日志输出信息,防止多次new对象,在此可用枚举进一步封装
        private static final Map<String,String> LOG_MAP = new HashMap<String, String>();
    
        static {
            LOG_MAP.put("pathError","Error:文件路径 错误 或 不存在!");
            LOG_MAP.put("operationError","Error:输入的指令错误!");
            LOG_MAP.put("invalidError","Error:无效指令!");
        }
    

    • Main方法
        /**
         * 主类
         * @param args 输入参数
         * @throws IOException IO流异常,抛出,不做处理
         */
        @SuppressWarnings("unused")
        public static void main(String[] args) throws IOException {
            System.out.println("---------------------------------------------------------");
            System.out.println("| 程序功能 :                                             |");
            System.out.println("|-c:返回文件的字段数                                     |");
            System.out.println("|-w:返回文件的词的数                                     |");
            System.out.println("|-l:返回文件的行数                                       |");
            System.out.println("|-s:递归处理目录下符合条件的文件                          |");
            System.out.println("|-a:返回文件的代码行数/空白行数/注释行数                   |");
            System.out.println("---------------------------------------------------------");
            //获取用户输入指令
            Scanner scanner = new Scanner(System.in);
            //循环来获取用户操作
            while (true){
                System.out.println("---------------------------------------------------------");
                System.out.println("请输入命令(格式:wc.exe [parameter] [file_path]):");
                //将指令集拆分,并做简单判断格式
                String[] split = scanner.nextLine().split(" ");
                if("wc.exe".equals(split[0]) && 3 == split.length){
                    basicOperation(split);
                }else if("wc.exe".equals(split[0]) && 4 == split.length){
                    if (split[3].matches(FILE_REGEX) && new File(split[3]).exists()){
                        recursionOperation(split);
                    }else {
                        log.severe(LOG_MAP.get("pathError"));
                    }
                }else {
                    log.severe(LOG_MAP.get("operationError"));
                }
            }
        }
    

    • 用户指令基本操作类
        /**
         * 判定用户操作
         * @param split 指令拆分集
         * @throws IOException IO流异常抛出
         */
        @SuppressWarnings("unused")
        public static void basicOperation(String[] split) throws IOException {
    
            //初始化统计数据参数
            int characterCount = 0, lineCount = 0, wordCount = 0;
            //进一步判断输入文件路径是否正确
            File file = new File(split[2]);
            String fileName = file.getName();
            if (!split[2].matches(FILE_REGEX) || !file.exists() || file.isDirectory()
                    ||!"c".equals(fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()))){
                log.severe(LOG_MAP.get("pathError"));
                return;
            }
            //获取本地文件的缓存流读取器,方便后面操作
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(split[2])));
            //用于暂时存储行数据
            String line;
            switch (split[1]){
                case "-c" :
                    while (null != (line = br.readLine())){
                        characterCount +=  line.length();
                    }
                    System.out.println("字符数为:" + characterCount);
                    break;
                case "-l" :
                    while (br.readLine() != null){
                        lineCount++;
                    }
                    System.out.println("行数为:" + lineCount);
                    break;
                case "-w" :
                    while ((line = br.readLine()) != null){
                        for (String s : line.split(SPILT_LINE_TO_WORD_REGEX)){
                            if (s.matches(WORD_REGEX)){
                                wordCount ++;
                            }
                        }
                    }
                    System.out.println("单词数:"+wordCount);
                    break;
                case "-a" :
                    specialOperation(br);
                    break;
                default:
                    log.warning(LOG_MAP.get("invalidError"));
            }
            br.close();
        }
    

    • 特殊操作
        /**
         * 统计一些高级的数据
         * @param bufferedReader 缓存流读取器
         * @exception IOException IO流异常,直接抛出,不做处理
         */
        @SuppressWarnings("unused")
        public static void specialOperation(BufferedReader bufferedReader) throws IOException {
    
            //初始化统计数据参数
            int blankCount = 0, codeCount = 0, explainCount = 0;
            String line;
            boolean b = false;
            while (null != (line = bufferedReader.readLine())){
                if (line.matches(BLANK_CODE_REGEX)){
                    blankCount++;
                }else if (line.matches(SINGLE_EXPLAIN_REGEX)){
                    explainCount++;
                }else if (line.matches(MULTIPLE_ROWS_EXPLAIN_REGEX_HEAD)){
                    explainCount++;
                    if (!line.matches(MULTIPLE_ROWS_EXPLAIN_REGEX_TAIL)){
                        b = true;
                    }
                }else if (b){
                    explainCount++;
                    if (line.matches(MULTIPLE_ROWS_EXPLAIN_REGEX_TAIL)){
                        b = false;
                    }
                }else {
                    codeCount++;
                }
            }
            System.out.println("代码行数:" + codeCount);
            System.out.println("注释行数:" + explainCount);
            System.out.println("空白行数:" + blankCount);
            bufferedReader.close();
        }
    

    • 递归操作
        /**
         * 递归判断文件
         * @param split 递归的指令集
         * @exception  IOException 直接抛出,不做处理
         */
        @SuppressWarnings("unused")
        public static void recursionOperation(String[] split) throws IOException {
            File file = new File(split[3]);
            if (file.isDirectory()){
                //判断为文件
                File[] files = file.listFiles();
                for(File f :files){
                    split[3] = f.getPath();
                    recursionOperation(split);
                }
            }else {
                //判断为非文件
                String fileName = file.getName();
                //判断是否为C后缀文件
                if ("c".equals(fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()))){
                    String[] operation = new String[]{split[0],split[2],file.getPath()};
                    System.out.println(file.getPath());
                    basicOperation(operation);
                    System.out.println("-------------------------------------------------------------");
                }
            }
        }
    

    • bat文件:
    javac -encoding utf-8 Wc.java
    java Wc
    

    测试运行

    • 测试 -c 命令

    • 测试 -w 命令

    • 测试 -l 命令

    • 测试 -a 命令

    • 测试 -s 命令

    test文件目录结构

    test00.c

    test01.c

    test02.c

    测试结果:

    一些错误的指令输入


    项目小结

    • 优点:有了充足的规划后,在进度方面有了较为合理的时间安排。也了解了软件开发的一些相关知识。

    • 缺点:时间不充足,很多功能未能来得及实现

    • 改进:我认为在之后的开发中,规划可能可以适当的延长,将开发环节效率最高化。

  • 相关阅读:
    Matlab练习——素数查找
    Matlab 三维绘图与统计绘图
    Matlab练习——多项式和一元方程求解
    Matlab 矩阵函数
    Malab 常用数学函数
    Matlab练习——矩阵和数组的操作
    Matlab 图像处理入门
    Matlab 二维绘图函数(plot类)
    Matlab 曲线拟合之polyfit与polyval函数
    android 画虚线、实线,画圆角矩形,一半圆角
  • 原文地址:https://www.cnblogs.com/gdutming/p/12500053.html
Copyright © 2020-2023  润新知