NetSpell - .NET 拼写检查器






4.90/5 (48投票s)
2003年10月22日
10分钟阅读

535219
NetSpell 项目是一个完全用托管 C# .NET 代码编写的拼写检查引擎。
引言
NetSpell 项目是一个完全用托管 C# .NET 代码编写的拼写检查引擎。NetSpell 对拼写错误单词的建议是使用语音(听起来像)匹配生成的,并按排版(看起来像)分数进行排名。NetSpell 支持多种语言,词典基于 OpenOffice Affix 压缩格式。该库可用于 Windows 或 Web 窗体项目。下载内容包括一个英文字典,其他语言的词典可在项目网站上下载。NetSpell 还支持用户添加的单词和用户词典的自动创建。它还包括一个词典构建工具,用于构建自定义词典。
词典
所有拼写检查器的基础都是词表,也称为词典。词典包含一种语言的常用词列表。例如,此包附带的美国英语词典包含 162,573 个单词。
在设计 NetSpell 词典时,我希望词典是单个文件,尽可能小且加载速度极快。我尝试了许多不同的方法来保存和加载大型词表。我尝试的技术范围从保存的数据集到二进制序列化集合,所有这些都证明太慢了。我最终使用了老旧的 UTF8 文本文件。加载和解析文本文件被证明速度极快。
词缀压缩
我想解决的第一个问题是文件大小。任何压缩方案都必须解压缩得非常快。我首先尝试使用 zip。虽然词典在一秒钟内加载,但仍然不够快,无法在 Web 环境中使用。
我对拼写检查器的研究发现了一种流行的技术,称为词缀压缩。词缀压缩是使用一个基础词,并向其添加前缀和后缀以创建其他词。词缀压缩方案最初由 Geoff Kuenning 为他的 ISpell 拼写检查器开发。OpenOffice 项目扩展了词缀压缩方案以简化其规则定义。NetSpell 词缀实现主要基于 OpenOffice MySpell 格式。阅读以下链接以更好地理解词缀压缩格式。
由于使用了 OpenOffice 词典格式,NetSpell 词典可以轻松地从 OpenOffice 词典创建。这使得 NetSpell 可以轻松支持其他语言。NetSpell 下载包括一个词典构建工具,允许您创建新词典。构建工具还允许您导入 OpenOffice 词典并将其保存为 NetSpell 格式。
词典部分
为了实现将词典作为单个文件的目标,我需要一种方法来分隔文件的不同部分。这将允许存储不同类型的数据,因为词表不是唯一需要存储的数据。我决定使用 INI 部分格式。我考虑过使用 XML,但 XML 由于使用标签而导致文件大小过大。我最终在文件中使用了以下部分。
[Copyright]
版权部分包含有关特定词典词表的任何版权信息。
[Try]
尝试部分包含一系列字母,用于尝试将拼写错误的单词组合成正确的单词。它们应在一行中按字符频率(从高到低)列出。此部分由稍后讨论的近似匹配策略使用。
[Replace]
替换部分包含经常拼写错误的字母组合序列,例如 ei 和 ie。数据以“搜索字符”空格“替换字符”的格式输入到此部分。例如,ei, ie 在词典中会显示为“ei ie”。此部分由稍后讨论的近似匹配策略使用。
[Prefix]
前缀部分用于定义一组词缀规则,用于可以附加到基础单词开头的词缀以形成其他单词。这些规则的格式与 OpenOffice 词缀文件的格式相同,只是 PFX 已删除。您可以在此处阅读有关 OpenOffice 词缀格式的更多信息。
[Suffix]
后缀部分用于定义一组词缀规则,用于可以附加到基础单词末尾的词缀以形成其他单词。后缀规则的格式与 OpenOffice 词缀文件的格式相同,只是 SFX 已删除。您可以在此处阅读有关 OpenOffice 词缀格式的更多信息。
[Phonetic]
语音部分是可选的,它包含一组规则,定义如何为字符或字符集生成语音代码。语音代码是使用 Lawrence Philips 的 Metaphone 算法生成的,该算法已由 ASpell 项目改编为表格格式。NetSpell 词典使用与 ASpell 相同的格式。ASpell 语音映射可以直接由 NetSpell 使用。请参阅以下链接以了解有关 ASpell 语音代码的更多信息。
[Words]
单词部分是词典的基础单词列表。此部分的格式为“单词/词缀键/语音代码”。词缀键和语音代码部分是可选的。词缀键部分指示哪些词缀规则适用于此单词。语音代码部分是此单词语音代码的缓存,由语音建议策略使用。
关于词典的另一个重要事项是,它们的命名与 .NET Framework `CultureInfo.Name` 属性匹配。例如,美国英语词典名为“en-US.dic”。en-US 与 `CultureInfo.Name` 属性匹配。这允许 NetSpell 库默认使用与计算机区域设置对应的词典。
拼写检查文本
拼写检查通常通过在词典中搜索给定单词来执行。现在我们已经实现了词缀压缩,搜索单词变得更加复杂。我们必须从给定单词中创建基本单词。过程如下:首先,在基本单词列表中搜索给定单词。如果单词在基本单词列表中未找到,则从单词中删除后缀规则。删除后缀后,检查新单词是否在基本单词列表中。如果单词仍然未找到,则对前缀重复相同的过程。如果删除后缀和前缀后仍未找到单词,则词典中未找到该单词,很可能是拼写错误。
生成建议
一旦确定单词拼写错误,我们需要为该单词的正确拼写生成建议。这就是拼写检查器神奇之处。NetSpell 使用两种不同的技术来生成建议。第一种是由 Geoff Kuenning 为 ISpell 开发的,通常称为近似匹配策略。第二种是 Lawrence Philips 的 Metaphone 算法,它返回一个代码,粗略近似英语单词的发音。
近似匹配策略
近似匹配策略是一种相当简单的生成建议的方法。近似匹配采取的方法是用户不一定拼错了单词,而是打错了。如果两个单词可以通过插入一个空格、交换两个相邻字母、更改一个字母、删除一个字母或添加一个字母而变得相同,则它们被认为是近似的。如果使用这些技术生成了一个有效单词,则将其添加到建议列表中。您可能已经猜到,当一个单词真正拼写错误时,近似匹配策略并不能提供最佳的建议列表。这就是语音策略发挥作用的地方。
语音策略
为了理解语音策略,需要定义语音代码。语音代码是单词发音的粗略近似。代码中的每个字符代表一个声音。重要的是还要理解语音代码并不表示如何发音单词;它只是其发音的表示。
语音策略是将拼写错误的单词的语音代码与词表中的所有单词进行比较。如果语音代码匹配,则将该单词添加到建议列表。
虽然这个过程听起来很简单,但在引入词缀压缩后,它变得复杂得多。词缀压缩的词表只包含基本单词。我们不能简单地将拼写错误的单词的语音代码与词表进行比较,因为拼写错误的单词可能不是基本单词。为了解决这个问题,我们从拼写错误的单词中删除所有符合规则条件的词缀规则,并将结果字符串添加到可能的基词列表中。需要记住的重要一点是,可能的基词列表不是真实单词的列表。它只是一个通过从拼写错误的单词中删除词缀规则而形成的字符串列表。
现在我们已经从拼写错误的单词中获得了可能的基词列表,我们可以对它们生成语音代码,并将这些代码与基词列表进行比较。如果其中一个代码与基词代码匹配,我们就将该单词添加到建议列表中。由于我们删除了所有词缀键,并且只比较了基词,因此扩展后的基词可能是正确的单词。因此,我们通过应用所有词缀规则来扩展匹配的基词,以获取该基词的所有可能单词列表。然后,我们将该列表添加到建议列表中。
建议排序
一旦我们有了建议列表,我们需要一种方法来根据最有可能的正确拼写对它们进行排序。我对最佳方法的研究发现了编辑距离算法。编辑距离定义为将一个字符串更改为另一个字符串所需的插入、删除和替换的最小次数。NetSpell 编辑距离算法的实现有一个细微的修改,即如果第一个字符和最后一个字符不匹配,则会增加额外的编辑距离。这背后的理由是,人们在尝试拼写单词时通常可以正确地拼写第一个字符和最后一个字符。
使用库
要在您的项目中使用 NetSpell 库,只需向项目中添加对 NetSpell.SpellChecker.dll 的引用。您还可以将该库添加到 Visual Studio 工具箱中,以便更轻松地与属性进行交互。该库是基于事件的,因此您必须处理各种事件。此外,如果将 `ShowDialog` 属性设置为 true,当 `MisspelledWord` 事件发生时,该库将使用其内部建议窗体显示建议。
以下代码是 NetSpell 库的一个非常简单的实现。
internal System.Windows.Forms.RichTextBox Document;
internal NetSpell.SpellChecker.Spelling SpellChecker;
// add event handlers
this.SpellChecker.MisspelledWord +=
new NetSpell.SpellChecker.Spelling.MisspelledWordEventHandler(
this.SpellChecker_MisspelledWord);
this.SpellChecker.EndOfText +=
new NetSpell.SpellChecker.Spelling.EndOfTextEventHandler(
this.SpellChecker_EndOfText);
this.SpellChecker.DoubledWord +=
new NetSpell.SpellChecker.Spelling.DoubledWordEventHandler(
this.SpellChecker_DoubledWord);
private void SpellChecker_DoubledWord(object sender,
NetSpell.SpellChecker.SpellingEventArgs args)
{
// update text
this.Document.Text = this.SpellChecker.Text;
}
private void SpellChecker_EndOfText(object sender,
System.EventArgs args)
{
// update text
this.Document.Text = this.SpellChecker.Text;
}
private void SpellChecker_MisspelledWord(object sender,
NetSpell.SpellChecker.SpellingEventArgs args)
{
// update text
this.Document.Text = this.SpellChecker.Text;
}
// Start Spell Checking
SpellChecker.Text = this.Document.Text;
SpellChecker.SpellCheck();
项目下载包括 NetSpell 库的两个示例应用程序。第一个是 Windows 窗体文本编辑器。第二个是一个 Web 项目,演示了如何在 Web 环境中使用该库。
结论
NetSpell 项目一直是一个有趣且具有挑战性的项目。我计划继续改进并向库中添加新功能。我目前正在开发的功能是实时拼写检查,类似于 MS Word。如有任何建议、错误报告和功能请求,请随时与我联系。
Paul Welter
http://www.loresoft.com/
参考文献和鸣谢
- NetSpell 主页 http://www.loresoft.com/NetSpell
- SourceForge 项目页面 http://sourceforge.net/projects/netspell/
- OpenOffice Lingucomponent http://lingucomponent.openoffice.org/dictionary.html
- ASpell http://aspell.net/
- Metaphone 算法 http://aspell.net/metaphone/
- 词典词表 http://wordlist.sourceforge.net/