GitHub地址:https://github.com/hanfeng98/WC
项目简介:
实现一个统计目标文件字符数、单词数、行数及其他特殊数据的的命令行程序。并能处理多个文件,同时还能识别一般的通配符。
基本项目要求:
基本功能:(已实现)
-c <文件路径> 统计文件中字符的数量。
-w <文件路径> 统计文件中单词的数量。
-l <文件路径> 统计文件的总行数。
扩展功能:(已实现)
-s <搜寻目录路径> <文件类型名> 批量处理符合条件的文件。(可识别一般通配符:*、?)
-a <文件路径> 统计文件代码行、空白行、注释行的数量。
高级功能:(未实现)
-x 显示图形界面
解题思路
项目开始后,先考虑了载入文本的方法,一是把代码内容全部通过输入输出流导入到一个长字符串中,二是通过输入输出流的readline方法进行边输入边统计,并且把统计功能封装成方法,通过调用方法进行统计,方法中通过使用正则表达式来区分目标对象。命令行输入通过map建立映射结合switch调用功能。
代码结构:
关键代码说明:
解析命令行参数
public static void main(String[] args) {
// TODO 自动生成的方法存根
System.out.print("请输入需要进行的操作与操作对象:");
Scanner sc=new Scanner(System.in);
String temp[]=sc.nextLine().split("\\s+");
String option=temp[0];
String filepath=temp[1];
String filetype=temp[2].substring(temp[2].lastIndexOf(".")+1);
String tongpei=temp[2].substring(0, temp[2].indexOf("."));
File file=new File(filepath);
try {
sc.close();
}catch (Exception e){
e.printStackTrace();
};
Map<String,Integer> map=new HashMap<String,Integer>();//通过map建立映射关系与switch调用方法
map.put("-c",1);
map.put("-w",2);
map.put("-l",3);
map.put("-s",4);
map.put("-a",5);
wordcount count=new wordcount();
switch (map.get(option)) {
case 1:count.charactercount(file);break;
case 2:count.wordcount(file);break;
case 3:count.linecount(file);break;
case 4:count.rtcatalog(file,tongpei,filetype);break;
case 5:count.CountSpecialLines(file);break;
default:System.out.println("请重新按格式输入"+"\n"+"[parameter] [file_name]");
}
}
统计行数、字符数、单词数
void charactercount(File file) {
String str=null;
char temp[]=null;
int characternum=0;
try {
InputStreamReader ir =new InputStreamReader(new FileInputStream(file));
BufferedReader BF=new BufferedReader(ir);
while((str=BF.readLine())!=null) {
temp=str.toCharArray();
characternum+=temp.length;
}
ir.close();
BF.close();
System.out.println("字符数:"+characternum);
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
System.out.println("无法找到指定的文件");
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
System.out.println("文件读取失败");
}
}
void wordcount(File file) {
String str=null;
int wordnum=0;
try {
InputStreamReader ir =new InputStreamReader(new FileInputStream(file));
BufferedReader BF=new BufferedReader(ir);
while((str=BF.readLine())!=null) {
wordnum+=str.split("\\W").length;
}
ir.close();
BF.close();
System.out.println("单词数:"+wordnum);
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
System.out.println("无法找到指定的文件");
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
System.out.println("文件读取失败");
}
}
try {
InputStreamReader ir =new InputStreamReader(new FileInputStream(file));
BufferedReader BF=new BufferedReader(ir);
while(BF.readLine()!=null) {
linenum++;
}
ir.close();
BF.close();
System.out.println("总行数:"+linenum);
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
System.out.println("无法找到指定的文件");
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
System.out.println("文件读取失败");
}
}
void CountSpecialLines(File file) {
int blanklines=0;
int commentlines=0;
int codelines=0;
String temp=null;
String blanklinesregex ="\\s*\\W?\\s*";
String bclbeginregex="\\s*.?\\s*/\\*.*";
String bclendregex="\\s*.?\\s*\\*/.*";
String clregex="\\W?//.*";
boolean blcflag=false;
try {
InputStreamReader ir =new InputStreamReader(new FileInputStream(file));
BufferedReader BF=new BufferedReader(ir);
while((temp=BF.readLine())!=null) {
if(temp.matches(blanklinesregex)&&(blcflag==false)) {
blanklines++;
}else if(temp.matches(bclbeginregex)&&temp.matches(bclendregex)) {
commentlines++;
blcflag=false;
}else if(temp.matches(clregex)) {
commentlines++;
}else if(temp.matches(bclbeginregex)||blcflag==true) {
commentlines++;
blcflag=true;
}else if((temp.matches(bclendregex))&&(blcflag==true)) {
commentlines++;
blcflag=false;
}else if(blcflag==false){
codelines++;
}
}
ir.close();
BF.close();
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
System.out.println("无法找到指定的文件");
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
System.out.println("文件读取失败");
}
System.out.println(" 空行 :"+blanklines);
System.out.println("代码行:"+codelines);
System.out.println("注释行:"+commentlines);
}
File listfile[]=filepath.listFiles();
String tongpei=null;
if(filename==null) {
tongpei=".*";
}else if(filename.contains("*")) {//通过pattern模式筛选出指定文件
tongpei=filename.replaceAll("\\*",".*");
}else if(filename.contains("?")) {
tongpei=filename.replaceAll("\\?",".?");
}
Pattern p=Pattern.compile(tongpei);
通过通配符模式筛选指定文件
for(File file:listfile) {
if(file.isDirectory()) {
rtcatalog(file,filename,str);
}else if(file.exists()){
Matcher m=p.matcher(file.getName());
if(file.getName().endsWith(str)&&m.find()) {
System.out.println("文件所在目录:"+file.getAbsolutePath());
charactercount(file);
wordcount(file);
linecount(file);
CountSpecialLines(file);
}
}else if(!file.exists()) {
System.out.println("无法找到指定的路径目录下指定类型的文件");
}
}
}
只有一行的文件
典型的源文件
递归遍历指定目录指定类型的文件
通配符 通过通配符筛选走文件
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
40 |
· Estimate |
· 估计这个任务需要多少时间 |
15 |
20 |
Development |
开发 |
300 |
360 |
· Analysis |
· 需求分析 (包括学习新技术) |
60 |
90 |
· Design Spec |
· 生成设计文档 |
30 |
40 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
20 |
20 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
15 |
20 |
· Design |
· 具体设计 |
60 |
80 |
· Coding |
· 具体编码 |
300 |
300 |
· Code Review |
· 代码复审 |
120 |
180 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
90 |
90 |
Reporting |
报告 |
90 |
120 |
· Test Report |
· 测试报告 |
60 |
45 |
· Size Measurement |
· 计算工作量 |
10 |
5 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
20 |
15 |
合计 |
1220 |
1425 |
总结:
本以为此项目会比较简单,但实际进行起来发现设计阶段的设计不足,查阅资料后知道要用正则表达式和文件输入流来解决问题,但是具体操作是发现正则表达式的表达式有些许疑问,特别是对于特定文件的筛选时,控制符号与正则表达式的转换让我耗费了不少时间,这让我深感基础的薄弱。