Github:

https://github.com/whoNamedCody/WordCount

PSP表格 

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

            10            15

· Estimate

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

            20            20

Development

开发

           180            250

· Analysis

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

            10            30

· Design Spec

· 生成设计文档

            10            20

· Design Review

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

            20               20

· Coding Standard

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

            10             20

· Design

· 具体设计

            20             20

· Coding

· 具体编码

           100            150

· Code Review

· 代码复审

            20            30

· Test

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

            50           100

Reporting

报告

            20            40  

· Test Report

· 测试报告

            30            40

· Size Measurement

· 计算工作量

            10            10

· Postmortem & Process Improvement Plan

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

             5            15
 

合计

           515           780

需求说明:

WordCount的需求可以概括为:对程序设计语言源文件统计字符数、单词数、行数,统计结果以指定格式输出到默认文件中,以及其他扩展功能,并能够快速地处理多个文件。

1、基础功能:

-c:输出字符,

-l:输出代码行,

-w:输出单词,

-o:输出

2、 扩展功能:

-a:输出代码行/空行/注释行,

-s:递归处理文件,

-e:停用词表,

解题思路:

1、java实现,但需要转成exe在cmd下输入命令执行,所以流程是:编码(.java)-->Export(.jar)-->exe4j(.exe)

2、java里有static void main(String[] args),里面的args就是cmd下的命令数组,比如输入-c -l -w file.c(空格隔开),那么args数组长度为4

3、对args数组进行遍历分析,找出输入命令和文件名,比如-c -l -w -a 后面跟的是输入文件名,-s后面会跟*.c之类的通配文件,-e后面会跟停用词表stoplist.txt,-o接输出文件result.txt

这里识别出命令和文件后,会再对文件分析,比如-s  ./WordCount/*.c,需要截取出文件的上一层(相对)路径./WordCount和后缀.c,方便后续递归文件夹下的.c文件

4、将所有的统计封装成一个函数:public void command(String[] args,String inputFile,String outputFile,WordCount WC)

5、创建一个WordCount类,里面的属性有字符数,单词数,行数,代码行,空行,注释行,如果没有出现-s:则只实例化一个对象WordCount,调用一次command函数,输出前面的结果,如果出                           现 -s:即递归处理文件夹下面的*.c文件(当然*.txt,*.doc文件也是可以的),就声明多个WordCount对象,循环对对象属性进行赋值。如果需要输出就调用get和set方法获取属性值。

6、递归处理文件:根据相对路径递归寻找文件夹下的后缀文件。

程序设计实现:

类:

public class WordCount{}

函数方法设计:

WordCount(int,int,int,int,int,int)是构造函数;get和set是MyEclipse自动生成的的getter和setter方法,main(string [ ])是程序入口,分析判断指令格式;command(String [ ],String,String,WordCount)执行指令,返回相应指令的统计值;wc(String,String)对输入文件进行统计;inStop(String,String[ ])判断单词是否在停用词表内;getFile(File)递归获取文件。

代码说明:

1、执行命令:需要输出的有-c,-w,-l,-a,判断指令,直接暴力循环,优化日后再说。

 //命令执行,根据命令输出数据到屏幕和outputFile中
public void command(String[] args,String inputFile,String outputFile,WordCount WC)throws IOException{
String outResult="";
inputFile=inputFile.substring(inputFile.lastIndexOf("\\")+1, inputFile.length());
for(int i=0;i<args.length;i++){
if(args[i].equals("-c"))
outResult=outResult+inputFile+",字符数:" + WC.getCharCount()+"\r\n";
}
for(int i=0;i<args.length;i++){
if(args[i].equals("-w"))
outResult=outResult+inputFile+",单词数:" + WC.getWordCount()+"\r\n";
}
for(int i=0;i<args.length;i++){
if(args[i].equals("-l"))
outResult=outResult+inputFile+",行数:" + WC.getLineCount()+"\r\n";
}
for(int i=0;i<args.length;i++){
if(args[i].equals("-a"))
outResult=outResult+inputFile+",代码行/空行/注释行:"+WC.getCodeCount()+","
+WC.getSpaceCount()+","+WC.getNoteCount()+"\r\n";
}
//写数据到outputFile
System.out.println(outResult);
File writename = new File(outputFile);
writename.createNewFile();
BufferedWriter out = new BufferedWriter(new FileWriter(writename,true));
out.write(outResult);
out.flush();
out.close();
}

2、统计功能字符数、单词数、行数、代码行/空行/注释行

提一下代码行/空行/注释行

      匹配空行的正则表达式或则判断该行只有一个字符,则当前行为空行,匹配/*,如果存在,注释行++,标志进入注释行,继续匹配*/,如果不存在,注释行++,记下总共多少行,遇到*/,注释行++,标志结束注       
      释行,再匹配单行注释,其他的是代码行,最后计算注释的时候要减去只有/*没有 */的要加
 //统计功能字符数、单词数、行数、代码行/空行/注释行
