Python实现单词拼写检查


Posted in Python onApril 25, 2015

这几天在翻旧代码时发现以前写的注释部分有很多单词拼写错误,这些单词错得不算离谱,应该可以用工具自动纠错绝大部分。用 Python 写个拼写检查脚本很容易,如果能很好利用 aspell/ispell 这些现成的小工具就更简单了。

要点

1、输入一个拼写错误的单词,调用 aspell -a 后得到一些候选正确单词,然后用距离编辑进一步?鹧〕龈??返拇省1热缭诵 aspell -a,输入 ‘hella' 后得到如下结果:
hell, Helli, hello, heal, Heall, he'll, hells, Heller, Ella, Hall, Hill, Hull, hall, heel, hill, hula, hull, Helga, Helsa, Bella, Della, Mella, Sella, fella, Halli, Hally, Hilly, Holli, Holly, hallo, hilly, holly, hullo, Hell's, hell's

2、什么是距离编辑(Edit-Distance,也叫 Levenshtein algorithm)呢?就是说给定一个单词,通过多次插入、删除、交换、替换单字符的操作后枚举出所有可能的正确拼写,比如输入 ‘hella',经过多次插入、删除、交换、替换单字符的操作后变成:
‘helkla', ‘hjlla', ‘hylla', ‘hellma', ‘khella', ‘iella', ‘helhla', ‘hellag', ‘hela', ‘vhella', ‘hhella', ‘hell', ‘heglla', ‘hvlla', ‘hellaa', ‘ghella', ‘hellar', ‘heslla', ‘lhella', ‘helpa', ‘hello', …

3、综合上面2个集合的结果,并且考虑到一些理论知识可以提高拼写检查的准确度,比如一般来说写错单词都是无意的或者误打,完全错的单词可能性很小,而且单词的第一个字母一般不会拼错。所以可以在上面集合里去掉第一个字母不符合的单词,比如:'Sella', ‘Mella', khella', ‘iella' 等,这里 VPSee 不删除单词,而把这些单词从队列里取出来放到队列最后(优先级降低),所以实在匹配不了以 h 开头的单词才去匹配那些以其他字母开头的单词。

4、程序中用到了外部工具 aspell,如何在 Python 里捕捉外部程序的输入和输出以便在 Python 程序里处理这些输入和输出呢?Python 2.4 以后引入了 subprocess 模块,可以用 subprocess.Popen 来处理。

5、Google 大牛 Peter Norvig 写了一篇 How to Write a Spelling Corrector 很值得一看,大牛就是大牛,21行 Python 就解决拼写问题,而且还不用外部工具,只需要事先读入一个词典文件。本文程序的 edits1 函数就是从牛人家那里 copy 的。

代码

 

#!/usr/bin/python
# A simple spell checker

import os, sys, subprocess, signal

alphabet = 'abcdefghijklmnopqrstuvwxyz'

def found(word, args, cwd = None, shell = True):
  child = subprocess.Popen(args, 
    shell = shell, 
    stdin = subprocess.PIPE, 
    stdout = subprocess.PIPE, 
    cwd = cwd, 
    universal_newlines = True) 
  child.stdout.readline()
  (stdout, stderr) = child.communicate(word)
  if ": " in stdout:
    # remove \n\n
    stdout = stdout.rstrip("\n")
    # remove left part until :
    left, candidates = stdout.split(": ", 1) 
    candidates = candidates.split(", ")
    # making an error on the first letter of a word is less 
    # probable, so we remove those candidates and append them 
    # to the tail of queue, make them less priority
    for item in candidates:
      if item[0] != word[0]: 
        candidates.remove(item)
        candidates.append(item)
    return candidates
  else:
    return None

# copy from http://norvig.com/spell-correct.html
def edits1(word):
  n = len(word)
  return set([word[0:i]+word[i+1:] for i in range(n)] +           
    [word[0:i]+word[i+1]+word[i]+word[i+2:] for i in range(n-1)] +
    [word[0:i]+c+word[i+1:] for i in range(n) for c in alphabet] +
    [word[0:i]+c+word[i:] for i in range(n+1) for c in alphabet])

def correct(word):
  candidates1 = found(word, 'aspell -a')
  if not candidates1:
    print "no suggestion"
    return 

  candidates2 = edits1(word)
  candidates = []
  for word in candidates1:
    if word in candidates2:
      candidates.append(word)
  if not candidates:
    print "suggestion: %s" % candidates1[0]
  else:
    print "suggestion: %s" % max(candidates)

def signal_handler(signal, frame):
  sys.exit(0)

if __name__ == '__main__':
  signal.signal(signal.SIGINT, signal_handler)
  while True:
    input = raw_input()
    correct(input)

