要求

  • 基本要求

    • [x] -c 统计文件字符数 (实现)

    • [x] -w 统计文件词数 (实现)

    • [x] -l 统计文件行数(实现)

  • 扩展功能

    • [x] -s 递归处理目录下符合条件得文件(实现)
    • [x] -a 返回文件代码行 / 空行 / 注释行(实现)
    • [x] 支持各种文件的通配符(*,?)(实现)
  • 高级功能

    • [ ] -x 图形化界面(未实现)

GitHub仓库:https://github.com/Pramy/wc

设计

按照需求可以分为3个模块,1:对文件内容的统计,2:对输入指令的解析,3:批量操作

第一个模块:可以将文本一行一行分析得到自己的结果,可以将一种指令对应一个处理器(handler),在程序启动的时候加载所有处理器,然后针对不同的指令调用不同的处理器,并且应该有获取结果的接口,然后再对各种处理进行抽象,抽象出Handler接口。

第二个模块:第二个模块加上第一个模块就需要相对调整第一个模块,根据输入的指令解析后,得到各种各样的处理器,然后把它连成一条处理链,将需要分析的一行字符串,从头到尾依次处理,也应当有一条获取结果的调用链,从头到尾一次获取处理结果,然后再对模块一的Handler进行抽象,得到AbstractHandler,各种处理器应当继承这个抽象处理器,然后对输入的命令进行匹配,查找

理器的架构图如下

第三个模块:根据-a命令来设计批量分析功能

代码

启动类App.java

public class App {private static final Map<String, Handler> MAP;private static boolean IS_RECURSION = false;private static String NAME;private static Handler HEAD;//将处理器存在map中static {MAP = new HashMap<>();MAP.put(Order.L.getCommand(),new LineHandler());MAP.put(Order.W.getCommand(),new WordHandler());MAP.put(Order.C.getCommand(),new CharHandler());MAP.put(Order.A.getCommand(),new StructureHandler());}public static void main(String[] args) throws IOException {File file = build(args);//对于通配符的处理String name = file.getName();if (file.isDirectory()) {NAME = ".*";} else {file = file.getParentFile();NAME = name.replaceAll("\\.", "\\\\.").replaceAll("[*?]", ".*");}if (file == null || !file.exists()) {throw new RuntimeException("文件:不存在");}File[] files = file.listFiles();if (files != null) {for (File file1 : files) {read(file1);}}}/*** 处理文件* @param file 需要分析的文件* @throws IOException io*/private static void read(File file) throws IOException {if (file.isFile() && file.getName().matches(NAME) && file.canRead()) {System.out.println(file.getPath());FileReader fileReader = new FileReader(file);BufferedReader bf = new BufferedReader(fileReader);String s;if (HEAD != null) {while ((s = bf.readLine()) != null) {//1.将读到的一行字符串从头带尾依次处理HEAD.handle(s);}//2.处理完成后获取处理结果HEAD.get();//3.清除处理结果以便接下来的处理HEAD.clear();}}//判断是否要递归处理if (IS_RECURSION) {File[] files = file.listFiles();if (files != null) {for (File file1 : files) {read(file1);}}}}/*** 构建处理链,然后分析是否要递归查找* @param args orders* @return file*/private static File build(String[] args) {Handler pos = null;for (int i = 0; i < args.length - 1; i++) {//对指令-s 的处理if (args[i].equals(Order.S.getCommand())) {IS_RECURSION = true;} else {Handler handler = MAP.get(args[i]);if (handler != null) {if (HEAD == null) {HEAD = handler;} else if (pos instanceof AbstractHandler) {//构建链表((AbstractHandler) pos).setNext(handler);}pos = handler;} else {throw new RuntimeException("参数:" + args[i] + "无效");}}}return args.length >= 1 ? new File(args[args.length - 1]) : new File("");}
}

AbstractHandler

@Setterprivate Handler next;//调用链的核心代码,只需要子类实现doHandle方法既可以实现链式调用@Overridepublic void handle(String line) {doHandle(line);if (next != null) {next.handle(line);}}protected abstract void doHandle(String line);

