当前位置:首页 > 后端开发 > 正文内容

java 完成中英文拼写查看和过错纠正?可我只会写 CRUD 啊!

邻居的猫1个月前 (12-09)后端开发1760

拼写纠正系列

NLP 中文拼写检测完成思路

NLP 中文拼写检测纠正算法收拾

NLP 英文拼写算法,假如提高 100W 倍的功用?

NLP 中文拼写检测纠正 Paper

java 完成中英文拼写查看和过错纠正?可我只会写 CRUD 啊!

一个提高英文单词拼写检测功用 1000 倍的算法?

单词拼写纠正-03-leetcode edit-distance 72.力扣修改间隔

开源项目

nlp-hanzi-similar 汉字相似度

word-checker 拼写检测

sensitive-word 灵敏词

简略的需求

接近下班,小明忙完了今日的使命,正准备下班回家。

一条音讯闪耀了起来。

“最近发现大众号的拼写查看功用不错,协助用户发现错别字,体会不错。给咱们体系也做一个。”

看着这条音讯,小明在心里静静问好了一句。

“我 TND 的会做这个,就直接去人家总部上班了,在这受你的气。”

“好的”,小明回复到,“我先看看”

今日,天王老子来了我也得下班,耶稣也留不住。

耶稣也留不住

小明想着,就回家了。

镇定剖析

提到这个拼写查看,小明其实是知道的。

自己没吃过猪肉,仍是见过猪跑的。

平常看过一些大众号大佬共享,说是大众号推出了拼写查看功用,今后再也不会有错别字了。

后来,小明仍是在他们的文章中看到了不少错别字。后来,就没有后来了。

为什么不去问一问全能的 github 呢?

小明打开了 github 发现如同没有老练的 java 相关的开源项目,有的几颗星,用起来不太定心。

估量 NLP 是搞 python 的比较多吧,java 完成中英文拼写查看和过错纠正?可我只会写 CRUD 啊!

小明静静地址起了一根华子……

窗外的夜色如水,不由陷入了深思,我来自何方?去往何处?人生的含义又是什么?

哲学三问

尚有余热的烟灰落在了小明某东买的拖鞋上,把他脑海中脱缰的野马烫的一机伶。

没有任何思路,没有任何条理,仍是先洗洗睡吧。

那一夜,小明做了一个长长的美梦。梦里没有任何的错别字,一切的字句都坐落在正确的方位上……

起色

第二天,小明打开了查找框,输入 spelling correct。

可喜的是,找到了一篇英文拼写纠正算法解说。

吾尝整天而思矣,不如顷刻之所学也。小明叹了一句,就看了起来。

算法思路

英文单词首要有 26 个英文字母组成,所以拼写的时分或许呈现过错。

首要能够获取正确的英文单词,节选如下:

apple,16192
applecart,41
applecarts,1
appledrain,1
appledrains,1
applejack,571
applejacks,4
appleringie,1
appleringies,1
apples,5914
applesauce,378
applesauces,1
applet,2

每一行用逗号分隔,后边是这个单词呈现的频率。

以用户输入 appl 的为例,假如这个单词不存在,则能够对其进行 insert/delete/replace 等操作,找到最接近的单词。(本质上便是找到修改间隔最小的单词)

假如输入的单词存在,则阐明正确,不必处理。

英文单词

词库的获取

那么英文词库去哪里取得呢?

小明想了想,所以去各个当地查了一圈,最终找到了一个比较完善的英文单词频率词库,合计 27W+ 的单词。

节选如下:

aa,1831
aah,45774
aahed,1
aahing,30
aahs,23
...
zythums,1
zyzzyva,2
zyzzyvas,1
zzz,76
zzzs,2

中心代码

获取用户当时输入的一切或许状况,中心代码如下:

/**
 * 构建出当时单词的一切或许过错状况
 *
 * @param word 输入单词
 * @return 回来成果
 * @since 0.0.1
 * @author 老马啸西风
 */
