NLP 开源形近字算法之相似字列表(番外篇)
创作目的
国内对于文本的相似度计算,开源的工具是比较丰富的。
但是对于两个汉字之间的相似度计算,国内基本一片空白。国内的参考的资料少的可怜,国外相关文档也是如此。
本项目旨在抛砖引玉,实现一个基本的相似度计算工具,为汉字 NLP 贡献一点绵薄之力。
推荐阅读:
开源项目在线化 中文繁简体转换/敏感词/拼音/分词/汉字相似度/markdown 目录

需求
有时候我们并不是需要返回两个字的相似,而是需要返回一个汉字的相似列表。
实现思路
我们可以分别计算所有的汉字之间的相似度,然后保留最大的前100个,放在字典中。
然后实时查询这个字典即可。
实现方式
bihuashu_2w.txt 中我们主要需要的是对应的 2W 常见汉字。
hanzi_similar_list.txt 用来存放汉字和相似字的映射关系。
数据初始化
public static void main(String[] args) {
final String path = "D:\\code\\coin\\nlp-hanzi-similar\\src\\main\\resources\\hanzi_similar_list.txt";
// 读取列表
List<String> lines = FileUtil.readAllLines("D:\\code\\coin\\nlp-hanzi-similar\\src\\main\\resources\\nlp\\bihuashu_2w.txt");
// 所有的单词
Set<String> allWordSet = new HashSet<>();
for(String line : lines) {
String word = line.split(" ")[0];
allWordSet.add(word);
}
// 循环对比
for(String word : allWordSet) {
List<String> list = getSimilarListData(word, allWordSet);
String line = word +" " + StringUtil.join(list, "");
FileUtil.append(path, line);
}
}
- 优先级队列取前 100 个
我们通过优先级队列存储:
private static List<String> getSimilarListData(String word, Set<String> wordSet) {
PriorityQueue<SimilarListDataItem> items = new PriorityQueue<>(new Comparator<SimilarListDataItem>() {
@Override
public int compare(SimilarListDataItem o1, SimilarListDataItem o2) {
// 相似度大的放在前面
return -o1.getRate().compareTo(o2.getRate());
}
});
for(String other : wordSet) {
if(word.equals(other)) {
continue;
}
// 对比
double rate = HanziSimilarHelper.similar(word.charAt(0), other.charAt(0));
SimilarListDataItem item = new SimilarListDataItem(other, rate);
items.add(item);
}
final int limit = 100;
List<String> wordList = new ArrayList<>();
for(SimilarListDataItem item : items) {
wordList.add(item.getWord());
if(wordList.size() >= limit) {
break;
}
}
return wordList;
}
相似字的获取
初始化好数据之后,一切就变得非常简单:
- 接口定义
/**
* 数据接口-相似列表
* @author binbin.hou
* @since 1.3.0
*/
public interface IHanziSimilarListData {
/**
* 返回数据信息
* @param word 单词
* @return 结果
* @since 1.3.0
*/
List<String> similarList(String word);
}
- 数据获取
public class HanziSimilarListData implements IHanziSimilarListData {
private static volatile Map<String, List<String>> map = Guavas.newHashMap();
@Override
public List<String> similarList(String word) {
if(MapUtil.isEmpty(map)) {
initDataMap();
}
return map.get(word);
}
private void initDataMap() {
if(MapUtil.isNotEmpty(map)) {
return;
}
//DLC
synchronized (map) {
if(MapUtil.isEmpty(map)) {
List<String> lines = StreamUtil.readAllLines("/hanzi_similar_list.txt");
for(String line : lines) {
String[] words = line.split(" ");
// 后面的100个相近词
List<String> list = StringUtil.toCharStringList(words[1]);
map.put(words[0], list);
}
}
}
}
}
便利性
为了用户使用方便,我们在 HanziSimilarHelper 中添加 2 个工具类方法:
/**
* 相似的列表
* @param hanziOne 汉字一
* @param limit 大小
* @return 结果
* @since 1.3.0
*/
public static List<String> similarList(char hanziOne, int limit) {
return HanziSimilarBs.newInstance().similarList(hanziOne, limit);
}
/**
* 相似的列表
* @param hanziOne 汉字一
* @return 结果
* @since 1.3.0
*/
public static List<String> similarList(char hanziOne) {
return similarList(hanziOne, 10);
}
测试效果
我们使用看一下效果:
我们来看一下【爱】的形近字。
List<String> list = HanziSimilarHelper.similarList('爱');
Assert.assertEquals("[爰, 爯, 受, 爭, 妥, 憂, 李, 爳, 叐, 雙]", list.toString());
开源地址
为了便于大家使用学习,项目已开源。
小结
一个字的形近字可以做很多有趣的事情,这个要看大家的想象力。
实现方式也不难,最核心的还是相似度的计算。
我是老马,期待与你的下次重逢。
NLP 开源形近字算法之相似字列表(番外篇)的更多相关文章
- NLP 开源形近字算法补完计划(完结篇)
前言 所有的故事都有开始,也终将结束. 本文将作为 NLP 汉字相似度的完结篇,为该系列画上一个句号. 起-NLP 中文形近字相似度计算思路 承-中文形近字相似度算法实现,为汉字 NLP 尽一点绵薄之 ...
- KMP算法番外篇--求解next数组
KMP算法实现字符串的模式匹配的时间复杂度比朴素的模式匹配好很多,但是它时间效率的提高是有前提的,那就是:模式串的重复率很高,不然它的效率也不会凸显出来.在实际的应用中,KMP算法不算是使用率很高的一 ...
- 数据结构和算法 – 番外篇.时间测试类Timing
public class Timing { //startingTime--用来存储正在测试的代码的开始时间. TimeSpan startingTime; //duration--用来存储正在测试的 ...
- CWMP开源代码研究番外篇——博通方案
声明:本篇文章来自于某公司Cable Modem产品的文档资料,源码来自于博通公司,只提供参考(为保护产权,本人没有源码). 前文曾提到会写一篇关于博通的tr069,那么福利来了.福利,福利,福利,重 ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记番外(1) - JLinkScript妙用
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记番外篇之JLinkScript妙用. JLinkScript 文件是配套 J-Link 调试器使用的脚本,这个脚本适 ...
- Java实现 蓝桥杯 算法提高 周期字串
算法提高 周期字串 时间限制:1.0s 内存限制:256.0MB 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些"从前有座山,山里有座庙,庙里有个老和尚给小和尚讲故事,讲的什么呢?从前有 ...
- zz【清华NLP】图神经网络GNN论文分门别类,16大应用200+篇论文最新推荐
[清华NLP]图神经网络GNN论文分门别类,16大应用200+篇论文最新推荐 图神经网络研究成为当前深度学习领域的热点.最近,清华大学NLP课题组Jie Zhou, Ganqu Cui, Zhengy ...
- Duang的成长——使用造字程序输入生僻字
使用造字程序输入生僻字 最近,一个字突然间火了起来,那就是——duang! (图片来自网络) 那么,问题来了!造字程序哪家强?(此处有掌声) 其实,微软早就考虑到各国文字的博大精深,在系统中集成了一个 ...
- 【开源.NET】轻量级内容管理框架Grissom.CMS(第三篇解析配置文件和数据以转换成 sql)
该篇是 Grissom.CMS 框架系列文章的第三篇, 主要介绍框架用到的核心库 EasyJsonToSql, 把标准的配置文件和数据结构解析成可执行的 sql. 该框架能实现自动化增删改查得益于 E ...
- 顶级开源项目 Sentry 20.x JS-SDK 设计艺术(Unified API篇)
SDK 开发 顶级开源项目 Sentry 20.x JS-SDK 设计艺术(理念与设计原则篇) 顶级开源项目 Sentry 20.x JS-SDK 设计艺术(开发基础篇) 顶级开源项目 Sentry ...
随机推荐
- 应用Sequelize创建项目
创建项目: 第一步:安装express-generator -g 第二步:安装ejs模板 express --view=ejs 项目名 第三步:安装依赖进入项目 npm i ------------ ...
- windows安装kafka
1.软件下载 kafka运行需要有jdk+zookeeper环境才能够使用,官网下载 https://www.apache.org/dyn/closer.cgi/zookeeper/ http://k ...
- 03php拉取服务器信息并生成json
<?php$servername = "服务器";$username = "用户名";$password = "密码";$dbname ...
- L0范式、L1范式、L2范式解释通俗版
L0范数是指向量中非0的元素的个数.(L0范数很难优化求解) L1范数是指向量中各个元素绝对值之和 L2范数是指向量各元素的平方和然后求平方根 L1范数可以进行特征选择,即让特征的系数变为0. L2范 ...
- 关于group by的一个问题
项目场景: 有时候,遇到数据库重复数据,需要将数据进行分组,并取出其中一条来展示,这时就需要用到group by语句.但是,如果mysql是高版本,当执行group by时,select的字段不属于g ...
- python发布定时任务(schedule模块)
最近公司开始让在自己开发的软件上写日志,有几次下班了都忘了写,好几次都是给领导发邮件,说明一下自己没有写日志这件事,很麻烦.但是我一想我每天都要写,岂不是很麻烦,想想自己之前有爬虫经验,为什么自己不写 ...
- XML_DOM4J_20200415
package com.wy.xml; import java.io.File;import java.util.Iterator; import org.dom4j.Attribute; impor ...
- drf认证与权限
1 认证 # 登录认证--->某个接口必须登录后才能房屋# 登录接口--->登录成功返回随机字符串--->携带随机字符串[认证] 通过,再继续访问某个接口# 读APIView源码时, ...
- ERR Client sent AUTH,but no password is set
问题产生原因: 就是Redis服务器没有设置密码,但客户端向其发送了AUTH(authentication,身份验证)请求携带着密码,导致报错. 既然是没有设置密码导致的报错,那我们就把Redis服务 ...
- [C#]Event相关的三个典型Case收录.
基本版: using System; namespace EventDemo1 { public delegate void CatCallEventHandler(); public class C ...