morph_generation.py 19.5 KB
import morfeusz2

morfeusz = morfeusz2.Morfeusz(generate=True, analyse=False, expand_tags=True)

LEMMA_KILL_LIST = {
    'oko:s1', 'ucho:s1',                         # ~a
    'łeb:s2', 'powód:s2',                        # ~owie
    'lew:s1',                                    # ~owi
    'paragraf:s1', 'sen:s2', 'lot:s2', 'lód:s2', # ~a
    'bat:s2', 'żywot:s2',                        # ~u
    # fikać kozły, spuszczać basałyki
    'kozioł:s3', 'basałyk:s1',                   # ~ów
    # ciągnąć druta, fiknąć kozła/koziołka, puścić kura, spiąć muła, popuścić pasa, zapuścić żurawia
    'drut:s1', 'drut:s2', 'kozioł:s1', 'koziołek:s1', 'kur:s1', 'muł:s1', 'pas:s2', 'pas:s3', 'żuraw:s2', # ~-
    # m1:
    'as:s2', 'baba:s2', 'biegun:s2', 'bzik:s2', 'fioł:s1', 'jeleń:s2', 'kułak:s1', 'lamus:s2', 'lis:s2', 'nurek:s1', 'osioł:s2', 'orzeł:s2',
    'szach:s2', 'admirał:s2', 'bęben:s2', 'głup:s2', 'kasztan:s2', 'król:s1', 'kurek:s2', 'młot:s2', 'pajac:s1', 'pion:s2',
    # m2:
    'płaz:s2', 'szatan:s1',                                                                                              
    'Abraham:s2', 'Abraham:s3', 'Grek:s2', 'Grek:s3', 'Kajfasz:s2', 'Kajfasz:s3', 'Marek:s2', 'Polak:s3', 'Polska:s2',
    'Wisła:s2', 'Wisła:s3', 'Zawisza:s2',  # nazwiska (w tym żeńskie)
    'Marcin:s2',           # człon nazwy geogr.
    'galop:s2',            # chor.
    'profit:s2',           # karc.
    'jeż:s2', 'kaduk:s1', 'smok:s2', 'ślimak:s2', # m3
    'kapitan:s3',          # f
    'pewny:a2',            # :a1: only ‘pewny’
    'dziób:s2',            # żegl.
    'mat:s3', 'mat:s1',    # mors., matowy
    'as:s3', 'as:s4',      # hist., muz.
    'przenosić:v2',
    'kasztan:s4',
    'stać:v4',             # perf
    'wpaść:v2',            # wpasie
    'należeć:v2',          # perf (należał się w łóżku)
}
FORM_KILL_LIST = (
    ('amen', 'amen:s', 'subst:sg:nom:n:ncol', ['nazwa_pospolita'], []),                       # m3
    ('amen', 'amen:s', 'subst:sg:acc:n:ncol', ['nazwa_pospolita'], []),
    ('Amora', 'Amor', 'subst:sg:gen:m2', ['imię'], ['mit.']),                                 # m1
    ('aniołków', 'aniołek', 'subst:pl:gen:m1', ['nazwa_pospolita'], []),                      # m2
    ('aniołów', 'anioł', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                         # m1
    ('awansy', 'awans', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                          # awanse
    ('bambusa', 'bambus:s1', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                     # w bambus
    ('blues', 'blues', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                           # bluesa
    ('bogowi', 'bóg', 'subst:sg:dat:m1', ['nazwa_pospolita'], []),                            # bogu
    ('burak', 'burak:s1', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['bot.']),                  # m3
    ('całuski', 'całusek', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                       # m3
    ('całusków', 'całusek', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                      # m3
    ('chujów', 'chuj:s1', 'subst:pl:acc:m1', ['nazwa_pospolita'], ['wulg.']),                 # obciągać chuje
    ('cudy', 'cud', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                              # wyczyniać cuda
    ('czartem', 'czart', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                        # m1
    ('czole', 'czoło:s2', 'subst:sg:loc:n:ncol', ['nazwa_pospolita'], []),                    # postawić na czele
    ('czort', 'czort', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['pot.']),                     # m1
    ('diabeł', 'diabeł', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabła', 'diabeł', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabła', 'diabeł', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabłami', 'diabeł', 'subst:pl:inst:m2', ['nazwa_pospolita'], []),                      # m1
    ('diabłem', 'diabeł', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                       # m1
    ('diabłu', 'diabeł', 'subst:sg:dat:m2', ['nazwa_pospolita'], []),                         # m1
    ('diabłów', 'diabeł', 'subst:pl:acc:m1', ['nazwa_pospolita'], []),                        # w diabły
    ('diabłów', 'diabeł', 'subst:pl:gen:m2', ['nazwa_pospolita'], []),                        # m1
    ('diabły', 'diabeł', 'subst:pl:nom:m2', ['nazwa_pospolita'], []),                         # diabli wiedzą
    ('drapak', 'drapak:s1', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                      # dać drapaka
    ('dwu', 'dwa', 'num:pl:loc:f:congr:ncol', [], []),                                        # dwóch
    ('dwu', 'dwa', 'num:pl:acc:m1:rec:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:m1:rec:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:inst:m3:congr:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:m3:congr:ncol', [], []),
    ('dwu', 'dwa', 'num:pl:loc:n:congr:ncol', [], []),
    ('dzióba', 'dziób:s1', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                       # dzioba
    ('dzióbach', 'dziób:s1', 'subst:pl:loc:m3', ['nazwa_pospolita'], []),                     # dziobach
    ('dzióbem', 'dziób:s1', 'subst:sg:inst:m3', ['nazwa_pospolita'], []),                     # dziobem
    ('figiel', 'figiel', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                         # figla
    ('garba', 'garb', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                            # wziąć sobie garb na plecy
    ('gąsiora', 'gąsior:s2', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                     # osuszać gąsior
    ('głąba', 'głąb:s1', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                         # uciec w głąb
    ('grzybki', 'grzybek', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                       # m3
    ('grzyby', 'grzyb:s1', 'subst:pl:nom:m2', ['nazwa_pospolita'], ['mikol.']),               # m3
    ('guz', 'guz', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                               # guza
    ('guza', 'guz', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                              # m3
    ('kaduk', 'kaduk:s2', 'subst:sg:nom:m2', ['nazwa_pospolita'], ['przest.']),               # m1
    ('kopniak', 'kopniak', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                       # kopniaka
    ('kloc', 'kloc:s1', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                          # walnąć kloca
    ('klin', 'klin:s1', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                          # klina
    ('klina', 'klin:s2', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                         # m3
    ('klinem', 'klin:s2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                       # m3
    ('kilku', 'kilka:n', 'num:pl:inst:m3:congr:ncol', [], []),                                # kilkoma
    ('kosz', 'kosz:s1', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                          # kosza
    ('kosza', 'kosz:s1', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                         # TODO do usunięcia po poprawce?
    ('koszu', 'kosz:s2', 'subst:sg:loc:m2', ['nazwa_pospolita'], []),                         # m3
    ('koszty', 'koszt', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                          # koszta
    ('krzaku', 'krzak', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # krzaka
    ('krzyw', 'krzywy', 'adj:sg:nom:m1:pos', [], []),                                         # krzywy
    ('marsz', 'marsz:s2', 'subst:sg:acc:m3', ['nazwa_pospolita'], ['muz.']),                  # grać marsza
    ('nieciekaw', 'nieciekawy', 'adj:sg:nom:m1:pos', [], []),                                 # nieciekawy
    ('nic', 'nic', 'subst:sg:gen:n:ncol', [], []),                                            # niczego
    ('obydwóch', 'obydwa', 'num:pl:loc:f:congr:ncol', [], []),                                # obydwu
    ('obydwóch', 'obydwa', 'num:pl:loc:n:congr:ncol', [], []),
    ('odtchu', 'oddech', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                         # od-tchu ;)
    ('oczyma', 'oko:s2', 'subst:pl:inst:n:col', ['nazwa_pospolita'], ['anat.']),              # oczami
    ('oczów', 'oko:s2', 'subst:pl:gen:n:col', ['nazwa_pospolita'], ['anat.']),                # oczu
    ('otworzoną', 'otworzyć', 'ppas:sg:inst:f:perf:aff', [], []),                             # otwartą
    ('otworzony', 'otworzyć', 'ppas:sg:nom:m1:perf:aff', [], []),                             # otwarty
    ('paru', 'parę', 'num:pl:inst:m3:congr', [], []),                                         # paroma
    ('pasjanse', 'pasjans', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                      # pasjanse m3
    ('pasjansy', 'pasjans', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),
    ('pasjansy', 'pasjans', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),
    ('pełen', 'pełny', 'adj:sg:nom:m1:pos', [], []),                                          # pełny
    ('podobien', 'podobny', 'adj:sg:nom:m1:pos', [], []),                                     # podobny
    ('policzeki', 'policzek', 'subst:pl:nom:m3', ['nazwa_pospolita'], []),                    # poli-czeki ;)
    ('procha', 'proch', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                          # prochu
    ('procenta', 'procent', 'subst:sg:acc:m2', ['nazwa_pospolita'], ['monet.']),              # na procent
    ('procentem', 'procent', 'subst:sg:inst:m2', ['nazwa_pospolita'], ['monet.']),            # m3
    ('proces', 'proces', 'subst:pl:acc:n:ncol', ['nazwa_pospolita'], ['muz.']),               # m3
    ('profity', 'profit:s1', 'subst:pl:acc:m2', ['nazwa_pospolita'], []),                     # m3
    ('rażony', 'razić', 'ppas:sg:nom:m1:imperf:aff', [], []),                                 # perf (jak rażony piorunem)
    ('ręku', 'ręka', 'subst:sg:loc:m3', ['nazwa_pospolita'], ['anat.']),                      # ręce
    ('rękoma', 'ręka', 'subst:pl:inst:f', ['nazwa_pospolita'], ['anat.']),                    # rękami
    ('rówien', 'równy', 'adj:sg:nom:m1:pos', [], []),                                         # równy
    ('rynsztoku', 'rynsztok', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # rynsztoka
    ('rzeknąć', 'rzec:v2', 'inf:perf', [], []),                                               # rzec
    ('rządu', 'rząd:s1', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                         # rosnąć do rzędu czegoś
    ('rzędów', 'rząd:s2', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                        # objąć ster rządów
    ('rzędy', 'rząd:s2', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                         # objąć rządy
    ('steka', 'stek:s1', 'subst:sg:acc:m2', ['nazwa_pospolita'], []),                         # wysmażyć stek
    ('strach', 'strach:s2', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                      # m3 (strach obleciał)
    ('stracha', 'strach:s2', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                     # napędzić stracha/strachu, ale umrzeć ze strachu
    ('strachu', 'strach:s2', 'subst:sg:loc:m2', ['nazwa_pospolita'], []),                     # m3
    ('syfon', 'syfon:s1', 'subst:sg:acc:m3', ['nazwa_pospolita'], []),                        # dać syfona
    ('szatan', 'szatan:s2', 'subst:sg:nom:m2', ['nazwa_pospolita'], []),                      # m1
    ('szatanem', 'szatan:s2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                   # m1
    ('szeląga', 'szeląg', 'subst:sg:gen:m2', ['nazwa_pospolita'], []),                        # m3                
    ('szmerglu', 'szmergiel', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                    # szmergla
    ('śmiecie', 'śmieć:s1', 'subst:pl:acc:m3', ['nazwa_pospolita'], []),                      # śmieci
    ('usty', 'usta', 'subst:pl:inst:n:pt', ['nazwa_pospolita'], ['przest.']),                 # ustami
    ('woru', 'wór', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                              # wora
    ('zwierzę', 'zwierzę', 'subst:sg:nom:n:ncol', ['nazwa_pospolita'], []),                   # col
    ('zwierzę', 'zwierzę', 'subst:sg:acc:n:ncol', ['nazwa_pospolita'], []),
    ('żłobu', 'żłób:s2', 'subst:sg:gen:m3', ['nazwa_pospolita'], []),                         # dopchać się do żłoba
    ('żurnalów', 'żurnal', 'subst:pl:gen:m3', ['nazwa_pospolita'], []),                       # żurnali
    ('żywcem', 'żywiec:s2', 'subst:sg:inst:m2', ['nazwa_pospolita'], []),                     # m3
    
    ('swe', 'swój', 'adj:sg:acc:n:pos', [], []),                                # dostać za swoje
    ('swym', 'swój', 'adj:sg:loc:n:pos', [], []),                               # obstawać przy swoim
    ('swojego', 'swój', 'adj:sg:gen:n:pos', [], []),                            # dopiąć swego
    ('swe', 'swój', 'adj:pl:acc:f:pos', [], []),                                # swoje in adjp(agr)
    ('swe', 'swój', 'adj:pl:acc:m3:pos', [], []),
    ('swe', 'swój', 'adj:sg:nom:n:pos', [], []),
    ('swe', 'swój', 'adj:pl:acc:n:pos', [], []),
    ('swej', 'swój', 'adj:sg:gen:f:pos', [], []),                               # swojej
    ('swej', 'swój', 'adj:sg:loc:f:pos', [], []),
    ('swego', 'swój', 'adj:sg:acc:m1:pos', [], []),                             # swojego
    ('swego', 'swój', 'adj:sg:gen:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:gen:f:pos', [], []),                              # swoich
    ('swych', 'swój', 'adj:pl:loc:f:pos', [], []),
    ('swych', 'swój', 'adj:pl:gen:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:loc:m3:pos', [], []),
    ('swych', 'swój', 'adj:pl:loc:n:pos', [], []),
    ('swym', 'swój', 'adj:pl:dat:m3:pos', [], []),
    ('swym', 'swój', 'adj:sg:loc:m3:pos', [], []),                              # swoim            
    ('swym', 'swój', 'adj:sg:inst:m3:pos', [], []),
    ('swym', 'swój', 'adj:pl:dat:n:pos', [], []),
    ('swym', 'swój', 'adj:sg:inst:n:pos', [], []),
    ('swymi', 'swój', 'adj:pl:inst:f:pos', [], []),                             # swoimi
    ('swymi', 'swój', 'adj:pl:inst:m3:pos', [], []),
    ('swymi', 'swój', 'adj:pl:inst:n:pos', [], []),
    ('swą', 'swój', 'adj:sg:acc:f:pos', [], []),                                # swoją
    ('swą', 'swój', 'adj:sg:inst:f:pos', [], []),
    ('mej', 'mój:a', 'adj:sg:gen:f:pos', [], []),                               # mojej
    ('mej', 'mój:a', 'adj:sg:dat:f:pos', [], []),
    ('mej', 'mój:a', 'adj:sg:loc:f:pos', [], []),
    ('memu', 'mój:a', 'adj:sg:dat:m3:pos', [], []),                             # mojemu
    ('mego', 'mój:a', 'adj:sg:acc:m2:pos', [], []),                             # mojego
    ('mego', 'mój:a', 'adj:sg:gen:m3:pos', [], []),
    ('mego', 'mój:a', 'adj:sg:gen:n:pos', [], []),
    ('mych', 'mój:a', 'adj:pl:loc:n:pos', [], []),                              # moich
    ('me', 'mój:a', 'adj:pl:nom:f:pos', [], []),
    ('me', 'mój:a', 'adj:pl:acc:f:pos', [], []),                                # moje
    ('me', 'mój:a', 'adj:pl:acc:m2:pos', [], []),
    ('me', 'mój:a', 'adj:pl:nom:m3:pos', [], []),
    ('me', 'mój:a', 'adj:pl:acc:m3:pos', [], []),
    ('me', 'mój:a', 'adj:sg:nom:n:pos', [], []),
    ('me', 'mój:a', 'adj:pl:nom:n:pos', [], []),
    ('me', 'mój:a', 'adj:sg:acc:n:pos', [], []),
    ('me', 'mój:a', 'adj:pl:acc:n:pos', [], []),
    ('ma', 'mój:a', 'adj:sg:nom:f:pos', [], []),                                # moja
    ('mą', 'mój:a', 'adj:sg:acc:f:pos', [], []),                                # moją
    ('mą', 'mój:a', 'adj:sg:inst:f:pos', [], []),
    ('mym', 'mój:a', 'adj:sg:loc:m3:pos', [], []),                              # moim
    ('mym', 'mój:a', 'adj:sg:inst:m3:pos', [], []),
    ('mym', 'mój:a', 'adj:pl:dat:n:pos', [], []),
    ('mym', 'mój:a', 'adj:sg:loc:n:pos', [], []),
    ('mym', 'mój:a', 'adj:sg:inst:n:pos', [], []),
    ('mymi', 'mój:a', 'adj:pl:inst:f:pos', [], []),                             # moimi
    ('mymi', 'mój:a', 'adj:pl:inst:m3:pos', [], []),
    ('mymi', 'mój:a', 'adj:pl:inst:n:pos', [], []),
    ('mych', 'mój:a', 'adj:pl:gen:f:pos', [], []),                              # moich
    ('mych', 'mój:a', 'adj:pl:loc:f:pos', [], []),
    ('mych', 'mój:a', 'adj:pl:gen:m3:pos', [], []),
    ('mych', 'mój:a', 'adj:pl:loc:m3:pos', [], []),
    ('mych', 'mój:a', 'adj:pl:gen:n:pos', [], []),
    ('twej', 'twój:a', 'adj:sg:gen:f:pos', [], []),                             # twojej
    ('twej', 'twój:a', 'adj:sg:loc:f:pos', [], []),
    ('twych', 'twój:a', 'adj:pl:gen:f:pos', [], []),                            # twoich
    ('twych', 'twój:a', 'adj:pl:loc:m3:pos', [], []),
    ('twych', 'twój:a', 'adj:pl:loc:n:pos', [], []),
    ('twą', 'twój:a', 'adj:sg:inst:f:pos', [], []),                             # twoją
    ('twe', 'twój:a', 'adj:pl:acc:m3:pos', [], []),                             # twoje
    ('twym', 'twój:a', 'adj:sg:loc:m3:pos', [], []),                            # twoim
    ('twych', 'twój:a', 'adj:pl:loc:f:pos', [], []),                            # twoich
    ('wsze', 'wszystek', 'adj:pl:nom:f:pos', [], []),                           # wszystkie
    ('wsze', 'wszystek', 'adj:pl:acc:f:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:nom:m3:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:acc:m3:pos', [], []),
    ('wsze', 'wszystek', 'adj:pl:acc:n:pos', [], []),
    ('wszech', 'wszystek', 'adj:pl:gen:m1:pos', [], []),                        # wszystkich
    ('wszech', 'wszystek', 'adj:pl:loc:m3:pos', [], []),
    ('wszemi', 'wszystek', 'adj:pl:inst:m3:pos', [], []),                       # wszystkimi
)

KWAL_KILL_LIST = { 'niepopr.', 'pot.', 'rzad.', 'daw.', 'przest.', 'gwar.', 'pogard.', }

# don’t put posp/kwal in the key (lists are unhashable)
FORM_MAP = {
    ('gwintu', 'gwint', 'subst:sg:gen:m3') : ('gwinta', 'gwint', 'subst:sg:gen:m3', [], []), # nie ma w Morfeuszu (pić z gwinta)
}

OVERRIDE = {
    'hopel' : ('hopla', 'subst:sg:gen:m3'),
    'łupień' : ('łupnia', 'subst:sg:gen:m3'),
    # kropka nad „i”
    'i' :  ('„i”', 'subst:sg:inst:n'),
}   

def filter_kwal(forms):
    return list(filter(lambda f: not KWAL_KILL_LIST.intersection(f[4]), forms))

def filter_by_feature(feature, forms):
    if feature:
        return list(filter(lambda f: feature in f[2], forms))
    else:
        return forms

def select_form(lemma, feats):
    if lemma in OVERRIDE:
        return OVERRIDE[lemma]
    # forms: list of tuples in format: ('herb', 'herb', 'subst:sg:nom.acc:m3', ['nazwa_pospolita'], [])
    # split the tags for filtering
    forms = [FORM_MAP.get(tuple(f[:3]), f) for f in morfeusz.generate(lemma)]
    forms = [(orth, base, tag.split(':'), posp, kwal) for orth, base, tag, posp, kwal in forms]
    for feat in feats:
        # single feature: just filter
        if type(feat) == str:
            forms = filter_by_feature(feat, forms)
        # priority list of features: filter by first that yields non-empty result 
        else:
            forms2 = []
            for ft in feat:
                forms2 = filter_by_feature(ft, forms)
                if forms2:
                    break
            forms = forms2
    # join the tags back
    forms = [(orth, base, ':'.join(tag), posp, kwal) for orth, base, tag, posp, kwal in forms]
    selected_forms = list(filter(lambda f: f[1] not in LEMMA_KILL_LIST and f not in FORM_KILL_LIST, forms))
    if len(selected_forms) > 1:
        filtered_forms = filter_kwal(selected_forms)
        if filtered_forms:
            selected_forms = filtered_forms
    selected_orth_tags = set((f[0], f[2]) for f in selected_forms)
    if len(selected_orth_tags) != 1:
        #print('----------', lemma, feats)
        #print(selected_forms)
        1 / 0
    return selected_orth_tags.pop()