中英文用词拼写纠正方案

Updated on with 0 views and 0 comments

中英文用词拼写及语法纠正开源方案调研

需求概述

1.1 需求整理

调研方案主要满足以下需求:

    ○ 英文单词拼写检查


    ○ 英文语句语法检查


    ○ 中文词汇正确性检查


    ○ 中文语法正确性检查

功能范围

2.1 本次调研开源方案实现的功能

单词拼写/词汇使用语句语法
中文1. 是否拼写正确 2. 返回最佳纠正结果 3. 返回所有纠正结果列表 4. 自定义词库1. 语法修正原因 2. 语法修正结果 3. 是否有语法错误 4. 自定义纠错规则
英文1. 是否拼写正确 2. 返回最佳纠正结果 3. 返回所有纠正结果列表 4. 自定义词库1. 语法修正原因 2. 语法修正结果 3. 是否有语法错误 4. 自定义纠错规则
其他1. 中英文混合长文本分词纠错 2. 内置8W+英文词库,扩展需自定义增加基础语法包包含Chinese,English, English (US), English (GB), English (Australian), English (Canadian), English (New Zealand), English (South African),Italian,Polish等

2.2 本方案涉及的模块

模块包
单词拼写/词汇使用word-checker:0.1.0
语句语法● language-en:6.0 ● language-zh:6.0 ● languagetool-core:6.0

3. 模块功能展示及验证

根据实际输入输出结果展示word-checker的单词纠错能力以及languagetool的语法纠正能力

3.1 word-checker英文单词拼写检查

功能展示

word-checker英文单词拼写检查支持的使用方式如下:

核心 api 在 EnWordCheckers 工具类下。

功能方法参数返回值备注
判断单词拼写是否正确isCorrect(string)待检测的单词boolean
返回最佳纠正结果correct(string)待检测的单词String如果没有找到可以纠正的单词,则返回其本身
判断单词拼写是否正确correctList(string)待检测的单词List返回所有匹配的纠正列表
判断单词拼写是否正确correctList(string, int limit)待检测的单词, 返回列表的大小返回指定大小的的纠正列表列表大小 <= limit

测试语句输入:

String testString = "Hi lets see fi iti cahn check miy seplling";

EnWordCheckers工具类仅支持单个单词的拼写纠正,目前word-checker-0.1.0版本支持中英文混合长文本自动分词纠正,以下输出结果可使用WordCheckers工具类直接输出。

测试输出结果:

单词:Hi,输出是否拼写正确:true,输出最佳纠正结果in,输出匹配纠正列表[in, is, i, it, if, ii, id, hi]
--------
单词:lets,输出是否拼写正确:true,输出最佳纠正结果lets,输出匹配纠正列表[lets]
--------
单词:see,输出是否拼写正确:true,输出最佳纠正结果see,输出匹配纠正列表[see]
--------
单词:fi,输出是否拼写正确:false,输出最佳纠正结果of,输出匹配纠正列表[of, in, is, i, it, if, ii, id, fri, fit, fix, fig, fin, fir, fid, fib, fie, hi]
--------
单词:iti,输出是否拼写正确:false,输出最佳纠正结果it,输出匹配纠正列表[it, its, ii, bit, kit, iii, int, hit, fit, tip, tim, sit, tie, tit, tin, vii, pit, lit, til, wit, tai, xii, tia, cit, tic, dit, git, ito, ait, lii, nit, rit, tui, twi, inti, zit, tiu, tiv, titi, ziti, wii]
--------
单词:cahn,输出是否拼写正确:false,输出最佳纠正结果can,输出匹配纠正列表[can, cash, scan, cant, clan, chen, chan, chin, cane, cans, cyan, cain, hahn, kahn, cath, cana, caen, chon, canc, icahn]
--------
单词:check,输出是否拼写正确:true,输出最佳纠正结果check,输出匹配纠正列表[check]
--------
单词:miy,输出是否拼写正确:false,输出最佳纠正结果my,输出匹配纠正列表[my, may, min, mid, mix, amy, mil, mic, mai, mia, ivy, mir, ami, moi, icy, mig, mim, mys, miry]
--------
单词:seplling,输出是否拼写正确:false,输出最佳纠正结果selling,输出匹配纠正列表[selling, spelling, swelling, smelling, spilling, shelling]