AbstractHandler是调用链的核心类。如果依次有处理器A->B->C,在调用了A的handle()方法后,然后A,B,C的doHandle()方法也会依次被调用

统计字符-c :CharHandler

    @Overridepublic void doHandle(String line) {//windows \r\n//Mac     \r//Unix    \ncount += line.length() + System.lineSeparator().length();}

count为字符数,一行字符串后面并没有算上回车符,然后根据不通过的操作系统补上相应的数量

统计单词-w:WordHandler

    @Overridepublic void doHandle(String line) {String s = line.replaceAll("[\\p{Nd}\\u4e00-\\uffe5\\p{Punct}\\s]", " ");count += StringUtils.split(s, " ").length;}

将一行中的数字和和中英文标点符号和中文替换为" " ,然后按照" "切分得到的数量就是单词数

统计行数-l:LineHandler

每一次++就可以,代码过于简单就不贴了

统计复杂结构 -a:StructureHandler

public class StructureHandler extends AbstractHandler {//空行private int emptyLine;//代码行private int codeLine;//注释行private int annotationLine;//注释开始标志private boolean isContinue;/**这种属于多行注释* @param line line*/@Overrideprotected void doHandle(String line) {//如果进入了多行注释/* 那必须得匹配*/才可以结束,并且/* */中间的所有行都是注释行if (isContinue) {if (line.matches(".*\\*/\\s*")) {isContinue = false;}annotationLine++;} else {//匹配全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符if (StringUtils.isAllBlank(line) || line.matches("\\s*\\p{Graph}\\s*")) {emptyLine++;//匹配单行注释// 和/* */} else if (line.matches("\\s*}?\\s*//.*") || line.matches(".*/\\*.*\\*/.*")) {annotationLine++;//匹配/*} else if (line.matches(".*/\\*.*")) {isContinue = true;annotationLine++;//匹配代码行} else {codeLine++;}}}}

首先判断是不是多行注释,如果是一定要匹配到结尾符号*/才算结束,如果不是多行注释,就对每一行的内容进行分析

测试

在命令行输入

java -jar count-1.0-jar-with-dependencies.jar  -w -c -l -a -s d://123.txt

然后得到结果

123.txt文件

代码覆盖率

进行代码覆盖率测试

运行命令(统计d盘下面所有的txt文件)

 -w -c -l -a -s d://*.txt

整体代码覆盖率是92%

PSP

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

总结

从新学了一遍正则表达式,由于一开始思路没有清晰,没有理解清楚需求,导致设计有点偏差,导致花费了大量时间在写无用代码上,造成了极大的浪费,在写代码的过程中希望写的高效经常尝试改写代码,在方案上面一开始没有定夺下来,也可能这方面用得比较少或者缺乏经验,导致走了很多弯路,在这个作业中,重新认识到Java一些比较有用并且高效的知识,收获还是蛮多的[]

转载于:https://www.cnblogs.com/pramy/p/9607743.html

WC Java 实现相关推荐

  1. 软件工程 java实现_软件工程作业——WC Java实现

    项目要求: 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功能,并能够快速地处理多个文件. 具体功能 -c 返回文件字符数 -w 返回词的数目 -l 返回行数 扩展 ...

  2. java开发个人项目_个人项目-WC (java实现)

    二.PSP表格 PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟) Planning 计划 30 30 · Estimate · 估计这个任务 ...

  3. java 添加用户 数据库,跟屌丝学DB2 第二课 建立数据库以及添加用户

    在安装DB2 之后,就可以在 DB2 环境中创建自己的数据库.首先考虑数据库应该使用哪个实例.实例(instance) 提供一个由数据库管理配置(DBM CFG)文件控制的逻辑层,可以在这里将多个数据 ...

  4. DB2: 为DB2数据库创建新用户帐户并为其分配特定特权

    目标 到目前为止,一直使用实例管理员帐户(SYSADM)来执行所有数据库命令.这个帐户对所有实用程序.数据和数据库对象具有完全访问权.因此,为了避免无意或有意的数据损失,必须要保护这个帐户.在大多数情 ...

  5. Oracle count函数原理,oracle count函数

    用来返回查询的行数. 当指定distinct时,不能接order_by_clause: 如果指定表达式,count返回表达式不为空的值: 当指定*号时,它返回所有行,含重复行和空值.count从不返回 ...

  6. HUST软测1504班第2周作业成绩:WordCount

    说明 本次公布的成绩为第2周个人作业WordCount的结果: 第2周个人作业:WordCount 如果同学对作业结果存在异议,可以: 在毕博平台讨论区的第2周作业第在线答疑区发帖申诉. 或直接在博客 ...

  7. flink keyby指定key方式详解

    1.keyby算子 keyby是flink中非常常见的操作.其作用为在逻辑上将流划分为不相交的分区,而具有相同key的数据都分配到同一个分区.这种操作在各种大数据计算引擎中都非常常见,比如最早的map ...

  8. 知道公司抢“坑位”是什么意思吗?

    一. 故事起源 很久很久以前,大概也就是昨天,肠胃作祟,急需排泄,提裤奔跑,进入厕所, 左右扫视,没有坑位,灵光一闪,换了楼层,找到坑位, 拉完粑粑接着回去写bug. 二.不安现状 身为程序员的我,想 ...

  9. 08001db2java程序,spring 访问db2 数据库时,一开始没问题,最近会经常出现这个错误 ERRORCODE=-4499, SQLSTATE=08001...

    Caused by: com.ibm.db2.jcc.b.gm: [jcc][t4][2030][11211][3.50.152] 在对连接的底层 socket.socket input stream ...

最新文章

  1. 整理oracle 树形查询
  2. tfs 点获取最新,如果检查到大量冲突
  3. mysql jdbc 5.1.6_mysql5.0+Mysqljdbc5.1.6.jar的整合 | 學步園
  4. Web前端开发笔记——第二章 HTML语言 第四节 超链接标签
  5. 深圳多管齐下破解“融资难”
  6. 四则运算题目生成程序(基于控制台)
  7. mvc分页生成静态页,mvc生成静态页
  8. 深度学习(2)--深度学习中的这25个概念
  9. 全球仅4人,刚毕业年薪201万元 !华为最高档“天才少年”回应...
  10. nao机器人行走速度_数计学院学子在2020世界机器人大赛总决赛中荣获佳绩!
  11. 出现类似于 ”IDD_DLG_WAIT 未声明的标识符“ 这样的错误怎么办
  12. HDU1293+Java+大整数
  13. 第一阶段 高等数学——常量与变量
  14. Dato for mac(自定义菜单栏日历)支持m1
  15. Redis数据类型及编码
  16. 星空特效HTML代码,HTML5特效库 HTML5+JS全屏星空特效源码
  17. 【单片机笔记】PWM信号与PPM信号简单理解
  18. 《与我长跑十年的女友就要嫁人了》…
  19. 英雄联盟英雄中英文名
  20. 做“合规”的数据处理者 | 一文图解《网络数据安全管理条例》

热门文章

  1. 《TT语音》用户体验分析报告
  2. Eeid—ligerUI学习(1)[首页布局]
  3. 姬魔恋战纪服务器维护,姬魔恋战纪闪退、进不去、黑屏不能玩的原因和解决办法[图]...
  4. 广州刷脸支付骗局_刷脸支付骗局你仔细观察一下
  5. 夫妻之间赠与房产,没过户前可以反悔
  6. 计算机专业小论文题目,计算机专业小类论文题目 计算机专业小论文题目怎样拟...
  7. layui checkbox选中
  8. 计算机电子工程专业就业前景,就业前景好的4大类专业,电气电子类上榜,有你喜欢的吗?...
  9. 移动端弹出层滚动时禁止body滚动
  10. 用心整理10个宝藏APP,涨薪刚需,入股不亏