更简单的方法

当然直接在程序里调用相关模块最简单了,有个叫做 PyEnchant 的库支持拼写检查,安装 PyEnchant 和 Enchant 后就可以直接在 Python 程序里 import 了:

>>> import enchant
>>> d = enchant.Dict("en_US")
>>> d.check("Hello")
True
>>> d.check("Helo")
False
>>> d.suggest("Helo")
['He lo', 'He-lo', 'Hello', 'Helot', 'Help', 'Halo', 'Hell', 'Held', 'Helm', 'Hero', "He'll"]
>>>
Python 相关文章推荐
Python的Django框架中模板碎片缓存简介
Jul 24 Python
Python3中简单的文件操作及两个简单小实例分享
Jun 18 Python
Django csrf 两种方法设置form的实例
Feb 03 Python
基于python判断目录或者文件代码实例
Nov 29 Python
matplotlib.pyplot画图并导出保存的实例
Dec 07 Python
Python时间差中seconds和total_seconds的区别详解
Dec 26 Python
pytorch 中pad函数toch.nn.functional.pad()的用法
Jan 08 Python
pytorch 利用lstm做mnist手写数字识别分类的实例
Jan 10 Python
通过实例了解Python str()和repr()的区别
Jan 17 Python
keras实现调用自己训练的模型,并去掉全连接层
Jun 09 Python
解决python3中os.popen()出错的问题
Nov 19 Python
python 下划线的多种应用场景总结
May 12 Python
在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程
Apr 25 #Python
使用PDB简单调试Python程序简明指南
Apr 25 #Python
Python脚本判断 Linux 是否运行在虚拟机上
Apr 25 #Python
在Python中使用cookielib和urllib2配合PyQuery抓取网页信息
Apr 25 #Python
使用Python的Tornado框架实现一个一对一聊天的程序
Apr 25 #Python
使用Python发送邮件附件以定时备份MySQL的教程
Apr 25 #Python
安装Python的web.py框架并从hello world开始编程
Apr 25 #Python
You might like
我的论坛源代码(五)
2006/10/09 PHP
php 全文搜索和替换的实现代码
2008/07/29 PHP
Linux Apache PHP Oracle 安装配置(具体操作步骤)
2013/06/17 PHP
PHP中Fatal error session_start()错误解决步骤
2014/08/05 PHP
PHP移动文件指针ftell()、fseek()、rewind()函数总结
2014/11/18 PHP
Yii框架登录流程分析
2014/12/03 PHP
php判断对象是派生自哪个类的方法
2015/06/20 PHP
Linux系统中为php添加pcntl扩展
2016/08/28 PHP
php实现生成code128条形码的方法详解
2017/07/19 PHP
javascript js cookie的存储,获取和删除
2007/12/29 Javascript
在html页面中包含共享页面的方法
2008/10/24 Javascript
jquery中ajax调用json数据的使用说明
2011/03/17 Javascript
js过滤HTML标签以及空格的思路及代码
2013/05/24 Javascript
JavaScript语言对Unicode字符集的支持详解
2014/12/30 Javascript
浅谈jQuery的offset()方法及示例分享
2015/07/17 Javascript
javascript性能优化之DOM交互操作实例分析
2015/12/12 Javascript
BootStrap扔进Django里的方法详解
2016/05/13 Javascript
bootstrapValidator.min.js表单验证插件
2017/02/09 Javascript
react实现pure render时bind(this)隐患需注意!
2017/03/09 Javascript
Angular入口组件(entry component)与声明式组件的区别详解
2018/04/09 Javascript
微信小程序实现星级评分和展示
2018/07/05 Javascript
详解微信小程序与内嵌网页交互实现支付功能
2018/10/22 Javascript
Node.js assert断言原理与用法分析
2019/01/04 Javascript
JS将时间秒转换成天小时分钟秒的字符串
2019/07/10 Javascript
[35:26]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第三局
2016/02/26 DOTA
python连接MySQL、MongoDB、Redis、memcache等数据库的方法
2013/11/15 Python
详解python中list的使用
2019/03/15 Python
Python中的list与tuple集合区别解析
2019/10/12 Python
使用python实现微信小程序自动签到功能
2020/04/27 Python
美国非常受欢迎的Spa品牌:Bliss必列斯
2018/04/10 全球购物
演讲稿祖国在我心中
2014/05/04 职场文书
计算机系本科生求职信
2014/05/31 职场文书
教师思想工作总结2015
2015/05/13 职场文书
励志语录:你若不勇敢,谁替你坚强
2019/11/08 职场文书
深入解析MySQL索引数据结构
2021/10/16 MySQL
JavaScript中10个Reduce常用场景技巧
2022/06/21 Javascript