统计.java源文件的关键字
统计.java源文件的关键字
问题叙述&分析
问题叙述:
? 实现一个类 Keyordldentifer,其中的核心方法的功能是读入1个 java 程序源文件,在控制台输出各个关键字的个数。
- 对Java语言的所有关键字进行统计,不是仅针对部分关键字。
- 要求具备“跳过注释”功能,注释中出现的关键字不计入关键字个数(要求支持单行注释“/... 和多行注释“/*/”的跳过)。
问题分析:
对java代码的关键字的统计可分为以下流程:
? 1.读取文件
? 题中读取的是java程序源文件——文本文件,因此可以使用 BufferedReader 字符流来读取 java 程序源文件。同时使用 BufferedReader 的好处在于,BufferedReader 提供了逐行读取文本的方法,对于本题中 java 代码的读取和文本分析更为方便。
//1.造流
br = new BufferedReader(new FileReader(inFile));
//2.数据操作
String data;
while ((data = br.readLine()) != null) {
//对字符串data进行一系列处理操作
}
? 2.对字符串data进行处理
? 因为要求统计的是 java 关键字,所以首先将53个关键字记录在 keywords.txt 文本文件中,在程序刚开始时,将此文件加载到内存中为一个 List< String > javaWords。然后对 data 中的每个单词进行检查,若javaWords中有,则加入统计。
if (javaWords.contains(word)) {
wordsCount.put(word, wordsCount.getOrDefault(word, 0) + 1);
return 1;
}
同时对于例如 "Map
StringBuilder sb = new StringBuilder(data);
for (int i = 0; i < sb.length(); i++) {
char c = data.charAt(i);
if (!Character.isLetterOrDigit(c) && c!='_' && c != '/' && c != '*') {
sb.replace(i,i+1," ");
}
}
stringHandle(sb.toString());
? 3.处理字符串中的 // 和 /**/
? 若遇到 //,则将 // 后的所有内容抛弃掉,只取 // 之前的字串;若遇到 /* , 则将 /* 后的所有内容抛弃掉,只取 /* 之前的子串,同时此时设置一个标志 flag=1,后续只要 flag 为1,则内容全部抛弃,直到遇到 */,令 flag=0,并取 */ 之后的子串。
String[] words = str.split(" ");
for (String word : words) {
if (word == null) {
continue;
} else if (word.contains("//")) {
int index = word.indexOf("//");
String substring = word.substring(0, index);
wordCount(substring);
break;
} else if (word.contains("/*")) {
int index = word.indexOf("/*");
String substring = word.substring(0, index);
wordCount(substring);
flag = 1;
break;
} else if (flag == 0) {
wordCount(word);
} else if (flag == 1 && word.contains("*/")) {
int index = word.indexOf("*/");
String substring = word.substring(index+2);
wordCount(substring);
flag = 0;
}
}
? 4.输出统计结果
? 因为是使用 Map 进行统计关键字,所以只需要将统计关键字的 Map
wordsCount.entrySet().forEach(System.out::println);
测试代码
KeywordIdentifierTest.java
@Test
public void keywordsCount() {
identifier.keywordsCount();
}
运行结果
在终端显示:
存储到.properties文件中
一些问题
- 程序中涉及到数次对文件输入流输出流的关闭操作,有冗余代码重复的嫌疑,因此创建一个 FileUtils 工具类,设置4个重载的 public static void closeStream() 方法,通过传入的流的不同,调用相应的关闭流的方法。
- 在将字符串中会干扰统计关键字的字符替换为空格字符时,涉及到大量的字符串的修改操作,使用String进行修改,因为每次修改都会返回一个新的 String,再加上本题不涉及线程安全问题,因此这里使用 StringBuilder 来操作。
- 统计完关键字的数量后,鉴于已经涉及了很多文件的 io 操作,那为什么不也将统计的结果保存起来呢?统计关键字用的是 Map,因此正好可以很方便地保存在 .properties 文件中
for (Map.Entry entry : wordsCount.entrySet()) {
properties.setProperty(entry.getKey(), entry.getValue().toString());
}