private List<String> edits(String word) {
    List<String> result = new LinkedList<>();
    for (int i = 0; i < word.length(); ++i) {
        result.add(word.substring(0, i) + word.substring(i + 1));
    }
    for (int i = 0; i < word.length() - 1; ++i) {
        result.add(word.substring(0, i) + word.substring(i + 1, i + 2) + word.substring(i, i + 1) + word.substring(i + 2));
    }
    for (int i = 0; i < word.length(); ++i) {
        for (char c = 'a'; c <= 'z'; ++c) {
            result.add(word.substring(0, i) + c + word.substring(i + 1));
        }
    }
    for (int i = 0; i <= word.length(); ++i) {
        for (char c = 'a'; c <= 'z'; ++c) {
            result.add(word.substring(0, i) + c + word.substring(i));
        }
    }
    return result;
}

然后和词库中正确的单词进行比照:

List<String> options = edits(formatWord);
List<CandidateDto> candidateDtos = new LinkedList<>();
for (String option : options) {
    if (wordDataMap.containsKey(option)) {
        CandidateDto dto = CandidateDto.builder()
                .word(option).count(wordDataMap.get(option)).build();
        candidateDtos.add(dto);
    }
}

最终回来的成果,需求依据单词呈现的频率进行比照,全体来说仍是比较简略的。

中文拼写

失之毫厘

中文的拼写初看起来和英文差不多,可是中文有个很特别的当地。

由于一切的汉字拼写自身都是固定的,用户在输入的时分不存在错字,只存在别字。

独自说一个字是别字是毫无含义的,有必要要有词,或许上下文。

这一点就让纠正的难度上升了许多。

小明无法的摇了摇头,中华文化,博学多才。

算法思路

针对中文别字的纠正,办法比较多:

(1)困惑集。

比方常用的别字,万变不离其宗 错写为 万变不离其间

(2)N-Gram

也便是一次字对应的上下文,运用比较广泛的是 2-gram。对应的语料,sougou 实验室是有的。

也便是当榜首个词固定,第2次呈现的会有对应的概率,概率越高的,必定越或许是用户原意想要输入的。

比方 跑的飞快,实践上 跑地飞快 或许才是正确的。

纠错

当然,中文还有一个难点便是,无法直接经过 insert/delete/replace 把一个字变成另一个字。

不过相似的,仍是有许多办法:

(1)同音字/谐音字

(2)形近字

(3)近义词

(4)字词乱序、字词增删

中文

算法完成

迫于完成的难度,小明挑选了最简略的困惑集。

首要找到常见别字的字典,节选如下:

一丘之鹤 一路货色
一依旧惯 一依旧贯
一付中药 一服中药
...
黯然消魂 黯然销魂
鼎峙相助 鼎力相助
鼓躁而进 鼓噪而进
龙盘虎据 龙盘虎踞

前面的是别字,后边的是正确用法。

以别字作为字典,然后对中文文本进行 fast-forward 分词,获取对应的正确方式。

当然一开端咱们能够简略点,让用户固定输入一个词组,完成便是直接解析对应的 map 即可

public List<String> correctList(String word, int limit, IWordCheckerContext context) {
    final Map<String, List<String>> wordData = context.wordData().correctData();
    // 判别是否过错
    if(isCorrect(word, context)) {
        return Collections.singletonList(word);
    }
    List<String> allList = wordData.get(word);
    final int minLimit = Math.min(allList.size(), limit);
    List<String> resultList = Guavas.newArrayList(minLimit);
    for(int i = 0; i < minLimit; i++) {
        resultList.add(allList.get(i));
    }
    return resultList;
}

中英文混合长文本

算法思路

实践的文章,一般是中英文混合的。

要想让用户运用起来愈加便利,必定不能每次只输入一个词组。

那要怎么办呢?

答案是分词,把输入的语句,分词为一个个词。然后区别中英文,进行对应的处理。

关于分词,引荐开源项目:

https://github.com/houbb/segment

算法完成

批改的中心算法,能够复用中英文的完成。

@Override
public String correct(String text) {
    if(StringUtil.isEnglish(text)) {
        return text;
    }

    StringBuilder stringBuilder = new StringBuilder();
    final IWordCheckerContext zhContext = buildChineseContext();
    final IWordCheckerContext enContext = buildEnglishContext();

    // 榜首步履行分词
    List<String> segments = commonSegment.segment(text);
    // 悉数为真,才认为是正确。
    for(String segment : segments) {
        // 假如是英文
        if(StringUtil.isEnglish(segment)) {
            String correct = enWordChecker.correct(segment, enContext);
            stringBuilder.append(correct);
        } else if(StringUtil.isChinese(segment)) {
            String correct = zhWordChecker.correct(segment, zhContext);
            stringBuilder.append(correct);
        } else {
            // 其他疏忽
            stringBuilder.append(segment);
        }
    }

    return stringBuilder.toString();
}