模块使用分析

优点缺点处理方案
响应时间● 单个单词保持在1MS上下响应结果 ● 长文本保持在19~100MS内初次调用工具类时间1S
单词覆盖● 基础词库8W+,覆盖基本常用单词 ● 可自定义词库● 英文单词总数60W左右,无全面覆盖如需增加单词使用自定义词库
纠错结果● 可判断单词拼写正确与否 ● 可返回纠正单词列表 ● 可返回最佳纠正结果● 拼写非常杂乱的单词无法纠正及判断对错,将会返回输入本身 ● 最佳纠正结果可能并不是最有效结果 ● 纠正单词列表内单词很多 ● 类似于my输入错误成miy,最佳结果会是may,根据字数有限判断 ● 无法在单词衔接及语法上给出建议,仅单独的单词拼写纠错需要在代码内对返回结果再做处理
其他● 长文本中英混合模式可自动分词纠错 ● 2核1G资源可用,每次需占用1核资源● 偶现抛错,出现在大量杂乱单词的长文本纠错模式下针对抛错需要捕获

使用方式及依赖包配置

目前最新版本为0.1.0

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

自定义词库

项目资源目录创建文件 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";
System.out.println(EnWordCheckers.isCorrect(word));
System.out.println(EnWordCheckers.isCorrect(word2));

//输出:
//true
//true

3.2 word-checker中文词语检查

功能展示

word-checker中文词语拼写检查支持的使用方式与英文一致

测试语句1输入:

String right = "正确";
String error = "万变不离其中";
System.out.println(ZhWordCheckers.isCorrect(right));
System.out.println(ZhWordCheckers.isCorrect(error));
System.out.println(ZhWordCheckers.correct(error));

测试1输出结果:

true
false
万变不离其宗

测试语句2输入:

String testStringOne = "以毒功毒";     System.out.println(ZhWordCheckers.isCorrect(testStringOne));
System.out.println(ZhWordCheckers.correct(testStringOne));
String testStringTwo = "错中复杂";   System.out.println(ZhWordCheckers.isCorrect(testStringTwo));
System.out.println(ZhWordCheckers.correct(testStringTwo));

测试2输出结果:

false
以毒攻毒
true
错中复杂

测试语句3输入:

String right = "你好,以毒功毒,每天都吃玉米但是吃不报,but i waut";
System.out.println(WordCheckers.isCorrect(right));
System.out.println(WordCheckers.correctMap(right));

测试3输出结果:

false
{你=[你], but=[but],  =[ ], 吃=[吃], 报=[报], 但=[但], 天=[天], 玉=[玉], i=[i], ,=[,], 不=[不], 每=[每], 是=[是], 米=[米], 以毒功毒=[以毒攻毒], 好=[好], 都=[都], waut=[want, wait, watt, walt, wat, wart, taut, wast, waft, naut]}

模块使用分析

优点缺点处理方案
响应时间● 单个词语10MS~20MS ● 长文本保持在19~100MS内初次调用工具类时间1S
单词覆盖● 可自定义词库● 大量中文词汇、相近字、同音字、同型字无法覆盖,基础词库覆盖性差如需使用,会大量使用到自定义词库
纠错结果● 可以判断词语正确与否 ● 可返回纠正词语 ● 可返回最佳纠正结果 ● 可结合英文长文本判断● 大量词汇无法纠错 ● 长文本下会出现分词不准确 ● 大量同音字无法判断错误,大量乱词类似"正确""正去"等无法区分对错 ● 中文无主语也可认为通顺,该情况也无法判断
其他● 长文本中英混合模式可自动分词纠错 ● 2核1G资源可用,每次需占用1核资源

使用方式及依赖包配置

自定义词库

项目资源目录创建文件 resources/data/define_word_checker_zh.txt

内容如下:

吃不报 吃不饱

使用英文空格分隔,前面是错误,后面是正确。

示例:


String right = "你好,以毒功毒,每天都吃玉米但是吃不报,but i waut";
System.out.println(WordCheckers.isCorrect(right));
System.out.println(WordCheckers.correctMap(right));

//false
//{你=[你], but=[but],  =[ ], 吃=[吃], 但=[但], 天=[天], 玉=[玉], i=[i], ,=[,], 每=[每], 是=[是], 米=[米], 以毒功毒=[以毒攻毒], 好=[好], 都=[都], 吃不报=[吃不饱], waut=[want, wait, watt, walt, wat, wart, taut, wast, waft, naut]}

中英文混合长文本校验使用

WordCheckers 工具类提供了长文本中英文混合的自动纠正功能。

功能方法参数返回值备注
文本拼写是否正确isCorrect(string)待检测的文本boolean全部正确,才会返回 true
返回最佳纠正结果correct(string)待检测的单词String如果没有找到可以纠正的文本,则返回其本身
判断文本拼写是否正确correctMap(string)待检测的单词Map<String, List>返回所有匹配的纠正列表
判断文本拼写是否正确correctMap(string, int limit)待检测的文本, 返回列表的大小返回指定大小的的纠正列表列表大小 <= limit

3.3 languagetool-en英文语法检查

功能展示

languagetool可支持的语言及语法规则数量

语言规则数量
Arabic520
Asturian61
Belarusian8
Breton675
CatalanVariants for: Valencian5306
Chinese1863
Danish78
DutchVariants for: Belgium3374
EnglishVariants for: Australian, Canadian, GB, New Zealand, South African, US5727
Esperanto422
French7263
Galician308
GermanVariants for: Austria, Germany, Swiss4724
Greek55
Irish1663
Japanese734
Italian139
Khmer33
Persian283
Polish1728
PortugueseVariants for: Angola preAO, Brazil, Moçambique preAO, Portugal2732
Romanian457
Russian878
Slovak170
Slovenian86
SpanishVariants for: voseo1430
Swedish26
Tagalog44
Tamil210
Ukrainian1038

测试语句1输入:

JLanguageTool lt = new JLanguageTool(new AmericanEnglish());
String input = "Hi lets see fi iti cahn check miy seplling";
List<RuleMatch> result = lt.check(input);
if (result !=null && !result.isEmpty()){
    System.out.println("有错误");
}else {
    System.out.println("无错误");
}
for (RuleMatch ruleMatch : result) {
    System.out.println("    " + ruleMatch);
}

测试1结果输出:

有错误
Checking 'Hi lets see fi iti cahn check miy seplling' with Chinese:
    MORFOLOGIK_RULE_EN_US:12-14:Possible spelling mistake found.
    MORFOLOGIK_RULE_EN_US:15-18:Possible spelling mistake found.
    MORFOLOGIK_RULE_EN_US:19-23:Possible spelling mistake found.
    MORFOLOGIK_RULE_EN_US:30-33:Possible spelling mistake found.
    MORFOLOGIK_RULE_EN_US:34-42:Possible spelling mistake found.
    //单词拼写错误

测试语句2输入:

JLanguageTool lt = new JLanguageTool(new AmericanEnglish());
String input = "who are you you";
List<RuleMatch> result = lt.check(input);
if (result !=null && !result.isEmpty()){
    System.out.println("有错误");
}else {
    System.out.println("无错误");
}
for (RuleMatch ruleMatch : result) {
    System.out.println("    " + ruleMatch);
}

测试2输出:

有错误
    UPPERCASE_SENTENCE_START:0-3:This sentence does not start with an uppercase letter.
    //语句开头单词没有大写
    ENGLISH_WORD_REPEAT_RULE:8-15:Possible typo: you repeated a word
    //you单词重复了

测试3对比文本输入:

JLanguageTool lt = new JLanguageTool(new AmericanEnglish());
String input = "I hope an world peace";
List<RuleMatch> result = lt.check(input);
if (result !=null && !result.isEmpty()){
    System.out.println("有错误");
}else {
    System.out.println("无错误");
}
for (RuleMatch ruleMatch : result) {
    System.out.println("    " + ruleMatch);
}

