用 Python 实现英文单词纠错功能

单词纠错

  在我们平时使用Word或者其他文字编辑软件的时候,常常会遇到单词纠错的功能。比如在Word中:

640?wx_fmt=png
单词拼写错误

单词纠错算法

  首先,我们需要一个语料库,基本上所有的NLP任务都会有语料库。单词纠错的语料库为bit.txt,里面包含的内容如下:

  • Gutenberg语料库数据;

  • 维基词典;

  • 英国国家语料库中的最常用单词列表。

下载的网址为:https://github.com/percent4/-word- 。

Python实现

  实现单词纠错的完整Python代码(spelling_correcter.py)如下:

# -*- coding: utf-8 -*-
import re, collections

def tokens(text):
    """
    Get all words from the corpus
    """
    return re.findall('[a-z]+', text.lower())

with open('E://big.txt', 'r') as f:
    WORDS = tokens(f.read())
WORD_COUNTS = collections.Counter(WORDS)

def known(words):
    """
    Return the subset of words that are actually
    in our WORD_COUNTS dictionary.
    """
    return {w for w in words if w in WORD_COUNTS}


def edits0(word):
    """
    Return all strings that are zero edits away
    from the input word (i.e., the word itself).
    """
    return {word}


def edits1(word):
    """
    Return all strings that are one edit away
    from the input word.
    """
    alphabet = 'abcdefghijklmnopqrstuvwxyz'

    def splits(word):
        """
        Return a list of all possible (first, rest) pairs
        that the input word is made of.
        """
        return [(word[:i], word[i:]) for i in range(len(word) + 1)]

    pairs = splits(word)
    deletes = [a + b[1:] for (a, b) in pairs if b]
    transposes = [a + b[1] + b[0] + b[2:] for (a, b) in pairs if len(b) > 1]
    replaces = [a + c + b[1:] for (a, b) in pairs for c in alphabet if b]
    inserts = [a + c + b for (a, b) in pairs for c in alphabet]
    return set(deletes + transposes + replaces + inserts)


def edits2(word):
    """
    Return all strings that are two edits away
    from the input word.
    """
    return {e2 for e1 in edits1(word) for e2 in edits1(e1)}


def correct(word):
    """
    Get the best correct spelling for the input word
    """
    # Priority is for edit distance 0, then 1, then 2
    # else defaults to the input word itself.
    candidates = (known(edits0(word)) or
                  known(edits1(word)) or
                  known(edits2(word)) or
                  [word])
    return max(candidates, key=WORD_COUNTS.get)


def correct_match(match):
    """
    Spell-correct word in match,
    and preserve proper upper/lower/title case.
    """

    word = match.group()

    def case_of(text):
        """
        Return the case-function appropriate
        for text: upper, lower, title, or just str.:
        """
        return (str.upper if text.isupper() else
                str.lower if text.islower() else
                str.title if text.istitle() else
                str)

    return case_of(word)(correct(word.lower()))


def correct_text_generic(text):
    """
    Correct all the words within a text,
    returning the corrected text.
    """
    return re.sub('[a-zA-Z]+', correct_match, text)

测试

  有了上述的单词纠错程序,接下来我们对一些单词或句子做测试。如下:

original_word_list = ['fianlly', 'castel', 'case', 'monutaiyn', 'foresta', \
                      'helloa', 'forteen', 'persreve', 'kisss', 'forteen helloa', \
                      'phons forteen Doora. This is from Chinab.']

for original_word in original_word_list:
    correct_word = correct_text_generic(original_word)
    print('Orginial word: %s\nCorrect word: %s'%(original_word, correct_word))

输出结果如下:

Orginial word: fianlly

  接着,我们对如下的Word文档(Spelling Error.docx)进行测试(下载地址为:https://github.com/percent4/-word-),

640?wx_fmt=png
有单词错误的Word文档

对该文档进行单词纠错的Python代码如下:

from docx import Document
from nltk import sent_tokenize, word_tokenize
from spelling_correcter import correct_text_generic
from docx.shared import RGBColor

# 文档中修改的单词个数
COUNT_CORRECT = 0
#获取文档对象
file = Document("E://Spelling Error.docx")

#print("段落数:"+str(len(file.paragraphs)))

punkt_list = r",.?\"'!()/\\-<>:@#$%^&*~"

document = Document()   # word文档句柄

def write_correct_paragraph(i):
    global COUNT_CORRECT

    # 每一段的内容
    paragraph = file.paragraphs[i].text.strip()
    # 进行句子划分
    sentences = sent_tokenize(text=paragraph)
    # 词语划分
    words_list = [word_tokenize(sentence) for sentence in sentences]

    p = document.add_paragraph(' '*7)  # 段落句柄

    for word_list in words_list:
        for word in word_list:
            # 每一句话第一个单词的第一个字母大写,并空两格
            if word_list.index(word) == 0 and words_list.index(word_list) == 0:
                if word not in punkt_list:
                    p.add_run(' ')
                    # 修改单词,如果单词正确,则返回原单词
                    correct_word = correct_text_generic(word)
                    # 如果该单词有修改,则颜色为红色
                    if correct_word != word:
                        colored_word = p.add_run(correct_word[0].upper()+correct_word[1:])
                        font = colored_word.font
                        font.color.rgb = RGBColor(0x00, 0x00, 0xFF)
                        COUNT_CORRECT += 1
                    else:
                        p.add_run(correct_word[0].upper() + correct_word[1:])
                else:
                    p.add_run(word)
            else:
                p.add_run(' ')
                # 修改单词,如果单词正确,则返回原单词
                correct_word = correct_text_generic(word)
                if word not in punkt_list:
                    # 如果该单词有修改,则颜色为红色
                    if correct_word != word:
                        colored_word = p.add_run(correct_word)
                        font = colored_word.font
                        font.color.rgb = RGBColor(0xFF, 0x00, 0x00)
                        COUNT_CORRECT += 1
                    else:
                        p.add_run(correct_word)
                else:
                    p.add_run(word)

for i in range(len(file.paragraphs)):
    write_correct_paragraph(i)

document.save('E://correct_document.docx')

print('修改并保存文件完毕!')
print('一共修改了%d处。'%COUNT_CORRECT)

输出的结果如下:

修改并保存文件完毕!

修改后的Word文档如下:

640?wx_fmt=png
单词纠错后的Word文档

其中的红色字体部分为原先的单词有拼写错误,进行拼写纠错后的单词,一共修改了19处。

总结

  单词纠错实现起来并没有想象中的那么难,但也不是那么容易~https://github.com/percent4/-word-

版权声明:本文为BF02jgtRS00XKtCx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/BF02jgtRS00XKtCx/article/details/102889533

智能推荐

Android VIEW简单绘图

画布canvas 提供两个构造函数: Canvas():创建一个空的Canvas对象 Canvas(Bitmap bitmap):创建一个以bitmap位图为背景的Canvas 常用的Canvas方法: void drawBitmap(Bitmap bitmap,float left,float top,Paint paint):在指定坐标绘制位图 void drawLine(float star...

数据去重的各种方法汇总(三)

Pandas去重DataFrame 接上篇,这篇就剩最后的用Pandas对DataFrame里面的数据去重,这里也有两种方法,可以直接看官方文档(但是掌柜觉得其实就是一种方法,因为第一种只是显示哪些重复。。。): 使用duplicated方法,它会返回一个布尔向量,其长度为行数,表示行是否重复,但是并不会删除重复数据。来看实例: 然后会得到这样一个表格: 现在使用duplicated方法: 会得到...

Linux环境下RabbitMQ消息队列的安装和配置

一、什么是RabbitMQ? RabbitMQ就是一个在AMQP基础上实现的企业级消息系统,简单的说,就是一个消息队列系统。具体的介绍,可以网上去搜!目前只介绍RabbitMQ在Linux系统的安装。 二、RabbitMQ的安装 1、 RabbitMQ是基于Erlang开发,所以使用之前必须安装Erlang语言开发包。 wget http://www.erlang.org/download/otp...

train_test_split切分数据集工具

顾名思义,这是一个切分训练集与测试集的工具   如果我们不使用,而是手动进行划分,要么进行简单的操作——划去前80%为训练集,后20%为测试集,这样会带来很多的问题,因为这样做,我们切出来的会让训练集和测试集的分布很不一致,我们可以看一下简单粗暴方法切出来的分布图: 红色的训练集,蓝色是测试集(点击图片放大可以看得很清楚,直接看博客好像图片模糊)   然...

shell编程第一节 和shell

shell编程看的博客感觉写的挺好的:http://www.cnblogs.com/dongying/p/6262935.html 以及  https://www.cnblogs.com/clsn/p/8028337.html#auto_id_0 简单总结:shell编程就是对一堆Linux命令的逻辑化处理。 chmod +x hello_world.sh ./hello_world.s...

猜你喜欢

微信开发:js sdk 分享(java)

今天记录一下微信jssdk 的分享给朋友的功能,获取config接口注入。 1.需要绑定域名(注意:设置js安全域名的时候,需要设置微信ip白名单,ip白名单新出来的,非白名单内的ip无法获取access_token 更无法获取jsapi) 在设置js 安全域名在 设置–>公众号设置–>功能设置里边 appid appSercret 在开发–>...

js--HTML美术馆

前言 因为之前库房合作的时候交给我一个任务,就是在点击某一项物品的时候显示出几张相印的小图片,然后点击小图片之后显示出一张大图片,因为当时还没有接触JavaScript,所以这方面的知识不是很了解,一直拖着,大概有两天吧,是在是解决不了,于是将这个任务交给了老付和建华,今天在学习JavaScript的时候突然之后就看到了有这么一项功能,于是就有感而发。 内容 首先向大家展示代码。 这部分是HTML...

Jenkins持续集成环境部署(入门篇)

为什么要持续集成 持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 价值: 1、减少风险 一天中进行多次的集成,并做了相应的测试,有利于检查缺陷,了解软件的健康状况,减少假定。 2、减少重复过程 节省时间、费用和工作量,通过自动化的持...

linux 下rabbitmq的安装以及设置远程用户访问

安装过程中会有提示,一路输入“y”即可。 完成后安装RabbitMQ: 3.自己建个文件夹 进行下载安装也可  直接执行也可 先下载rpm: 完成后启动服务: 可以查看服务状态: 这里可以看到log文件的位置,转到文件位置,打开文件: 这里显示的是没有找到配置文件,我们可以自己创建这个文件 编辑内容如下: 这里的意思是开放使用,rabbitmq默认创建的用户gue...

Java工程师成长修炼手册:01--Java基础特性和字符串

一.三大特性 1.封装 封装,把对象的属性封装起来(使用private修饰符),不被外部程序直接随意调用或修改成员变量。只能通过对象使用public修饰符的set 和 get 方法,来设置和获取成员变量的值。也可以把只在本类内部使用的方法使用 private。另外,还可以封装,隐藏一些方法,需要用的时候,就调用这些方法。这些就是封装。 封装的优点 良好的封装能够减少耦合,可以独立地开发、优化和修改...