• Stars
    star
    141
  • Rank 259,971 (Top 6 %)
  • Language
    Python
  • Created over 10 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Попытка сделать свой GLR-парсер для русского языка на Python

GLRParser

Описание в блоге: http://vas3k.ru/blog/358/

Инструмент извлечения структурированных данных (фактов) из текста на естественном (русском) языке на Python 2.x. Построен с использованием любимого всеми морфологического анализатора pymorphy2 и никому неизвестного GLR-парсера jupyLR (был взят как самый простой для переписывания). Чем-то похож на Томита-парсер Яндекса (http://api.yandex.ru/tomita/), хотя чего греха таить, общем-то проект и был начат из-за сложной применимости Томита-парсера простыми смертными в силу особеностей его распространения и небогатой документации. По которой, в прочем, вполне очевидно, что сам парсер был открыт Яндексом лишь частично, а цель помочь простым смертным при этом была далеко не на первом месте (иначе бы Яндекс распространял его не скудным бинарником, а оформил как остальные свои проекты в библиотеку или демон).

Проект практически повторяет открытую функциональность Томита-парсера, однако написан на чистом python и открыт, что позволяет использовать его в реальных проектах и модифицировать. А еще не болен протобафом головного мозга, а использует понятные и простые питонячие структуры данных. Возможно когда-нибудь Яндекс таки дооткроет Томита-парсер и настанут светлые времена, а пока таким вот отщепенцам как я приходится выживать как могут.

Подробнее про работу GLR-парсеров и алгоритма Томиты можно почитать на википедии или нагуглить. http://ru.wikipedia.org/wiki/GLR-%D0%BF%D0%B0%D1%80%D1%81%D0%B5%D1%80

Для примера можно смотреть example.py.

from glr import GLRParser

dictionaries = {
    u"CLOTHES": [u"куртка", u"пальто", u"шубы"]
}

grammar = u"""
    S = adj<agr-gnc=1> CLOTHES
"""

glr = GLRParser(grammar, dictionaries=dictionaries)

text = u"на вешалке висят пять красивых курток и вонючая шуба"
for parsed in glr.parse(text):
    print "FOUND:", parsed

# FOUND: красивых курток
# FOUND: вонючая шуба

Примерное описание работы

  1. Входной текст разбивается на предложения по символам [!?;.]+, а так же очищается от лишних символов. Если такое поведение не устраивает, модифицируйте splitter.py.
  2. Каждое предложение разбивается на токены согласно регулярным выражениям в glr.py (константа DEFAULT_PARSER). Модифицируя этот список, можно вводить свои терминальные символы в грамматику (токены новых типов, например, можно ввести отдельный тип для чисел).
  3. Каждый токен нормализуется и к нему добавляются его морфологические характеристики. Морфологическая неоднозначность снимается... никак. Берется просто первая форма, которую вернул pymorphy2. Если такое поведение не устраивает - милости прошу в normalizer.py и в пулл реквесты.
  4. Дальше стандартный GLR-парсинг входной строки. Если строка не разбирается, то отбрасывается первый токен и все повторяется заново. Все совпадения откладываются и в конце возвращается список.

Синтаксис грамматик

Начальный символ — S (можно менять параметром root в конструкторе GLRParser);

Нетерминал - зарезервированное слово в нижнем регистре (adj, verb, noun, см. начало GLRParser чтобы научиться вводить свои);

Терминал — слово с большой буквы (зарезервированное Word или любое введенное прям в грамматике AsYouWish);

Словари - слово капсом, означающее название словаря (например CITIES), сами словари задаются как { "CITIES": ["val1", "val2", ...]} и передаются в конструктор GLRParser;

Одно слово - слово в 'одинарных' 'кавычках', будет искаться во всех своих формах (например 'шуба') (hint: в грамматике слово нужно указывать в начальной форме, а то не найдется);

Лейблы - список через запятую в <угловых скобочках> после терминала/нетерминала.

S = SomeClothes
SomeClothes = adj 'шуба'
SomeClothes = adj 'валенок'

Словари

Словарь задается простым питоновским словарем (каламбурчик). Ключи - названия словарей, их принято писать капсом. А еще лучше везде использовать юникод-строки, а то мало ли. Например:

dictionaries = {
    u"НАЗВАНИЕ_СЛОВАРЯ": [u"значение1", u"значение2", ...]
}

Пример использования есть выше.

Список зарезервированных терминалов и нетерминалов

Символ Значение
Word Любое слово
noun Существительное
adj Прилагательное
verb Глагол
pr Причастие
dpr Деепричастие
num Числительное (или число)
adv Наречие
pnoun Местоимение
prep Предлог
conj Союз
prcl Частица
lat Слово на латинице

Список лейблов

Лейблами можно задавать ограничения или сочетаемость слов. Заметьте, что лейблы могут сильно повлиять на производительность, если применять их к слишком широким по значению (не)терминалам. Не увлекайтесь. Лейблы всегда проверяются только на этапе свертки, если вы понимаете о чем я.

Символ Значение
gram Слово имеет какое-то грамматическое свойство, например определенный падеж. Пример: adj<gram=gent> — прилагательное в родительном падеже.
reg-l-all Все буквы в слове нижнего регистра. Пример: noun<reg-l-all> - существительное, все буквы маленькие.
reg-h-first Первая буква - заглавная. Пример: noun<reg-h-first> - существительное с заглавной буквы.
reg-h-all Все буквы заглавные (капс). Пример аналогичен предыдущим.
agr-gnc Согласование по роду, числу, падежу (gender, number, case). Пример: adj<arg-gnc=1> noun - прилагательное согласуется со следующим за ним существительным по роду, числу, падежу. Обратите внимание, цифра указывает с каким по счету словом от этого сравнивать (возможно и отрицательное значение).
agr-nc По числу и падежу (number, case). Пример аналогичен.
agr-c По падежу (case).
agr-gn По роду и числу (gender, number).
agr-gc По роду и падежу (gender, case).
regex Слово удовлетворяет регулярному выражению. Пример: word<regex=[0-9]+>.

Можно указывать сразу по нескольку лейблов через запятую. Например noun<reg-l-all, gram=nomn> — существительное в именительном падеже, все буквы которого в нижнем регистре.

Если нужно указать несколько значений одного лейбла, это можно делать так: <gram=nomn, gram=masc> (слово мужского рода в именительном падеже).

Список грамматических категорий см. в доке pymorphy2: https://pymorphy2.readthedocs.org/en/latest/user/grammemes.html

More Repositories

1

btt-touchbar-presets

BetterTouchTool Touch Bar Presets
AppleScript
1,837
star
2

vas3k.club

No bullshit IT community with private membership
Python
809
star
3

infomate.club

RSS feed aggregator with collections and NLP article summarization
Python
445
star
4

GodMode2

Semi-automatic admin site generator for any SQL database
CSS
272
star
5

vas3k.blog

My blog codebase
Python
124
star
6

home-assistant-berlin-transport

Berlin (BVG) and Brandenburg (VBB) transport widget for Home Assistant
Python
114
star
7

pepic

Image and video proxy for my pet-projects
Go
90
star
8

stuff

Jupyter Notebook
44
star
9

i.vas3k.ru

One-page script for easy uploading, resizing and inserting pictures to blog
Python
17
star
10

poor-python-yandex-tomita-parser

Простая обертка на языке Python для яндексового Tomita Parser'а (больше не нужна, Яндекс открыл исходники)
Python
17
star
11

player.vas3k.ru

Open online music player with last.fm scrobbling
JavaScript
17
star
12

GodMode

Automatic admin interface for MySQL, PostgreSQL, MongoDB, etc
CSS
15
star
13

valyrics

Spotify and iTunes lyrics widget for Notification Center
Swift
13
star
14

lovelace-berlin-transport-card

Lovelace card for https://github.com/vas3k/home-assistant-berlin-transport
11
star
15

NGTMap

iOS-приложение для мониторинга общественного транспорта Новосибирска
Objective-C
7
star
16

geektool-gismeteo-parser

Parse gismeteo.ru and display current weather in you GeekTool app
Python
5
star
17

vas3k

Jupyter Notebook
4
star
18

FormValidator

Pure client-side javascript form validator
JavaScript
4
star
19

l100n

Unusual JavaScript library for pure client-side localization by css-selectors
JavaScript
3
star
20

loggy

Неудавшаяся попытка сделать Sentry. Сдохла.
Python
1
star