其间分词的默许完成如下:

import com.github.houbb.heaven.util.util.CollectionUtil;
import com.github.houbb.nlp.common.segment.ICommonSegment;
import com.github.houbb.nlp.common.segment.impl.CommonSegments;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 默许的混合分词,支撑中文和英文。
 *
 * @author binbin.hou
 * @since 0.0.8
 */
public class DefaultSegment implements ICommonSegment {

    @Override
    public List<String> segment(String s) {
        //依据空格分隔
        List<String> strings = CommonSegments.defaults().segment(s);
        if(CollectionUtil.isEmpty(strings)) {
            return Collections.emptyList();
        }

        List<String> results = new ArrayList<>();
        ICommonSegment chineseSegment = InnerCommonSegments.defaultChinese();
        for(String text : strings) {
            // 进行中文分词
            List<String> segments = chineseSegment.segment(text);

            results.addAll(segments);
        }


        return results;
    }

}

首要是针对空格进行分词,然后对中文以困惑集的别字做 fast-forward 分词。

当然,这些说起来也不难。

真的完成起来仍是比较费事的,小明把完好的完成现已开源:

https://github.com/houbb/word-checker

觉得有协助的小伙伴能够 fork/star 一波~

快速开端

word-checker 用于单词拼写查看。支撑英文单词拼写检测,和中文拼写检测。

话不多说,咱们来直接体会一下这个东西类的运用体会。

特性阐明

  • 能够敏捷判别当时单词是否拼写过错

  • 能够回来最佳匹配成果

  • 能够回来纠正匹配列表,支撑指定回来列表的巨细

  • 过错提示支撑 i18n

  • 支撑巨细写、全角半角格局化处理

  • 支撑自定义词库

  • 内置 27W+ 的英文词库

  • 支撑根本的中文拼写检测

快速开端

maven 引进

<dependency>
     <groupId>com.github.houbb</groupId>
     <artifactId>word-checker</artifactId>
    <version>1.2.0</version>
</dependency>

测验事例

会依据输入,主动回来最佳纠正成果。

final String speling = "speling";
Assert.assertEquals("spelling", EnWordCheckers.correct(speling));

中心 api 介绍

中心 api 在 EnWordCheckers 东西类下。

功用 办法 参数 回来值 补白
判别单词拼写是否正确 isCorrect(string) 待检测的单词 boolean
回来最佳纠正成果 correct(string) 待检测的单词 String 假如没有找到能够纠正的单词,则回来其自身
判别单词拼写是否正确 correctList(string) 待检测的单词 List<String> 回来一切匹配的纠正列表
判别单词拼写是否正确 correctList(string, int limit) 待检测的单词, 回来列表的巨细 回来指定巨细的的纠正列表 列表巨细 <= limit

测验比如

拜见 EnWordCheckerTest.java

是否拼写正确

final String hello = "hello";
final String speling = "speling";
Assert.assertTrue(EnWordCheckers.isCorrect(hello));
Assert.assertFalse(EnWordCheckers.isCorrect(speling));

回来最佳匹配成果

final String hello = "hello";
final String speling = "speling";
Assert.assertEquals("hello", EnWordCheckers.correct(hello));
Assert.assertEquals("spelling", EnWordCheckers.correct(speling));

默许纠正匹配列表

final String word = "goox";
List<String> stringList = EnWordCheckers.correctList(word);
Assert.assertEquals("[good, goo, goon, goof, gook, goop, goos, gox, goog, gool, goor]", stringList.toString());

指定纠正匹配列表巨细

final String word = "goox";
final int limit = 2;
List<String> stringList = EnWordCheckers.correctList(word, limit);
Assert.assertEquals("[good, goo]", stringList.toString());

中文拼写纠正

中心 api

为下降学习本钱,中心 api 和 ZhWordCheckers 中,和英文拼写检测保持一致。

