# Однако есть много городов, которых нет в списке, их нужно попытаться обработать # Названиями могут быть существительные и прилагательные, регистр мне не будет важен # Пример: Инженерный, Сургут (которого реально нет в списках сверху) CITY_PROBABLY = or_( NOUN, ADJF ).interpretation( City.name ) # Готовим варианты ключего слова CITY_KEYWORD = or_( rule(normalized('город')), rule( caseless('г'), DOT.optional() ) ).interpretation( City.city_type.const('город') ) # Два основных условия: либо слово из списков назаний, тогда "ключ" не важен # Или мы считаем названием города сущ. или прил. с "ключом" # Поскольку "ключ" во втором случае не опционале, то регистр не так важен CITY = or_( rule(CITY_KEYWORD, CITY_PROBABLY), rule(CITY_KEYWORD.optional(), CITY_NAME) ).interpretation( City )
############ FED_OKRUG_NAME = or_( rule( dictionary({ 'дальневосточный', 'приволжский', 'сибирский', 'уральский', 'центральный', 'южный', }) ), rule( caseless('северо'), DASH.optional(), dictionary({ 'западный', 'кавказский' }) ) ).interpretation( Region.name ) FED_OKRUG_WORDS = or_( rule( normalized('федеральный'), normalized('округ') ),
# coding: utf-8 from __future__ import unicode_literals from yargy import (rule, and_, or_, fact) from yargy.predicates import (eq, in_, gram, normalized, caseless) Money = fact('Money', ['amount', 'currency']) EURO = normalized('евро') DOLLARS = or_(normalized('доллар'), eq('$')) RUBLES = or_(rule(normalized('рубль')), rule(or_(caseless('руб'), caseless('р')), eq('.').optional())) CURRENCY = or_(rule(EURO), rule(DOLLARS), RUBLES).interpretation(Money.currency) INT = gram('INT') AMOUNT_ = or_( rule(INT), rule(INT, INT), rule(INT, INT, INT), rule(INT, '.', INT), rule(INT, '.', INT, '.', INT), ) FRACTION_AMOUN = rule(AMOUNT_, in_({',', '.'}), INT)
'data scientist', 'data engineer', 'engineer', 'analyst', 'data analyst', 'data manager', 'scientist', 'researcher', "developer", "intern" ]), rule(dictionary(['DS', 'DE']), is_capitalized()), morph_pipeline(["аналитик", "разработчик", "стажер"])).interpretation(Position.name.inflected())) FIELD = rule( caseless_pipeline([ 'ML', 'DL', 'CV', 'computer vision', 'NLP', 'bi', 'machine learning', 'deep learning', 'software', 'research', 'big data', 'python', 'c++', "scala", "java", 'ios', "android", 'devops', "backend", 'frontend' ]).interpretation(Position.field)) HEAD = rule( caseless('head').interpretation(Position.level), eq('of'), caseless_pipeline(['analytics', 'predictive analytics', 'data science']).interpretation(Position.field)) POSITION = or_( rule(LEVEL.optional(), FIELD.optional(), eq('-').optional(), NAME), HEAD).interpretation(Position) # TODO: нужен метод extract с фильтрацией. Например, разбирать возможные ложные срабатывания ("аналитика"), # фильтровать по длине (чем больше полей заполнено, тем предпочтительнее) # можно выдавать "аналитик" только тогда, когда ничего более конкретного не нашлось class PositionExtractor(Extractor): def __init__(self): super(PositionExtractor, self).__init__(POSITION)
'шестьсот': 600, 'семьсот': 700, 'восемьсот': 800, 'девятьсот': 900, 'тысяча': 10**3, 'миллион': 10**6, 'миллиард': 10**9, 'триллион': 10**12, } DOT = eq('.') INT = type('INT') THOUSANDTH = rule(caseless_pipeline(['тысячных', 'тысячная'])).interpretation(const(10**-3)) HUNDREDTH = rule(caseless_pipeline(['сотых', 'сотая'])).interpretation(const(10**-2)) TENTH = rule(caseless_pipeline(['десятых', 'десятая'])).interpretation(const(10**-1)) THOUSAND = or_( rule(caseless('т'), DOT), rule(caseless('тыс'), DOT.optional()), rule(normalized('тысяча')), rule(normalized('тыща')) ).interpretation(const(10**3)) MILLION = or_( rule(caseless('млн'), DOT.optional()), rule(normalized('миллион')) ).interpretation(const(10**6)) MILLIARD = or_( rule(caseless('млрд'), DOT.optional()), rule(normalized('миллиард')) ).interpretation(const(10**9)) TRILLION = or_( rule(caseless('трлн'), DOT.optional()), rule(normalized('триллион'))
# #in_(['€', 'EUR']) # eq('€'), # #eq('EUR') # ).interpretation( # const(dsl.EURO) # ) # EURO = caseless_pipeline(['евро', '€', 'eur'])#.interpretation(const(dsl.EURO)) EURO = or_(normalized('евро'), eq('€'), eq('EUR')).interpretation(const(dsl.EURO)) DOLLARS = or_(normalized('доллар'), eq('$'), eq('USD')).interpretation(const(dsl.DOLLARS)) RUBLES = or_( rule(normalized('рубль')), rule(or_(caseless('руб'), caseless('р'), eq('₽')), DOT.optional())).interpretation(const(dsl.RUBLES)) CURRENCY = or_(EURO, DOLLARS, RUBLES).interpretation(Money.currency) # TODO: копейки и центы тоже можно выпилить для ускорения KOPEIKA = or_(rule(normalized('копейка')), rule(or_(caseless('коп'), caseless('к')), DOT.optional())) CENT = or_(normalized('цент'), eq('¢')) EUROCENT = normalized('евроцент') COINS_CURRENCY = or_(KOPEIKA, rule(CENT), rule(EUROCENT)) ############ #
from yargy import or_, rule from yargy.interpretation import attribute, fact import yargy.interpretation as meaning from yargy.pipelines import morph_pipeline from yargy.predicates import caseless, gram, normalized from .common import Array # Working = fact('Working', [attribute('to', default=[])]) Type = fact('Type', [attribute('value', default=[]), 'status', attribute('inversed', default=False)]) ENTER_EXIT_WORD = rule( or_(caseless('на'), caseless('для')).optional(), morph_pipeline(['вход', 'выход']).interpretation(Type.value), ).interpretation(Type) # и на вход и на выход ON_ENTER_AND_EXIT = rule( caseless('и').optional(), ENTER_EXIT_WORD .interpretation(meaning.custom(lambda p: p.value)) .interpretation(Array.element), # caution: misses comma, I don't know why rule( caseless('и').optional(), ENTER_EXIT_WORD .interpretation(meaning.custom(lambda p: p.value)) .interpretation(Array.element), ).optional(), ).interpretation(Array)
'восемьсот': 800, 'девятьсот': 900, 'тысяча': 10**3, 'миллион': 10**6, 'миллиард': 10**9, 'триллион': 10**12, } DOT = eq('.') INT = type('INT') THOUSANDTH = rule(caseless_pipeline(['тысячных', 'тысячная' ])).interpretation(const(10**-3)) HUNDREDTH = rule(caseless_pipeline(['сотых', 'сотая'])).interpretation(const(10**-2)) TENTH = rule(caseless_pipeline(['десятых', 'десятая'])).interpretation(const(10**-1)) THOUSAND = or_(rule(caseless('т'), DOT), rule(caseless('тыс'), DOT.optional()), rule(normalized('тысяча')), rule(normalized('тыща'))).interpretation(const(10**3)) MILLION = or_(rule(caseless('млн'), DOT.optional()), rule(normalized('миллион'))).interpretation(const(10**6)) MILLIARD = or_(rule(caseless('млрд'), DOT.optional()), rule(normalized('миллиард'))).interpretation(const(10**9)) TRILLION = or_(rule(caseless('трлн'), DOT.optional()), rule(normalized('триллион'))).interpretation(const(10**12)) MULTIPLIER = or_(THOUSANDTH, HUNDREDTH, TENTH, THOUSAND, MILLION, MILLIARD, TRILLION).interpretation(Number.multiplier) NUM_RAW = rule( morph_pipeline(NUMS_RAW).interpretation(Number.int.normalized().custom( NUMS_RAW.get))) NUM_INT = rule(INT).interpretation(Number.int.custom(int)) NUM = or_(NUM_RAW, NUM_INT).interpretation(Number.int)
from yargy import or_, rule from yargy.interpretation import fact from yargy.predicates import caseless, gram from notebook.common import gnc from notebook.time import TIME Duration = fact('Duration', ['since', 'to']) FROM = rule( or_(caseless('от'), caseless('с')), TIME.means(Duration.since), ) UNTIL_PREP = or_(caseless('до'), caseless('по')) UNTIL_TIME = rule( UNTIL_PREP, TIME.means(Duration.to), ) UNTIL_WORD = rule( UNTIL_PREP, or_( gram('ADJF'), gram('NOUN'), ).match(gnc).repeatable(max=4)).means(Duration.to) DURATION = or_(rule(FROM, UNTIL_WORD.optional()), rule( FROM.optional(),
EURO = or_( normalized('евро'), eq('€') ) DOLLARS = or_( normalized('доллар'), eq('$') ) RUBLES = or_( rule(normalized('рубль')), rule( or_( caseless('руб'), caseless('р'), eq('₽') ), eq('.').optional() ) ) CURRENCY = or_( rule(EURO), rule(DOLLARS), RUBLES ).interpretation( Money.currency )
HOUR.interpretation(HourAndMinute.hour), HOUR_MINUTE_SEPARATOR.optional(), MINUTE.interpretation(HourAndMinute.minute), ).interpretation(HourAndMinute) TIME = or_( HOUR_AND_MINUTE.interpretation(Time.time), HOUR.interpretation(Time.time), MINUTE.interpretation(Time.time), ).interpretation(Time) # date DAY = or_(rule(and_(gte(1), lte(31)))).interpretation(Date.day.custom(to_int)) MONTH = and_(gte(1), lte(12)).interpretation(Date.month.custom(to_int)) YEAR = and_(gte(1), lte(2099)).interpretation(Date.year.custom(to_int)) YEAR_WORDS = or_(rule(caseless("г"), "."), rule(normalized("год"))) MONTH_NAME = dictionary(MONTHS).interpretation(Date.month.normalized().custom( MONTHS.__getitem__)) DATE = or_( rule(YEAR, DATE_SEPARATOR, MONTH, DATE_SEPARATOR, DAY), rule(DAY, DATE_SEPARATOR, MONTH_NAME, DATE_SEPARATOR, YEAR.optional(), YEAR_WORDS.optional()), rule(DAY, DATE_SEPARATOR, MONTH, DATE_SEPARATOR, YEAR.optional(), YEAR_WORDS.optional()), rule(DAY, MONTH_NAME, YEAR.optional(), YEAR_WORDS.optional()), ).interpretation(Date) DAYNAME = dictionary(DAYS).interpretation( DayName.name.normalized().custom(day)) AT = or_(rule("в"), rule("во"))
REGION = rule( gram('ADJF').match(gnc), dictionary({ 'край', 'район', 'область', 'губерния', 'уезд', }), ).interpretation(Location.name.inflected()) gnc1 = gnc_relation() gnc2 = gnc_relation() FEDERAL_DISTRICT = rule( rule(caseless('северо'), '-').optional(), dictionary({ 'центральный', 'западный', 'южный', 'кавказский', 'приволжский', 'уральский', 'сибирский', 'дальневосточный', }).match(gnc1), or_( rule( dictionary({'федеральный'}).match(gnc1, gnc2), dictionary({'округ'}).match(gnc2), ),
'винзавод', 'подстанция', 'гидроэлектростанция', ]) gnc = gnc_relation() ADJF_PREFIX = rule( or_( rule(gram('ADJF').match(gnc)), # международное rule( # историко-просветительское true(), eq('-'), gram('ADJF').match(gnc), ), ), or_(caseless('и'), eq(',')).optional(), ).repeatable() case = case_relation() GENT_GROUP = rule( gram('gent').match(case) ).repeatable().optional() QUOTED = rule( TYPE, in_(QUOTES), not_(in_(QUOTES)).repeatable(), in_(QUOTES), ) TRIPLE_QUOTED = rule(
'коллектив', 'правление', 'совет', ] gnc = gnc_relation() ADJF_PREFIX = rule( or_( rule(gram('ADJF').match(gnc)), # международное rule( # историко-просветительское true(), eq('-'), gram('ADJF').match(gnc), ), ), or_(caseless('и'), eq(',')).optional(), ).repeatable() case = case_relation() GENT_GROUP = rule( gram('gent').match(case) ).repeatable().optional() QUOTED = rule( gram('OrganisationType'), gram('QUOTE'), not_( or_( gram('QUOTE'), gram('END-OF-LINE'), )).repeatable(),
or_( or_( gram('PREP'), gram('Vpre'), gram('CONJ'), gram('PRCL'), gram('INTJ'), ), gram('POST'), ).optional()) case = case_relation() GENT_GROUP = rule(gram('gent').match(case)).repeatable().optional() #ADJF ADJF_PREFIX_COUNTABLE = rule(or_(caseless('и'), eq(',')).optional(), ).repeatable() ADJF_PREFIX_ADJF = and_(ADJF, TITLE).repeatable() ADJF_PREFIX = rule( ADJF_PREFIX_ADJF, ADJF.optional(), #Киевском государственном университете ADJF_PREFIX_COUNTABLE).repeatable() # ### ### 1-ST RING RULES R1_SIMPLE = rule(EDUORGANISATION_DICT, ).repeatable() gnc = gnc_relation()
or_(eq('врид'), eq('врио')).optional(), or_(rule('пом', DOT.optional()), rule('зам', DOT.optional()), rule('ст', DOT.optional()), rule(dictionary({'заместитель'}))).optional(), normalized('полковой').optional(), or_( rule('сотр', DOT.optional()), rule( dictionary({ 'оперуполномоченный', 'сотрудник', 'командир', 'уполномоченный', 'шофер', 'следователь', 'наркома', 'работник', 'инспектор', 'комендант', 'разведчик', 'начальник', 'секретарь', 'особоуполномоченный', 'председатель', 'фельдъегерь', 'сотрудница', 'лейтенант', 'референт', 'слушатель', 'руководитель', 'переводчик', 'управляющий' })), rule(caseless('нач'), DOT), rule(normalized('министра'), 'внутренних', 'дел')), or_(rule(eq('контрразведки')), rule(eq('особой'), eq('роты'))).optional()) pos_parser = Parser(POSITION) def parse(d): for match in pos_parser.findall(d): b, e = match.tokens[0].span[0], match.tokens[-1].span[1] return d[b:e], d[e + 1:] return '', '' # POSITION = rule( # eq('врид').optional(),
# # FED OKRUGA # ############ FED_OKRUG_NAME = or_( rule( dictionary({ 'дальневосточный', 'приволжский', 'сибирский', 'уральский', 'центральный', 'южный', })), rule(caseless('северо'), DASH.optional(), dictionary({'западный', 'кавказский'}))).interpretation(Region.name) FED_OKRUG_WORDS = or_(rule(normalized('федеральный'), normalized('округ')), rule(caseless('фо'))).interpretation( Region.type.const('федеральный округ')) FED_OKRUG = rule(FED_OKRUG_WORDS, FED_OKRUG_NAME).interpretation(Region) ######### # # RESPUBLIKA # ############ RESPUBLIKA_WORDS = or_(rule(caseless('респ'), DOT.optional()),
or_( or_( gram('PREP'), gram('Vpre'), gram('CONJ'), gram('PRCL'), gram('INTJ'), ), gram('POST'), ).optional()) case = case_relation() GENT_GROUP = rule(gram('gent').match(case)).repeatable().optional() #ADJF ADJF_PREFIX_COUNTABLE = rule(or_(caseless('и'), eq(',')).optional(), ) ADJF_PREFIX_ADJF = and_(ADJF, TITLE).repeatable() ADJF_NORM = rule( and_(ADJF, custom(lambda s: EDUORG_DICT_REGEXP.search(s), types=(str)))).repeatable() ADJF_PREFIX = rule( ADJF_PREFIX_ADJF, ADJF.optional(), #Киевском государственном университете ADJF_PREFIX_COUNTABLE).repeatable() # ### ### 1-ST RING RULES
).interpretation( const(dsl.EURO) ) DOLLARS = or_( normalized('доллар'), eq('$') ).interpretation( const(dsl.DOLLARS) ) RUBLES = or_( rule(normalized('рубль')), rule( or_( caseless('руб'), caseless('р'), eq('₽') ), DOT.optional() ) ).interpretation( const(dsl.RUBLES) ) CURRENCY = or_( EURO, DOLLARS, RUBLES ).interpretation( Money.currency
from yargy import or_, rule from yargy.interpretation import attribute, fact import yargy.interpretation as meaning from yargy.predicates import caseless, eq, in_, in_caseless, normalized from .common import Array from .literal import LIST_OF_NUMERALS from .station_title import STATION_TITLE Station = fact('Station', ['name', attribute('num', default=[])]) STATION_WORD = or_( rule(caseless('ст'), '.'), rule(normalized('станция')), ) METRO_WORD = or_( rule(caseless('м'), '.'), rule(normalized('метро')), ) __quotes = "„“”‚‘’'\"" LEFT_QUOTE = in_("«" + __quotes) RIGHT_QUOTE = in_("»" + __quotes) STATION = rule( STATION_WORD.optional(), METRO_WORD.optional(), LEFT_QUOTE.optional(), STATION_TITLE.interpretation( meaning.custom(lambda p: p.value)).interpretation(Station.name),
from yargy import or_, rule from yargy.interpretation import attribute, fact import yargy.interpretation as meaning from yargy.predicates import caseless, gram, in_caseless, normalized from .station import FROM_STATION_TO_STATION, LIST_OF_STATIONS, STATION Transfer = fact('Transfer', [attribute('to', default=[])]) TRANSFER = rule( gram('ADJF').optional(), # пешеходный normalized('переход'), or_( FROM_STATION_TO_STATION.interpretation(Transfer.to), rule( or_(caseless('на'), caseless('между'), caseless('с')).optional(), LIST_OF_STATIONS.interpretation(Transfer.to)), ).optional(), ).interpretation(Transfer) StationAndTransfer = fact('StationAndTransfer', ['station', 'transfer']) STATION_AND_TRANSFER = rule( STATION.interpretation(StationAndTransfer.station), rule( in_caseless('и,'), TRANSFER.interpretation(meaning.custom(lambda p: p.to)).interpretation( StationAndTransfer.transfer), ).optional()).interpretation(StationAndTransfer)
attribute('currency', '-'), attribute('multiplier', -1), attribute('period', '-') ]) DOT = eq('.') INT = type('INT') ######## # # CURRENCY # ########## EURO = or_(normalized('евро'), normalized('euro'), eq('€'), caseless('EUR')).interpretation(const('EUR')) DOLLARS = or_(normalized('доллар'), normalized('дол'), normalized('dollar'), eq('$'), caseless('USD')).interpretation(const('USD')) RUBLES = or_( rule(normalized('ruble')), rule(normalized('рубль')), rule(normalized('рубл')), rule( or_( caseless('руб'), caseless('rub'), # caseless('rur'), caseless('р'), eq('₽')),
is_minute = custom(minute_re.fullmatch).activate(TOKENIZER) HOUR_UNIT = rule(morph_pipeline(['ч', 'час', 'часы']), eq('.').optional()) MINUTE_UNIT = rule(morph_pipeline(['м', 'мин', 'минуты']), eq('.').optional()) # 17:02 ч. TIME_DIGITAL = rule( is_hour.means(Time.hours), in_(':-.'), is_minute.means(Time.minutes), or_(HOUR_UNIT, MINUTE_UNIT).optional(), ).means(Time) # 17ч 02 TIME_HUMAN = rule( is_hour.means(Time.hours), HOUR_UNIT, is_minute.means(Time.minutes), MINUTE_UNIT.optional(), ).means(Time) # в 15:00 TIME = rule(caseless('в').optional(), or_( TIME_DIGITAL, TIME_HUMAN, )).means(Time) if __name__ == '__main__': print(sys.argv)
############ FED_OKRUG_NAME = or_( rule( dictionary({ 'дальневосточный', 'приволжский', 'сибирский', 'уральский', 'центральный', 'южный', }) ), rule( caseless('северо'), DASH.optional(), dictionary({ 'западный', 'кавказский' }) ) ).interpretation( Region.name ) FED_OKRUG_WORDS = or_( rule( normalized('федеральный'), normalized('округ') ),
REGION = rule( gram('ADJF').match(gnc), dictionary({ 'край', 'район', 'область', 'губерния', 'уезд', }).match(gnc), ).interpretation(Location.name.inflected()) gnc = gnc_relation() FEDERAL_DISTRICT = rule( rule(caseless('северо'), '-').optional(), dictionary({ 'центральный', 'западный', 'южный', 'кавказский', 'приволжский', 'уральский', 'сибирский', 'дальневосточный', }).match(gnc), or_( rule( dictionary({'федеральный'}).match(gnc), dictionary({'округ'}).match(gnc), ),
REGION = rule( gram('ADJF').match(gnc), dictionary({ 'край', 'район', 'область', 'губерния', 'уезд', }).match(gnc), ).interpretation(Location.name.inflected()) gnc1 = gnc_relation() gnc2 = gnc_relation() FEDERAL_DISTRICT = rule( rule(caseless('северо'), '-').optional(), dictionary({ 'центральный', 'западный', 'южный', 'кавказский', 'приволжский', 'уральский', 'сибирский', 'дальневосточный', }).match(gnc1), or_( rule( dictionary({'федеральный'}).match(gnc1, gnc2), dictionary({'округ'}).match(gnc2), ),
from natasha.grammars.date import DATE Metro = fact('Metro', ['name', 'type']) Address = fact('Address', [attribute('parts').repeatable()]) METRO_STATIONS = rule( morph_pipeline({ 'Автозаводская', 'Щукинская', 'Академическая', 'Электрозаводская', 'Александровский сад', 'Юго-Западная', 'Алексеевская', 'Южная', 'Алма-Атинская', 'Ясенево' })) METRO_WORDS = or_( rule(normalized('метро')), rule(caseless('м'), DOT.optional()), ).interpretation(Metro.type.const('метро')) METRO = or_(rule(METRO_WORDS.optional(), METRO_STATIONS), rule(METRO_STATIONS, METRO_WORDS.optional())).interpretation(Metro) STREET_LEVEL.rules.append(METRO) ADDRESS.rule = rule( rule(PRE_STREET_LEVEL.interpretation(Address.parts), SEP.optional()).optional().repeatable(), STREET_LEVEL.interpretation(Address.parts), rule(SEP.optional(), DOM.interpretation(Address.parts)).optional(), rule(SEP.optional(), POST_STREET_LEVEL.interpretation( Address.parts)).optional().repeatable(), ).interpretation(Address)