hanlp源码解读之字符正规化CharTable
来源:互联网 发布:京东12g数据库网盘 编辑:程序博客网 时间:2024/06/03 04:05
概述:字符正规化是指在分词之前把繁体转成简体、大写转成小写等,在自然语言处理中这是必不可以的一个步骤!在hanlp中的实现方法是基于词典的,也就是正规则字符对照表。就是“data/dictionary/other/CharTable.txt” 这个词典,打开后是下面这个样子的!
«=《「=“」=”『=‘』=’【=《〗="〝="〞="と=之ふ=子ル=儿ㄖ=日丟=丢
在java程序中如何实现呢,相信大部分人会想用到用HashMap缓存起来不就可以了吗!当然,这个方法是可行的,但是HashMap在数据量比较大时,时间复杂度是接近O(n)的。这也是为什么加载词典用trie树,而不是直接用HashMap的原因了,当然内存也是一个方面,本篇文章不会讨论!下面我们来看下hanlp代码里的具体实现。
在hanlp中,是采用一维数据实现的,下面一步步来看源码的实现!源码位于com.hankcs.hanlp.HanLP包下的CharTable类中,这个类主是要加把 CharTable.txt加载到一维数组中。为了方便阅读,下面直接在代码中加入注释!
在分词之前会首化调用正规化接口(在启用正规化的情况下)
public List<Term> seg(char[] text) { assert text != null; if (HanLP.Config.Normalization) { CharTable.normalization(text);//执行正规化 } return segSentence(text); }下面来看下CharTable.normalization(text);这个函数的实现:这个函数极其简单,就是对text中的每个字符查询一维数据COVERT,看到这里应该就能明白,正规化最重要的就是加载txt文件到CONVERT数组中
public static void normalization(char[] charArray) { assert charArray != null; for (int i = 0; i < charArray.length; i++) { charArray[i] = CONVERT[charArray[i]]; } }
/** * 字符正规化表 * @author hankcs */public class CharTable{ /** * 正规化使用的对应表 * 存储原理是CONVERT[line.charAt(0)] = CONVERT[line.charAt(2)]; * line.charAt(0)是词典中的源始字符(如①),line.charAt(2)是正规化后的字符(如一) * ①=一 * ②=二 * ④=四 * ⑤=伍 * 这样以来在正规化时直接 charArray[i] = CONVERT[charArray[i]];就可以了,时间复杂度是O(1) */ public static char[] CONVERT; static { long start = System.currentTimeMillis(); if (!load(HanLP.Config.CharTablePath))//通过static语句块加载词典,hanlp中所有的词典都是这种方法加载的 { logger.severe("字符正规化表加载失败"); System.exit(-1); } logger.info("字符正规化表加载成功:" + (System.currentTimeMillis() - start) + " ms"); } /** * 首先偿试加载CharTable.txt.bin序列化词典,首次编译好词典会序列化到CharTable.txt.bin中 * 如果CharTable.txt.bin不存在,则加载CharTable.txt文件 * 对于这个词典来说加载CharTable.txt.bin和CharTable.txt在效率上基本上是没有区别的,因为不存在编译的过程 * 便CoreNatureDictionary.txt这类词典因为要编译成trie树,是需要一定时间的 * @param path * @return */ private static boolean load(String path) { String binPath = path + Predefine.BIN_EXT; if (loadBin(binPath)) return true;//二进制的词典存在直接读入到CONVERT数组中即可 CONVERT = new char[Character.MAX_VALUE + 1]; for (int i = 0; i < CONVERT.length; i++)//这个循环用来初始化数组,避免在使用时出现null的情况 { CONVERT[i] = (char) i; } IOUtil.LineIterator iterator = new IOUtil.LineIterator(path);//读入txt对照表 while (iterator.hasNext()) { String line = iterator.next(); if (line == null) return false; if (line.length() != 3) continue; CONVERT[line.charAt(0)] = CONVERT[line.charAt(2)];//这个其实就是正规化时的对照表,虽然简单的一条语句就实现了, 但是这种思考问题的方式和编码风格还是非常值和得学习的 } logger.info("正在缓存字符正规化表到" + binPath); IOUtil.saveObjectTo(CONVERT, binPath); return true; } /** * 这个函数主要用来加载.bin对照表到CONVERT数组中 * @param path * @return */ private static boolean loadBin(String path) { try { ObjectInputStream in = new ObjectInputStream(IOUtil.newInputStream(path)); CONVERT = (char[]) in.readObject(); in.close(); } catch (Exception e) { logger.warning("字符正规化表缓存加载失败,原因如下:" + e); return false; } return true; } /** * 将一个字符正规化 * @param c 字符 * @return 正规化后的字符 */ public static char convert(char c) { return CONVERT[c]; } public static char[] convert(char[] charArray) { char[] result = new char[charArray.length]; for (int i = 0; i < charArray.length; i++) { result[i] = CONVERT[charArray[i]]; } return result; } public static String convert(String charArray) { assert charArray != null; char[] result = new char[charArray.length()]; for (int i = 0; i < charArray.length(); i++) { result[i] = CONVERT[charArray.charAt(i)]; } return new String(result); } /** * 正规化一些字符(原地正规化) * @param charArray 字符 */ public static void normalization(char[] charArray) { assert charArray != null; for (int i = 0; i < charArray.length; i++) { charArray[i] = CONVERT[charArray[i]]; } }}
阅读全文
1 0
- hanlp源码解读之字符正规化CharTable
- hanlp源码解析之中文分词算法
- 源码解读之Intent解读
- 源码解读----之-----KMeans
- JBPM源码解读之:Fork
- postgres 源码解读之 toast
- nodeJS之eventproxy源码解读
- java源码解读之Vector
- java源码解读之stack
- Netty源码解读之线程
- JDK源码解读之RegularEnumSet
- Netty源码解读之线程
- Opencv 源码解读之 ImageEncoder
- 解读SDWebImage源码之UIImageView
- RxJava之just源码解读
- SDWebImage源码解读 之SDWebImageCompat
- SDWebImage源码解读 之SDWebImageDecoder
- SDWebImage源码解读 之SDWebImageDownloaderOperation
- 隐式游标属性
- 优秀的工程师更加注重基础-UIbutton
- 切域后台进行的批量账号和组导入导出
- 几种常用的版本控制系统优缺点比较
- 欢迎使用CSDN-markdown编辑器
- hanlp源码解读之字符正规化CharTable
- php修改网站默认编码
- python pandas to_sql 中文乱码问题
- HDU 5514 Frogs 【容斥原理】
- 面向过程与面向对象
- genymotion模拟器 安装使用
- 深入理解Android Handler 消息机制
- java生成word的几种方案
- C语言经典算法87-94