String input2 = "I hope for world peace";
List<RuleMatch> result2 = lt.check(input2);
if (result2 !=null && !result2.isEmpty()){
    System.out.println("有错误");
}else {
    System.out.println("无错误");
}
for (RuleMatch ruleMatch : result2) {
    System.out.println("    " + ruleMatch);
}

测试3对比输出:

有错误
    EN_A_VS_AN:7-9:Use <suggestion>a</suggestion> instead of 'an' if the following word doesn't start with a vowel sound, e.g. 'a sentence', 'a university'.
无错误

模块使用分析

优点缺点处理方案
响应时间● 单个句子语法检查在10~30MS上下初次工具类调用需要3.6S代码结构处理
语法覆盖● 可自定义规则 ● 包含基础规则xml英语规则5727个 ● 包含多种风格英语规则包● 无法完全覆盖所有英文语法规范如有需要可以自定义加入规则
纠错结果● 可以判断多种语法错误 ● 可根据使用需要灵活切换规则包及语言 ● 可以给出详细出错的字数位置及详细错误信息● 单词拼写错误无法给出纠正结果
其他● 基于错误模式匹配,降低文本纠正难度 ● 规则可配置,检验规则灵活。 ● 可积累复用的规则文件。● 各个语法规则包判断标准不一样需要自行判断所需包 ● 扫描匹配的资源消耗巨大。目前测试每次扫描需要1G内存以及大量CPU资源,需要大于3核2G的资源可运行 ● 自定义匹配规则配置复杂可根据需要加入规则类以及配置

使用方式及包配置

<dependency>
    <groupId>org.languagetool</groupId>
    <artifactId>language-en</artifactId>
    <version>6.0</version>
</dependency>

<dependency>
    <groupId>org.languagetool</groupId>
    <artifactId>languagetool-core</artifactId>
    <version>6.0</version>
</dependency>

语言包选择:

创建META-INF/org/languagetool/language-module.properties 。

该文件如下所示:

languageClasses=org.languagetool.language.Italian

languageClasses=org.languagetool.language.Polish

languageClasses=org.languagetool.language.English,org.languagetool.language.AmericanEnglish

注: 该类JLanguageTool不是线程安全的。JLanguageTool 每个线程创建一个实例,但只创建一次语言(例如new BritishEnglish())并将其用于所有实例JLanguageTool。对于它也是如此 MultiThreadedJLanguageTool——它的名字指的是它在内部使用线程,但它本身不是线程安全的。

3.4 languagetool-zh中文检查

功能展示

测试语句1输入:

JLanguageTool langTool = new JLanguageTool(new Chinese());
System.out.println(langTool.getAllActiveRules());
List<RuleMatch> matches = langTool.check("我和她去吃了二顿饭。");
System.out.println(matches);
for (RuleMatch match : matches) {
    System.out.println("可能拼写错误 " +
            match.getFromPos() + "-" + match.getToPos() + ": " +
            match.getMessage());
    System.out.println("建议修正(s): " +
            match.getSuggestedReplacements());
}

测试1输出结果:

[wa5[5]:6-8:若非古汉语,则量词“二”可能使用错误,您的意思是否是:<suggestion>两顿</suggestion>?]
可能拼写错误 6-8: 若非古汉语,则量词“二”可能使用错误,您的意思是否是:<suggestion>两顿</suggestion>?
建议修正(s): [两顿]

测试语句2输入:

JLanguageTool langTool = new JLanguageTool(new Chinese());
System.out.println(langTool.getAllActiveRules());
List<RuleMatch> matches = langTool.check("消毁一个人,我没有计性,我天每三顿饭吃我");
System.out.println(matches);
for (RuleMatch match : matches) {
    System.out.println("可能拼写错误 " +
            match.getFromPos() + "-" + match.getToPos() + ": " +
            match.getMessage());
    System.out.println("建议修正(s): " +
            match.getSuggestedReplacements());
}

测试2输出结果:

[XIAO1_XIAO2[1]:0-2:您的意思是"<suggestion>销毁</suggestion>"吗?, JI31_JI32[5]:9-10:您的意思是"<suggestion>记</suggestion>性"吗?]
可能拼写错误 0-2: 您的意思是"<suggestion>销毁</suggestion>"吗?
建议修正(s): [销毁]
可能拼写错误 9-10: 您的意思是"<suggestion>记</suggestion>性"吗?
建议修正(s): [记]

测试语句3输入:

JLanguageTool langTool = new JLanguageTool(new Chinese());
System.out.println(langTool.getAllActiveRules());
List<RuleMatch> matches = langTool.check("后歌开了会唱演,险保买我");
System.out.println(matches);
for (RuleMatch match : matches) {
    System.out.println("可能拼写错误 " +
            match.getFromPos() + "-" + match.getToPos() + ": " +
            match.getMessage());
    System.out.println("建议修正(s): " +
            match.getSuggestedReplacements());
}

测试3输出结果:

[]

模块使用分析

优点缺点处理方案
响应时间● 单个句子语法检查在10~30MS上下初次工具类调用需要3.6S代码结构处理
语法覆盖● 可自定义规则● 自定义规则配置复杂 ● 中文语言规则仅1863项,且大多数不是语法错误,都是成语及词语相近词错误,中文规则数量庞大,完全无法覆盖
纠错结果● 可以给出详细出错的字数位置及详细错误信息● 大部分无纠错结果,与语法覆盖有关,影响使用
其他● 基于错误模式匹配,降低文本纠正难度 ● 规则可配置,检验规则灵活。 ● 可积累复用的规则文件。● 各个语法规则包判断标准不一样需要自行判断所需包 ● 扫描匹配的资源消耗巨大。目前测试每次扫描需要1G内存以及大量CPU资源,需要大于3核2G的资源可运行 ● 中文规则包过于小 ● 中文中的量词包含阿拉伯数字、中文大小写数字等,数词的筛选很困难,找出统一的判断规则配置的难度极大。 ● 以错误的匹配规则检查语法的方式,难以做到高度抽象,无法涵盖到不同的语法情况,就需要通过具体的字词匹配,才能满足改错的精确性。 ● 一些不常用的词语和隐性的表达方式,难以用规则涵盖,使用LT提供的XML系统也难以进行统一规格化描述,不得不为每一种“隐性错误”进行区别对待,单独编写规则。 ● 标点符号的类别多样,目前 LT 所使用的 ICTCLAS 分词系统,对大部分符号的支持度都不高,甚至会对一些符号进行断句处理,这样就无法通过规则匹配出大部分符号使用错误的语法规则。

使用方式及依赖包配置:

<dependency>
    <groupId>org.languagetool</groupId>
    <artifactId>language-zh</artifactId>
    <version>6.0</version>
</dependency>

4.调研对比结论

languagetoolword-checker可用性分析
中文词语检查可检查词语错误与正确,可以根据规则给出纠正,配置复杂,覆盖面小,需要大量自填规则,基础规则基本不可用可以检查词语错误与正确,可以给出是否准确词语,覆盖面小,需要大量自定义词库中文词语检查覆盖面太小,中文本身词语就过多,针对日常对话词语可用性差
英文单词检查可以检查单词拼写正确与错误,但无法给出纠正单词推荐可以检查单词拼写正确错误,可以给出纠正单词推荐以及最佳纠正结果word-checker基本可用于英文单词拼写检查,效果比languagetool要好,单个单词拼写上效率高且资源占用小,占用约2核1G
中文语法检查可以根据规则检查语法,但规则太小,基本无法覆盖日常语言的语法,很多说错主语的句子也无法纠正。另中文组合错误不好判断仅可以检查单词,无法进行语法检查只有languagetool可以支持语法检查,但是中文语法规则配置复杂,基础规则覆盖面太小,可用性非常差
英文语法检查可以检查英文的多个语法错误,长文本中多个语法错误都可以返回,规则包覆盖面较广,但资源占用较大仅可检查单词,无长文本上下文连接,无法检查语法错误languagetool在英文语法检查上表现良好,目前基础规则包覆盖面较广,可以检查大部分的英文语法,但资源占用较大,需要至少4核2G的空闲资源机器可运行
------------------------- 走在路上的symoon