是否拼写正确

final String right = "正确";
final String error = "万变不离其间";

Assert.assertTrue(ZhWordCheckers.isCorrect(right));
Assert.assertFalse(ZhWordCheckers.isCorrect(error));

回来最佳匹配成果

final String right = "正确";
final String error = "万变不离其间";

Assert.assertEquals("正确", ZhWordCheckers.correct(right));
Assert.assertEquals("万变不离其宗", ZhWordCheckers.correct(error));

默许纠正匹配列表

final String word = "万变不离其间";

List<String> stringList = ZhWordCheckers.correctList(word);
Assert.assertEquals("[万变不离其宗]", stringList.toString());

指定纠正匹配列表巨细

final String word = "万变不离其间";
final int limit = 1;

List<String> stringList = ZhWordCheckers.correctList(word, limit);
Assert.assertEquals("[万变不离其宗]", stringList.toString());

长文本中英文混合

情形

实践拼写纠正的话,最佳的运用体会是用户输入一个长文本,而且或许是中英文混合的。

然后完成上述对应的功用。

中心办法

WordCheckers 东西类供给了长文本中英文混合的主动纠正功用。

功用 办法 参数 回来值 补白
文本拼写是否正确 isCorrect(string) 待检测的文本 boolean 悉数正确,才会回来 true
回来最佳纠正成果 correct(string) 待检测的单词 String 假如没有找到能够纠正的文本,则回来其自身
判别文本拼写是否正确 correctMap(string) 待检测的单词 Map<String, List<String>> 回来一切匹配的纠正列表
判别文本拼写是否正确 correctMap(string, int limit) 待检测的文本, 回来列表的巨细 回来指定巨细的的纠正列表 列表巨细 <= limit

拼写是否正确

final String hello = "hello 你好";
final String speling = "speling 你好 以毒功毒";
Assert.assertTrue(WordCheckers.isCorrect(hello));
Assert.assertFalse(WordCheckers.isCorrect(speling));

回来最佳纠正成果

final String hello = "hello 你好";
final String speling = "speling 你好以毒功毒";
Assert.assertEquals("hello 你好", WordCheckers.correct(hello));
Assert.assertEquals("spelling 你好以毒攻毒", WordCheckers.correct(speling));

判别文本拼写是否正确

每一个词,对应的纠正成果。

final String hello = "hello 你好";
final String speling = "speling 你好以毒功毒";
Assert.assertEquals("{hello=[hello],  =[ ], 你=[你], 好=[好]}", WordCheckers.correctMap(hello).toString());
Assert.assertEquals("{ =[ ], speling=[spelling, spewing, sperling, seeling, spieling, spiling, speeling, speiling, spelding], 你=[你], 好=[好], 以毒功毒=[以毒攻毒]}", WordCheckers.correctMap(speling).toString());

判别文本拼写是否正确

同上,指定最多回来的个数。

final String hello = "hello 你好";
final String speling = "speling 你好以毒功毒";

Assert.assertEquals("{hello=[hello],  =[ ], 你=[你], 好=[好]}", WordCheckers.correctMap(hello, 2).toString());
Assert.assertEquals("{ =[ ], speling=[spelling, spewing], 你=[你], 好=[好], 以毒功毒=[以毒攻毒]}", WordCheckers.correctMap(speling, 2).toString());

格局化处理

有时分用户的输入是林林总总的,本东西支撑关于格局化的处理。

巨细写

大写会被一致格局化为小写。

final String word = "stRing";

Assert.assertTrue(EnWordCheckers.isCorrect(word));

全角半角

全角会被一致格局化为半角。

final String word = "string";

Assert.assertTrue(EnWordCheckers.isCorrect(word));

自定义英文词库

文件装备

你能够在项目资源目录创立文件 resources/data/define_word_checker_en.txt

内容如下:

my-long-long-define-word,2
my-long-long-define-word-two

不同的词独立一行。

每一行榜首列代表单词,第二列代表呈现的次数,二者用逗号 , 离隔。

次数越大,在纠正的时分回来优先级就越高,默许值为 1。

用户自定义的词库优先级高于体系内置词库。

测验代码

咱们在指定了对应的单词之后,拼写检测的时分就会收效。

