zlukfo@gmail.com
  • Публикации
  • Темы
  • Ключевые слова
  • Архив

Генерация словарей ispell

Данная задача родилась из одной практической проблемы.

В Сети можно легко найти ispell-словарь русского языка общей лексики, например здесь. Где используются такие словари, можно прочитать по этой ссылке. Но на тот момент было главное, что ispell-словари являются важной частью полнотекстового поиска в базах данных postgresql. Также важным было то, что в разрабатываемом проекте пользовательский поиск выполнялся c акцентом на географические названия и фамилии. Которых в общем словаре не так уж много.

Поэтому возникла задача поиска (составления, генерации, ...) дополнительных словарей ispell необходимой тематики.

В данной публикации приводится решение этой задачи с попыткой его максимального обобщения.

После экспериментов был выбран следующий подход решения задачи

  1. Генерация словаря ispell выполняется на основе файла-списка необходимых слов. Получить такой список можно минимум двумя способами: а) составить вручную, б) выделить из словаря языкового корпуса, например, русского или британского
  2. Каждое слово словаря приводится в нормальную форму. Для этого используются морфологические анализаторы. Для русского языка можно использовать mystem от Yandex или библиотеку python pymorphy2. Для английского языка можно использовать nltk
  3. Для нормальной формы слова подбирается набор правил образования словоформ на основе составленных правил для ispell-словарей. Скачать эти правила для различных языков можно по этой ссылке

Данный подход реализован в скрипте на python, код приводится в конце публикации. Скрипт реализован для решения задачи со следующими исходными условиями:

  • словарь генерируется для русского языка
  • на вход скрипту может передаваться словарь Opencorpora или файл с произвольным списком слов

Использование словаря Opencorpora имеет ряд преимуществ:

  • на сегодня это самый объемный словарь для русского языка, доступный для свободного скачивания (содержит более 400 тыс. уникальных слов)
  • каждая словоформа словаря характеризуется морфологическими признаками (граммеми). Это позволяет выделять для генерируемого словаря только слова нужного типа (например, географические названия или глаголы)

Для приведения слова к нормальной форме в скрипте используется библиотека pymorphy2. Помимо скорости работы и высокого качества распознавания слов, ее преимущество еще и в том, что работа библиотеки основана на словаре Opencorpora и имеет тот же набор граммем.

Вот полный код скрипта

# -*- coding: utf-8 -*-
import codecs
import re
def getFromOpencorpora(filename, grammem):
        '''
        Function: getWFromOpencorpora
        Summary:  извлекает из словаря Opencorpora нормальную форму слова
                        (соответсвующую заданному набору граммем) и ее словоформы
        Examples:
        Attributes:
                        @param (filename): путь к имени файла словаря Opencorpora
                        @param (grammem): массив граммем (признаков) слова, которые необходимо извлекать
                                                        из словаря. По сути является фильтром для извлечения слов
                                                        нужного типа (глагол, одущивленное сущ. и т.д.)
        Returns: Возвращает итератор на генератор пары (список) (исходная форма слова, массив словоформ)
        '''
        DELIM='[,\s]+'
        if type(grammem)==type(''): grammem=[grammem]
        f=codecs.open(filename, 'r', 'utf-8')
        words_form=[]
        ps=re.compile(DELIM)
        for line in f:
                g=ps.split(line.replace('\n',''))
                if len(g)>1:
                        w=g.pop(0)
                        if set(grammem)<=set(g) or words_form:
                                words_form.append(w)
                if len(line)<2 and words_form:
                        n=words_form.pop(0)
                        ff=set([i.lower() for i in words_form if n!=i])
                        yield [n.lower(), ff]
                        words_form=[]
        f.close()

