【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)

一、前言

本次学习应用于文本处理方面,前面我们说到实现统计不同种类的字符频率,本次目的是为了实现查询指定字词或统计全文字频

在上一篇博客中我们讲到了正则表达式的实际应用。

在这里我们将要与数据打交道,所以我们将要学习JAVA中的“容器”(其中的Map接口)。

二、分析学习(Map接口)

1)介绍和引入

现实生活中,我们经常需要成对存储某些信息。比如,我们使用的微信,一个手机号只能对应一个微信账户。这就是一种成对存储的关系。

Map就是用来存储“键(key)-值(value) 对”的。 Map类中存储的“键值对”通过键来标识,所以“键对象”不能重复。

Map 接口的实现类有HashMapTreeMapHashTableProperties等。

  • 常用方法: 【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第1张图片

2)特点和区别

HashTable类HashMap用法几乎一样,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低

HashMap与HashTable的区别

  1. HashMap: 线程不安全,效率高。允许key或value为null。

  2. HashTable: 线程安全,效率低。不允许key或value为null。

TreeMap是红黑二叉树的典型实现。 TreeMap的put()/remove()方法大量使用了红黑树的理论。

TreeMap和HashMap实现了同样的接口Map,因此,用法对于调用者来说没有区别。HashMap效率于TreeMap;在需要排序的Map时才选用TreeMap

三、编程学习

1)任务要求

  • 完成一个 java application应用程序,实现文本文档的读取和写入,将修改后(查询指定字词或统计全文字频)的新内容存入到新的文本文档中。
  • 应用数据流的相关知识,使用BufferedReader/BufferedWriter处理流:将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。使用InputStreamReader/OutputStreamWriter处理流:将字节流对象转化成字符流对象。
  • 应用JAVA“容器”中的HashMap的知识进行字频查询和统计

2)程序代码

/* 项目名称:Task_Shao
 * 创建时间:2019年2月21日
 * 创建者:Administrator_wz
 * 创建地点:kmust
 * 功能:文本处理中的特定字频统计(java 排序容器HashMap统计方法)
 */
import java.io.*;//导入java.io包中的所有类
import java.util.*;//导入java.util包中的所有类
import java.util.regex.Matcher;//导入java.util包中的Matcher类
import java.util.regex.Pattern;//导入java.util包中的Pattern类
public class character_frequency_statistics {//创建类名
	public static void main(String[] args) throws IOException {	//程序的主函数入口	
		long startTime=System.currentTimeMillis();//定义开始时间,用于统计程序的运行时长
		try{//用try-catch语句将逻辑语句包起来,并读取指定的文件
        	Scanner s1 = new Scanner(System.in);//获取键盘输入并赋值给s1字符串
        	System.out.println("请输入想要打开的文本文档:");//输入提示信息
        	String a = s1.nextLine();//定义字符串变量,并赋值为用户输入的信息
			InputStreamReader isr = new InputStreamReader(new FileInputStream(a),"utf-8"); //指定文件格式为utf-8
			BufferedReader br = new BufferedReader(isr);//用于读取指定文件
			StringBuffer c = new StringBuffer();//定义
			Scanner s2 = new Scanner(System.in);//获取键盘输入并赋值给s2字符串
			System.out.println("请选择是否单个字符(串)查询:确定(1)/拒绝(2)");//提示选择查询方式
			int b = s2.nextInt();//定义一个int类型变量,选择查询方式
			switch(b){//查询方式类
				case 1://查询类型1,单字符查询
					Scanner s3 = new Scanner(System.in);//获取键盘输入并赋值给s3字符串
					System.out.println("请输入想要查询的字符(串):");//输入提示信息
					String d = s3.nextLine();//定义字符串变量,并赋值为用户输入的信息
					String str1 = null;//定义一个字符串类型变量str1
					int n1 = 0;  //定义一个int类型变量n1     
					while((str1=br.readLine())!=null){//readLine()方法, 用于读取一行,只要读取内容不为空就一直执行
					c.append(str1);//添加进字符串c
					}  
					Pattern p = Pattern.compile(d);//创建正则表达式
					Matcher m = p.matcher(c);//创建合适的匹配器
					while(m.find()) {//匹配函数,true时执行
					n1++;//数值加1
					}
					br.close();//关闭数据流
					System.out.println("该字符(串)在文本中出现了"+n1+"次");//输出总的出现次数
					//System.out.println("测试1");//测试1
					break;
				case 2://查询类型2,文本统计并写出
					Scanner s4 = new Scanner(System.in);//获取键盘输入并赋值给s4字符串
					System.out.println("请输入想要写入内容的文本文档:");//输入提示信息
					String e = s4.nextLine();//定义字符串变量,并赋值为用户输入的信息
					File file=new File(e);;//写入待写入文件	
					if(!file.exists()) {//if语句的条件,若指定路径下该文件不存在
						file.createNewFile();//则在指定路径下新建该文件
					}
					int i = 0;//定义一个int类型变量i
					String str2 = null;//定义一个字符串类型变量
					while((str2 = br.readLine()) != null) {//readLine()方法, 用于读取一行,只要读取内容不为空就一直执行
						c.append(str2);//将该行内容追加到字符串b的后面
					}
					HashMap<Character,Integer>map =Count(c.toString());//调用HashMap函数
					PrintStream out = new PrintStream(file);//输出并存储
					System.setOut(out);//改变输出流并将内容保存到指定路径
					System.out.println("汉字统计结果:"+map);//输出结果
					Iterator<Integer>it = map.values().iterator();//获取tm中values值并迭代
					while(it.hasNext()) {//检查序列中是否含有元素,若有则为true
						Integer j=(Integer)it.next();//定义变量获取元素
						i+=j;//迭代求总字符数
					}
					br.close();//关闭数据流	
					System.out.println("总汉字数为"+i);//输出总的汉字数					
					//System.out.println("测试2");//测试2
					break;
				default:
					System.out.println("该字符(串)有误");//输出错误提示
					break;
				}
			}catch(Exception e){//当代码异常时用catch捕获异常
			e.printStackTrace();//printStackTrace()方法是打印异常信息在程序中出错的位置及原因
		}
		long endTime=System.currentTimeMillis();//定义一个结束时间
		long Time=endTime-startTime;//所需时间为结束时间-开始时间
		System.out.println("耗时:"+Time+"毫秒");//输出所用时间
		}
	public static HashMap<Character,Integer>Count(String str) {//构造TreeMap统计方法
		//String t = null;//定义一个字符串类型变量
		char charArray[]  = str.toCharArray();//将字符串转换为字符数组		
		HashMap<Character,Integer> map = new HashMap<Character,Integer>();//定义一个HashMap集合	
		for(int x = 0;x < charArray.length;x++) {//循环遍历字符数组
		String t=Character.toString(charArray[x]);//返回一个字符串对象	
			if (t.matches("[\\u4e00-\\u9fa5]")) {//if语句的条件,判断是否为汉字
				if(!map.containsKey(charArray[x])) {//if语句的条件,判断该汉字是否在 map中
					map.put(charArray[x], 1);//若该汉字不在 map中则初始化其value值为1
				} else {//若该汉字在tem中
					int count = map.get(charArray[x])+1;//其出现次数增加1
				    map.put(charArray[x],count);//若汉字在 map中则其value值为count
			    }
			}
		}
		return map;//返回map
	}
}