public void wc(String inputFile,String stopFile) throws IOException{
String lineString = null;
String[] buffer=null; //文件每行
String[] buffer1 = null;//stoplist boolean isNote = false;
int notNote=0; //读取停用词表
if(useStop){
File dirr=new File(stopFile);
BufferedReader bff = new BufferedReader(new FileReader(dirr));
while((lineString=bff.readLine())!=null){
buffer1=lineString.split(",| ");
}
bff.close();
}
lineString = null; // 读取输入文件inputFile
File dir=new File(inputFile);
BufferedReader bf = new BufferedReader(new FileReader(dir));
while((lineString=bf.readLine())!=null){ //遇到 , 空格 就结束赋值
buffer=lineString.split(",| ");
for(int i=0;i<buffer.length;i++){ //使用停用词表则剔除词表内单词,不用则不踢
if(useStop){
if(!buffer[i].equals("")&&!inStop(buffer[i], buffer1)){
wordCount++;
}
}
else{
wordCount++;
} }
if(buffer.length!=1)
lineCount++; charCount+=(lineString.length()+1); lineString=lineString.trim();
//空行,一个字符的也算空行
if (lineString.matches("^[//s&&[^//n]]*$")||lineString.length()==1) {
spaceCount++;
}
//注释/*的开始
else if (lineString.startsWith("/*") && !lineString.endsWith("*/")||((lineString.startsWith("{/*")
||lineString.startsWith("}/*"))&&!lineString.endsWith("*/"))){
noteCount++;
isNote=true;
}
//没有遇到*/
else if(isNote&&!lineString.endsWith("*/")&&!lineString.startsWith("*/")) {
notNote++;
noteCount++;
}
//遇到*/
else if (isNote == true && (lineString.endsWith("*/")||lineString.startsWith("*/"))) {
noteCount++;
isNote=false;
}
//注释行
else if (lineString.startsWith("//")|| lineString.startsWith("}//")||lineString.startsWith("{//")||
((lineString.startsWith("{/*") ||lineString.startsWith("}/*")||lineString.startsWith("/*"))
&& lineString.endsWith("*/"))) {
noteCount++;
}
else{
codeCount++;
}
}
bf.close();
noteCount-=notNote;
codeCount+=notNote;
}
3、每次判断单词是否在停用词表内
 //判断是否在停用词表内
public static boolean inStop(String str,String[] buffer){
int count=0;
for(int i=0;i<buffer.length;i++){
if(str.equals(buffer[i])){
count++;
}
}
if(count>0)
return true;
else
return false;
}

