统计某目录下的所有文本文件的单词出现频率
思路
- 1.设置一个全局表来存放每一个出现过的单词和它的出现次数
- 2.遍历所有文件,根据文件类型来判断是不是我们想要读取的文件
- 3.读取文件内容
- 4.把文件内容分割成一个个单词,并将文件中出现的单词,以及出现的次数存到全局表中
- 5.根据出现次数从大到小排序数据
- 6.打印出结果
实现
1.设置一个全局表来存放每一个出现过的单词和它的出现次数
这里用TreeMap方便我们排序
private static Map<String, Integer> table=new TreeMap<String, Integer>();
2.遍历所有文件,根据文件类型来判断是不是我们想要读取的文件
通过递归遍历目录下的所有文件,我们只读取c,cpp,java为后缀的文件。
private static void statisticDir(File dir) {
if(dir.isFile()) {
return;
}
File[] fs=dir.listFiles();
if(fs==null) {
return;
}
for (File f:fs)
{
if (f.isFile())
{
String full=f.getAbsolutePath();
if(full.endsWith(".c")||full.endsWith(".cpp")||full.endsWith(".java")) {
statisticFile(full);
}
}
else{
System.out.println("扫描:"+f.getAbsolutePath());//想快点可以把这行注释掉
statisticDir(f);
}
}
}
3.读取文件内容
private static StringBuilder readFile(String file) {
BufferedReader bufferedReader=null;
StringBuilder stringBuilder=new StringBuilder();
try {
bufferedReader=new BufferedReader(new FileReader(file));
String line=null;
while ((line=bufferedReader.readLine())!=null) {
stringBuilder.append(line+"\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if(bufferedReader!=null) {
try {
bufferedReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return stringBuilder;
}
4.把文件内容分割成一个个单词,并将文件中出现的单词,以及出现的次数存到全局表中
这里将忽略单个字母的单词,支持大驼峰和小驼峰命名的单词组合拆分,例如:void setName(name);
或者void SetName(Name);
将被分解成4个单词。
private static void statisticWordsBySentence(String sentence){
int start=0;
int end=0;
String word=null;
boolean scan=false;
int len=sentence.length();
State state=State.Other;
for(int i=0;i<len;i++) {
char ch=sentence.charAt(i);
//小写字母
if(Character.isLowerCase(ch)) {
if(!scan){
start=i;
scan=true;
}
//根据前一个状态判断
if(state==State.Other){
state=State.LowerCase;
scan=true;
}
else if(state==State.LowerCase||state==State.UpperCase){
if(i==len-1){
end=len;
if(end-start==1) {
//不要一个字母的单词
scan=false;
continue;
}
word=sentence.substring(start, end);
if(!sensitive){
word=word.toLowerCase();
}
if(table.containsKey(word)) {
int newVal=table.get(word)+1;
table.put(word, newVal);
}
else {
table.put(word, 1);
}
}
}
}
//大写字母
else if(Character.isUpperCase(ch)) {
if(!scan){
start=i;
scan=true;
state=State.UpperCase;
continue;
}
if(state==State.LowerCase||state==State.UpperCase||state==State.Other){
end=(i==len-1)?len:i;
if(end-start==1) {
//不要一个字母的单词
scan=false;
continue;
}
word=sentence.substring(start, end);
if(!sensitive){
word=word.toLowerCase();
}
if(table.containsKey(word)) {
int newVal=table.get(word)+1;
table.put(word, newVal);
}
else {
table.put(word, 1);
}
state=State.UpperCase;
scan=true;
start=i;
}
}
//其他
else{
if(!scan){
scan=false;
continue;
}
if(state!=State.Other){
end=(i==len-1)?len:i;
if(end-start==1) {
//不要一个字母的单词
scan=false;
continue;
}
word=sentence.substring(start, end);
if(!sensitive){
word=word.toLowerCase();
}
if(table.containsKey(word)) {
int newVal=table.get(word)+1;
table.put(word, newVal);
}
else {
table.put(word, 1);
}
state=State.Other;
scan=false;
}
}
}
}
5.根据出现次数从大到小排序数据
private static List<Map.Entry<String, Integer>> sortData() {
List<Map.Entry<String, Integer>> entryArrayList = new ArrayList<>(table.entrySet());
Collections.sort(entryArrayList, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> v1, Map.Entry<String, Integer> v2) {
// TODO Auto-generated method stub
return v2.getValue()-v1.getValue();
}
});
return entryArrayList;
}
6.打印出结果
拼成Markdown的表格,使打印更加直观。在这里输出前100的排名,读者可自行调整
System.out.println("| 排名 | 单词 | 出现频率 |");
System.out.println("| ------------- |:-------------:| --------:|");
for(int i=0;i<100;i++) {
Map.Entry<String, Integer> entry=list.get(i);
System.out.println("| "+(i+1)+" | "+entry.getKey()+" | "+entry.getValue()+" |");
}
结果
在测试的时候,在大小写敏感模式下,统计某Java源码目录的结果,得到的结果如下:
排名 | 单词 | 出现频率 |
---|---|---|
1 | the | 311620 |
2 | if | 160965 |
3 | int | 147354 |
4 | to | 124752 |
5 | ud | 122707 |
6 | return | 120929 |
7 | is | 103377 |
8 | of | 97253 |
9 | public | 82258 |
10 | code | 80901 |
11 | get | 80374 |
12 | in | 78338 |
13 | this | 72584 |
14 | for | 66639 |
15 | void | 66632 |
16 | const | 65662 |
17 | String | 61459 |
18 | and | 60536 |
19 | static | 58577 |
20 | be | 52238 |
21 | new | 52176 |
22 | value | 50750 |
23 | set | 48107 |
24 | define | 46341 |
25 | or | 44280 |
26 | final | 44272 |
27 | The | 43007 |
28 | null | 40870 |
29 | param | 39200 |
30 | ua | 35429 |
31 | Exception | 35177 |
32 | not | 33046 |
33 | that | 32959 |
34 | with | 31674 |
35 | char | 31605 |
36 | private | 30663 |
37 | name | 30092 |
38 | by | 28578 |
39 | else | 28552 |
40 | on | 27356 |
41 | data | 27117 |
42 | link | 26914 |
43 | type | 26831 |
44 | length | 26330 |
45 | an | 25982 |
46 | License | 25953 |
47 | class | 25941 |
48 | android | 24778 |
49 | udc | 24752 |
50 | Code | 24273 |
51 | This | 24032 |
52 | ude | 23355 |
53 | key | 22997 |
54 | from | 22842 |
55 | are | 22709 |
56 | Object | 22363 |
57 | result | 22353 |
58 | Unicode | 22143 |
59 | import | 22070 |
60 | as | 21689 |
61 | it | 21530 |
62 | td | 21388 |
63 | size | 21351 |
64 | Array | 20837 |
65 | status | 20546 |
66 | file | 20100 |
67 | case | 20058 |
68 | udd | 19954 |
69 | Type | 19706 |
70 | index | 19660 |
71 | View | 19528 |
72 | use | 19258 |
73 | include | 18985 |
74 | Name | 18622 |
75 | object | 18118 |
76 | start | 18109 |
77 | boolean | 17693 |
78 | Value | 17223 |
79 | will | 16990 |
80 | out | 16947 |
81 | error | 16763 |
82 | Set | 16560 |
83 | may | 16362 |
84 | To | 16344 |
85 | string | 16319 |
86 | err | 16081 |
87 | true | 15680 |
88 | throws | 15655 |
89 | endif | 15619 |
90 | unsigned | 15532 |
91 | long | 15313 |
92 | udf | 15279 |
93 | at | 15106 |
94 | ctx | 14984 |
95 | State | 14939 |
96 | Info | 14749 |
97 | If | 14680 |
98 | block | 14453 |
99 | false | 14434 |
100 | used | 14247 |