def getFromListFile(filename):
        '''
        Function: getFromListFile
        Summary: возвращает каждое слово из файла, хранящего пользовательский список слов
                        для которого нужно сформировать правила
        Examples:
        Attributes:
                        @param (filename): имя файла
        Returns: Возвращает итератор на генератор пары (список) (исходная форма слова, массив словоформ)
        '''
        for f in codecs.open(filename, 'r', 'utf-8'):
                yield[f.replace('\n','').lower(),set()]

import pymorphy2
def getFromPymorphy(word, grammem, morph):
        '''
        Function: getFromPymorphy
        Summary: для исходного слова и заданного набора граммем генерирует исходну форму
                        и возможные словоформы
        Examples:
        Attributes:
                        @param (word): исходное слово
                        @param (grammem): массив нужных граммем для извлекаемого слова и словоформ
                        @param (morph): объект морфологического анализатора morph = pymorphy2.MorphAnalyzer()
        Returns: возвращает список пар - (исходная форма, список словоформ), соответсвующий заданным грамменам
        '''
        wf=[]
        if type(grammem)==type(''): grammem=[grammem]
        # исходное слово может распознаться как относящееся к различным типам (по набору граммем)
        # например, 'туши'
        # на практике такого не должно быть - исходный набор граммем нужно задавать так,
        # чтобы однозначно определять категорию слова
        for j in morph.parse(word):
                f=set()
                for i in j.lexeme:
                        if set(grammem)<=i.tag.grammemes:
                                f.add(i.word)
                        if (j.normal_form,f) not in wf:
                                        wf.append((j.normal_form,f))
        return wf

def getAffixRules(filename):
        r=[]
        f=codecs.open(filename, 'r', 'utf-8')
        for i in f:
                ii=re.split(r'\s+', i[:-1])
                if len(ii)>=5:
                        if ii[2]=='0': ii[2]=''
                        if ii[3]=='0': ii[3]=''
                        r.append(ii)
        return r
        f.close()

if __name__=='__main__':
        grammem=['VERB']
        f_out_dict=codecs.open("%s.dict" % ('_'.join(grammem).lower(),), 'w', 'utf-8')
        rc=[(re.compile(j[4]+'$'), re.compile(j[2]+'$'), j[3], j[1]) for j in getAffixRules('ru.affix')]
        morph = pymorphy2.MorphAnalyzer()
        for word, wf in getFromOpencorpora("dict.opcorpora.txt", grammem):
        #for word, wf in getFromListFile("my_dict.txt"):
                for normal_form, words_forms in getFromPymorphy(word, grammem, morph):
                        r=set()
                        for p in rc:
                                if p[0].findall(normal_form):
                                        if p[1].sub(p[2], normal_form) in words_forms:
                                                r.add(p[3])
                if r:
                        f_out_dict.write('%s/%s\n' % (normal_form, ''.join(r)))

        f_out_dict.close()

Для работы со словарем Opencorpora используется функция getWFromOpencorpora, для работы с произвольным файлом-списком - getFromListFile.

Для того, чтобы выбрать из Opencorpora только слова нужных типов, необходимо в переменной grammem задать список необходимых граммем. Обозначения граммем можно посмотреть на этой странице

Практическую пользу от данного скрипта (и от этой публикации) можно оценить, ознакомившись с материалами этой статьи

Англоязычные словари ispell

Описанный подход также применяться для генерации словарей ispell для необходимых слов английского языка (и других тоже). Главное здесь - найти подходящий языковой корпус. Например, скрипт для генерации словаря ispell на основе Британского национального корпуса выглядит примерно так

Полезные ссылки

  1. Все граммемы OpenCorpora
  2. Ресурс с русскими словарями (словарь синонимов, кладра НП россии (только им падеж), тезаурус)
  3. Алгоритм работы ispell-словарей

Опубликовано

авг. 16, 2016

Тема

Анализ текста

Ключевые слова

  • ispell 2
  • zlukfo@gmail.com - Публикации на тему разработки web-приложений
  • Все авторские права защищены
  • Автор и разработчик блога zlukfo. Theme: Elegant by Talha Mansoor