1. 前言
实现的功能是,记录四级试卷中所有单词出现频率,并将单词以频率高低的方式进行排序,当然不仅是试卷,其他的文章都可以
2. 思路
怎么使用Java记录一张四级卷子里中所有的单词呢
-
读取到文章所有的内容
-
区分单词与其他字符,用
map
将单词与出现次数建立映射 -
将
map
排序
3. 实现
3.1 读取文章所有内容
首先在网上下载四级卷子的word版,将其内容复制到txt文本
中,我们使用Java读取这个txt文本
里的所有内容
使用的是Java 7
中新增的NIO
包中的Files
类和Path
类来读取文件,非常方便,确保JDK版本在1.7以上
// 参数填上需要读取文件的路径
Path path = Paths.get("D:\code\words\2015年6月.txt");
BufferedReader br = Files.newBufferedReader(path);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
3.2 区分单词与其他字符,用map将单词与出现次数建立映射
一开始想使用正则的方法来将单词拆分,但发现会比较麻烦,因为单词拆分原则比较多,有空格,有括号,引号以及句号等等
还有一个重要原因是因为,我想把单词第一个大写的字母转换为小写,这样在统计频率的时候,会更加利于我们操作
所以采用了下面的方法
while ((line = br.readLine()) != null) {
StringBuilder word = new StringBuilder();
for (int j = 0; j < line.length(); j++) {
char ch =line.charAt(j);
if (ch >= 'a' && ch <= 'z') {
word.append(ch);
} else if (ch >= 'A' && ch <= 'Z') { // 如果单词是大写,把它转换为小写形式,方便统计次数
word.append((char) (ch + 32));
} else if (word.toString().length() > 1) {// 如果遇到不是单词的字符,而且单词不是一个字母
String word_string = word.toString();
// 如果单词不存在, 将单词填入并初始化为1次
if (!map.containsKey(word_string)) {
map.put(word_string, 1);
} else {
// 如果单词存在,找到该单词对应的频率,将其加1,重新覆盖
map.put(word_string, map.get(word_string) + 1);
}
// 清空StringBuilder, 计入下个单词
word.setLength(0);
}
}
}
3.3 将map排序
用到Collections.sort()
方法和map的内部接口Map.Entry
Map.Entry
是map的一个内部接口,它表示map的一个实体(也就是一个key-value
对)
用以下方法可以实现,将Map按value以降序的方式排序
List<Map.Entry<String, Integer>> infoIds = new ArrayList<>(map.entrySet());
Collections.sort(infoIds, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
}
});
4. 代码
以下是实现的总代码,可计算多张卷子
package indi.zmj.corejava.bit;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
* @author zmj
* @create 2018/11/11
*/
public class splitWords {
public void readPapers(String[] url) throws IOException {
TreeMap<String, Integer> map = new TreeMap<>();
for (int i = 0; i < url.length; i++) {
Path path = Paths.get(url[i]);
BufferedReader br = Files.newBufferedReader(path);
String line = null;
// 读取文件中的每一行, 并用StringBuilder统计每个单词
while ((line = br.readLine()) != null) {
StringBuilder word = new StringBuilder();
for (int j = 0; j < line.length(); j++) {
char ch = line.charAt(j);
if (ch >= 'a' && ch <= 'z') {
word.append(ch);
} else if (ch >= 'A' && ch <= 'Z') {
// 如果单词是大写,把它转换为小写形式,方便统计次数
word.append((char) (ch + 32));
} else if (word.toString().length() > 1) {
String word_string = word.toString();
// 如果单词不存在, 将单词填入并初始化为1次
if (!map.containsKey(word_string)) {
map.put(word_string, 1);
} else {
// 如果单词存在,找到该单词对应的频率,将其加1,重新覆盖
map.put(word_string, map.get(word_string) + 1);
}
// 清空StringBuilder, 计入下个单词
word.setLength(0);
}
}
}
br.close();
}
List<Map.Entry<String, Integer>> infoIds = new ArrayList<>(map.entrySet());
Collections.sort(infoIds, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
}
});
for (int i = 0; i < infoIds.size(); i++) {
System.out.printf("单词:%12s 出现了:%d次\n", infoIds.get(i).getKey(), infoIds.get(i).getValue());
}
}
public static void main(String[] args) throws IOException {
String[] url = {"D:\\code\\words\\2015年6月.txt", "D:\\code\\words\\2015年12月.txt"
, "D:\\code\\words\\2016年6月.txt", "D:\\code\\words\\2016年12月.txt",
"D:\\code\\words\\2017年12月.txt", "D:\\code\\words\\2018年6月.txt"};
new splitWords().readPapers(url);
}
}
5. 效果图
截取了其中一部分效果