final String word = "my-long-long-define-word";
final String word2 = "my-long-long-define-word-two";

Assert.assertTrue(EnWordCheckers.isCorrect(word));
Assert.assertTrue(EnWordCheckers.isCorrect(word2));

自定义中文词库

文件装备

你能够在项目资源目录创立文件 resources/data/define_word_checker_zh.txt

内容如下:

默守陈规 墨守陈规

运用英文空格分隔,前面是过错,后边是正确。

小结

中英文拼写的纠正一直是比较抢手,也比较难的论题。

近些年,由于 NLP 和人工智能的前进,在商业上的使用也逐步成功。

本次首要完成是根据传统的算法,中心在词库。

后续

在阅历了几天的尽力之后,小明总算完成了一个最简略的拼写查看东西。

“前次和我说的大众号的拼写查看功用还要吗?”

“不要了,你不说我都忘记了。”,产品显得有些惊奇。"那个需求做不做也无所谓,咱们最近揉捏了一堆事务需求,你优先看看。"

“……”

"我最近又看到 xxx 上有一个功用也十分不错,你给咱们体系也做一个。"

“……”

扫描二维码推送至手机访问。

版权声明:本文由51Blog发布,如需转载请注明出处。

本文链接:https://www.51blog.vip/?id=137

分享给朋友:

“java 完成中英文拼写查看和过错纠正?可我只会写 CRUD 啊!” 的相关文章

【日记】差点把工装玩儿丢了(863 字)

【日记】差点把工装玩儿丢了(863 字)

正文   今日好大的妖风。正午外面吹得旗杆猎猎作响。吃饭的时分还能看到漫天的絮。尽管我也不清楚那究竟是什么……   上个周末差点把工装玩儿没了。昨日晚上临睡觉,处处找我那个西装外套,找不到。想了一下,应该没有落在体检中心,应该也没落在饭馆等等其他当地,横竖必定内行里。便是找不到。抛弃了。你死我活,想...

shell (3)脚本参数传递与数学运算

shell (3)脚本参数传递与数学运算

🌟声明🌟 红客全栈教程 学习视频来自UP 泷羽sec,如涉及侵权马上删除文章 以下只涉及学习内容,其他都与本人无关,切莫逾越法律红线,否则后果自负。 星河飞雪网络安全人才培养计划,绝对零区,公益免费教学!没有网络安全,就没有国家安全! 脚本参数如何传递? echo 执行的文件名是:$0 echo...

Python网址,python官网免费下载

Python网址,python官网免费下载

以下是关于Python的一些重要网址信息,包括官方网站、教程网站和社区网站: Python 官方网站 Python 官方网站: 提供Python源代码和安装程序下载,最新版本为Python 3.13.1。 包含Python标准库的文档、教程和指南,可以在线获取。 Python 教程网站 Py...

r语言聚类分析,方法、实例与技巧

1. Kmeans聚类:Kmeans是最常用的聚类算法之一,它将数据点分为K个簇,其中K是用户指定的。Kmeans的目标是最小化簇内数据点与簇中心之间的距离。2. 层次聚类:层次聚类是一种将数据点逐层合并或分裂的聚类方法。它构建一个树状结构,称为聚类树或树状图,用于表示数据点之间的相似性。3. 密度...

java算法,基础概念与常用算法解析

java算法,基础概念与常用算法解析

Java是一种广泛使用的高级编程语言,用于开发各种应用程序,包括桌面应用程序、Web应用程序、移动应用程序和游戏等。在Java中实现算法时,通常需要遵循一定的步骤和最佳实践,以确保代码的效率、可读性和可维护性。1. 理解算法:在开始编码之前,确保你完全理解了算法的工作原理。这包括理解算法的输入、输出...

go反编译, Android应用软件游戏汉化概述

go反编译, Android应用软件游戏汉化概述

Go语言的反编译通常是指将Go语言的编译后的二进制文件转换回Go源代码的过程。Go语言的二进制文件并不包含原始源代码的足够信息,这使得完全准确的反编译变得非常困难。尽管如此,还是有一些工具和技术可以尝试从Go的二进制文件中提取出有用的信息。 常用的Go反编译工具1. Gobuster:一个用于暴力破...