4、遍历文件目录,如-s ./test/*.c则递归遍历./test目录下的.c文件

 //遍历目录文件
public static List<File> getFile(File dir) {
List<File> files = new ArrayList<File>();
// 此文件下的所有文件和文件夹集合
File[] subs = dir.listFiles();
for (File file : subs) {
if (file.isFile() && file.getName().endsWith(endStr)) {
// 把获取到的后缀文件添加到集合中,可以是任何后缀文件
files.add(file);
} else if (file.isDirectory())
//如果是目录,就进行递归
files.addAll(getFile(file));
}
return files;
}

测试设计过程:

    设计测试用例的思路是采用白盒测试的语句覆盖,尽可能把测试用例覆盖所有可能的程序语句,当然特别是分支语句,会多做测试,如-s的是否递归处理文件在我的程序中是一个分支语句

基本功能:

1、测试-c:输出file.c字符数

wc.exe -c file.c

2、测试-c、-w、-l:输出file.c字符数,单词数、行数 (当前根目录)

wc.exe -c -w -l file.c

3、测试-w 、-l 、-c:输出./testFile/file.c 字符数,单词数、行数 (根目录下其他路径,命令顺序)

wc.exe -w -l -c ./testFile/file.c

4、测试-c 、-l 、-w、-o:输出file.c字符数,单词数、行数、输出到文件resultAdd.txt

wc.exe -c -l -w file.c -o resultAdd.txt

扩展功能:

         5、测试-a:输出file.c的代码行/空行/注释行

wc.exe -a file.c

6、测试-s、-a:输出根目录下所有.c文件的代码行/空行/注释行

wc.exe -s -a *.c

7、测试-e:测试停用词表stoplist.txt

wc.exe -w file.c -e stoplist.txt

8、测试-c、-w、-l 、-a、-o:输出file.c字符数,单词数、行数 、代码行/空行/注释行输出到result.txt

wc.exe -c -w -l -a file.c -o result.txt

9、测试-a、-s、-e:测试递归,代码行/空行/注释行,停用词表stoplist.txt

wc.exe -a -s ./testFile/*.c -e stoplist.txt

10、测试-c、-w、-l、-a、-e、-o:对不递归进行测试

wc.exe -c -w -l -a file.c -e stoplist.txt -o result.txt

11、测试-c、-w、-l、-a、-s、-e、-o:覆盖所有的指令测试

测试脚本

         点击testScript.exe可以执行完11个测试用例,类似于批处理的方式,但只有一个进程,批处理测试用例。

下面是java代码,简单叙述一下思路:创建一个进程打开之前的wc.exe,逐行读取测试用例testCase.txt,一行是一条测试用例。

 package test;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner; public class TestScript {
//进程p
static Process p;
public static void main(String[] args) throws IOException{
String lineString=null;
File dirr=new File("testCase.txt"); //测试用例文件
if(dirr.exists()){
BufferedReader bff = new BufferedReader(new FileReader(dirr));
while((lineString=bff.readLine())!=null){
//非空行执行测试用例
if(!lineString.trim().matches("^[//s&&[^//n]]*$")){
System.out.println(lineString);
command(lineString);
}
}
bff.close();
}else{
System.out.println("没有该测试文件");
} Scanner sc = new Scanner(System.in);
String scc=sc.nextLine();
} public static void command(String cmd){
Runtime run = Runtime.getRuntime();//返回与当前 Java 应用程序相关的运行时对象
try {
p = run.exec(cmd);// 启动另一个进程来执行命令
BufferedInputStream in = new BufferedInputStream(p.getInputStream());
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null)
System.out.println(lineStr);
if (p.waitFor() != 0) {
if (p.exitValue() == 1)
System.err.println("命令执行失败!");
}
inBr.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
} }

参考链接:

https://www.baidu.com

https://i.cnblogs.com/

https://bbs.csdn.net/

https://github.com/

WordCount--实现字符,单词,代码统计的更多相关文章

  1. 软件工程 wc.exe 代码统计作业

    软件工程 wc.exe 代码统计作业分享 1. Github 项目地址 https://github.com/EdwardLiu-Aurora/WordCount 更好地阅读本文,可点击这里 基本要求 ...

  2. WC 代码统计 java

    GitHub地址 项目需求 实现一个wc统计程序,可以对文本进行相关功能的统计与分析 基本功能 -c 统计字符数 -w 统计文件词数 -l 统计行数 扩展功能 -s 递归搜索目录下面的文件 -a 返回 ...

  3. Spark学习笔记1——第一个Spark程序:单词数统计

    Spark学习笔记1--第一个Spark程序:单词数统计 笔记摘抄自 [美] Holden Karau 等著的<Spark快速大数据分析> 添加依赖 通过 Maven 添加 Spark-c ...

  4. python 练习(一)代码统计工具的实现

    最近部门成立了一个python学习小组,旨在让大家在做项目中开始成长起来,于是老大就给布置了第一个小任务:代码统计工具,具体的需求如下: 需求: . 能够统计指定目录下C++程序的代码行数. . C+ ...

  5. Python实现代码统计工具——终极加速篇

    Python实现代码统计工具--终极加速篇 声明 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对 ...

  6. Python代码统计工具

    目录 Python代码统计工具 声明 一. 问题提出 二. 代码实现 三. 效果验证 Python代码统计工具 标签: Python 代码统计 声明 本文将对<Python实现C代码统计工具(一 ...

  7. Python实现C代码统计工具(三)

    目录 Python实现C代码统计工具(三) 声明 一. 性能分析 1.1 分析单条语句 1.2 分析代码片段 1.3 分析整个模块 二. 制作exe Python实现C代码统计工具(三) 标签: Py ...

  8. Atitit. . 软件命名空间与类名命名单词的统计程序设计v2

    Atitit. . 软件命名空间与类名命名单词的统计程序设计v2 1. 要实现的目标1 1.1. Camel字符串模式的分词处理1 1.2. 多个大写的处理1 1.3. 数字与字幕的分离1 1.4.  ...

  9. 【学习笔记】C#中HashTable和快速排序的用法,从单词频率统计小程序写起

    先瞎扯点别的.进入这个神圣的地方总需要些鞭策,阿西巴,我是被鞭策进来摆摊的程序猿.软件工程老师说,写程序,发博客,就来博客园.这是个号召力很强的口号.最近看网络营销 搜索引擎优化的书多一些,只能说王老 ...

  10. Java实现 蓝桥杯VIP 算法提高 不同单词个数统计

    算法提高 不同单词个数统计 时间限制:1.0s 内存限制:512.0MB 问题描述 编写一个程序,输入一个句子,然后统计出这个句子当中不同的单词个数.例如:对于句子"one little t ...

随机推荐

  1. 获取radio点击事件

    获取radio点击事件,不能用click(),而是用change(). $('input[name="options"]').change(function(){ console. ...

  2. FineReport做成之后如何在Tomcat上运行

    问题描述: 自己用FineReport做成的报表画面,要在Tomcat上运行启动 第一步:下载Tomcat 网址: http://tomcat.apache.org/download-80.cgi 下 ...

  3. Source Insight快捷键

    常用使用技巧 按住"ctrl", 再用鼠标指向某个变量(或函数),点击一下,就能进入这个变量(或函数)的定义. 快捷键 "Alt + F12",可以让显示界面中 ...

  4. 工作总结 CTO(张王岩) File构造器

    import java.io.File; /** * 构建File对象 * @author Allen17805272076 * */ public class FileDemo2 { public ...

  5. 多年经验【Parallels Desktop14.0.1 永久激活 】版 推荐苹果mac 虚拟机pmg序列号

    parallels desktop 14 mac 激活码          parallels 13免费密钥 parallels desktop 14 激活码 很多用 MAC 的朋友发现平时离不开 W ...

  6. 【CodeForces】868F. Yet Another Minimization Problem

    原题链接 题目大意是有N个数,分成K段,每一段的花费是这个数里相同的数的数对个数,要求花费最小 如果只是区间里相同数对个数的话,莫队就够了 而这里是!边单调性优化边莫队(只是类似莫队)!而移动的次数和 ...

  7. Scratch运动模块——有趣的弹球游戏(一)

    大家好!我是蓝老师,有了前几期Scratch的基础,相信大家早已摩拳擦掌,跃跃欲试了,甚至还有些小伙伴已经编写了非常不错的程序. 学习编程就是这样不断探索.主动思考.解决问题的过程. 本期内容: 课程 ...

  8. (转)从0移植uboot (四) _点亮调试LED

    这一节主要讨论1个问题:点灯.点灯是实际开发中,特别是裸板开发中常见的调试手段,相当于主机开发中漫天飞舞的printf/printk.为了追踪程序的现场执行情况,很多时候我们都使用点一个灯的方法来进行 ...

  9. 怎样修改原型对象prototype

    修改原型对象的方法分为两种情况, 一种是对原型对象的属性方法做增删改, 一种改变原型对象的指向. 第一种: 对原型对象的属性/方法做增删改 function Person(name){ this.na ...

  10. JS原型的动态性

    由于在原型中查找成员的过程是一次搜索,所以我们对原型对象所做的任何修改都能立即从实例上反映出来(但不包括对原型对象的重写,下面会介绍到),即使是对原型的修改操作在创建实例之后.如下面的示例所示: fu ...