3)执行结果(以西游记文本为例)

另:demo1.txt文件是测试文件,xiyouji.txt文件为最终实现文件。
【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第2张图片

【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第3张图片

【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第4张图片

【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第5张图片
【JAVA】文本处理(4)—文本处理中的字频统计(查询指定字词或统计全文字频)_第6张图片

四、总结

HashMap底层实现采用了哈希表,这是一种非常重要的数据结构。对于我们以后理解很多技术都非常有帮助(比如:redis数据库的核心技术和HashMap一样),因此,非常有必要让大家理解。

数据结构中由数组和链表来实现对数据的存储,他们各有特点。

(1) 数组:占用空间连续。 寻址容易,查询速度快。但是,增加和删除效率非常低。

(2) 链表:占用空间不连续。 寻址困难,查询速度慢。但是,增加和删除效率非常高。

那么,我们能不能结合数组和链表的优点(即查询快,增删效率也高)呢? 答案就是“哈希表”。 哈希表的本质就是“数组+链表”

总结存储数据过程:

当添加一个元素(key-value)时,首先计算key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素已经被放在数组同一位置了,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,就形成了链表,同一个链表上的Hash值是相同的,所以说数组存放的是链表。 JDK8中,当链表长度大于8时,链表就转换为红黑树,这样又大大提高了查找的效率。(仅限于了解)

总之,实现Map接口的类用来存储键(key)-值(value) 对。Map 接口的实现类有HashMapTreeMap等。Map类中存储的键-值对通过键来标识,所以键值不能重复。

参考链接:
https://blog.csdn.net/youyou_yo/article/details/49284169
https://blog.csdn.net/qq_36843413/article/details/81511998
https://blog.csdn.net/qq_35529801/article/details/78757280
https://blog.csdn.net/qq_34944851/article/details/52625607
https://blog.csdn.net/qingxili/article/details/44427449
https://blog.csdn.net/ahua001/article/details/81169960
https://blog.csdn.net/wyf2017/article/details/80256729
https://blog.csdn.net/u013838592/article/details/83419005
https://blog.csdn.net/haishu_zheng/article/details/50434157
https://blog.csdn.net/New_feature/article/details/78340875


你可能感兴趣的:(java,查询指定字词或统计全文字频,容器Map接口,HashMap和TreeMap,HashTable,红黑树和哈希表)