├── .gitignore ├── .gitmodules ├── LICENSE ├── MANIFEST.in ├── README.md ├── example.py ├── pytrovich.png ├── pytrovich ├── __init__.py ├── detector.py ├── enums.py ├── gender_models.py ├── maker.py ├── meta.py ├── rule_models.py └── rules_data.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.xml 3 | *~ 4 | *.pyc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pytrovich/petrovich-rules"] 2 | path = pytrovich/petrovich-rules 3 | url = https://github.com/petrovich/petrovich-rules 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Petrovich Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include pytrovich/petrovich-rules/* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Pytrovich](pytrovich.png) 2 | ========================================== 3 | 4 | __pytrovich__ is a Python 3.6+ port of [petrovich library](https://github.com/petrovich) which inflects Russian names 5 | to a given grammatical case. It supports first names, last names and middle names inflections. Since version 0.0.2, 6 | gender detection is also available. 7 | 8 | [petrovich-java](https://github.com/petrovich/petrovich-java) was the main inspiration. 9 | 10 | __The alternative (earlier) port__: [Petrovich](https://github.com/damirazo/Petrovich) ([@alexeyev](https://github.com/alexeyev) was not aware of it at the time of porting `petrovich` to Python). 11 | The only meaningful difference we have found is that it does not support gender detection. 12 | 13 | 14 | ![Python 3x](https://img.shields.io/badge/python-3.x-blue.svg) 15 | [![PyPI version][pypi_badge]][pypi_link] 16 | [![Downloads](https://pepy.tech/badge/pytrovich)](https://pepy.tech/project/pytrovich) 17 | 18 | [pypi_badge]: https://badge.fury.io/py/pytrovich.svg 19 | [pypi_link]: https://pypi.python.org/pypi/pytrovich 20 | 21 | ## Installation 22 | Should be as simple as that 23 | ```bash 24 | pip install pytrovich 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Inflection 30 | 31 | ```python 32 | from pytrovich.enums import NamePart, Gender, Case 33 | from pytrovich.maker import PetrovichDeclinationMaker 34 | 35 | maker = PetrovichDeclinationMaker() 36 | print(maker.make(NamePart.FIRSTNAME, Gender.MALE, Case.GENITIVE, "Иван")) # Ивана 37 | print(maker.make(NamePart.LASTNAME, Gender.MALE, Case.INSTRUMENTAL, "Иванов")) # Ивановым 38 | print(maker.make(NamePart.MIDDLENAME, Gender.FEMALE, Case.DATIVE, "Ивановна")) # Ивановне 39 | ``` 40 | 41 | ### Gender detection 42 | 43 | ```python 44 | from pytrovich.detector import PetrovichGenderDetector 45 | 46 | detector = PetrovichGenderDetector() 47 | print(detector.detect(firstname="Иван")) # Gender.MALE 48 | print(detector.detect(firstname="Иван", middlename="Семёнович")) # Gender.MALE 49 | print(detector.detect(firstname="Арзу", middlename="Лутфияр кызы")) # Gender.FEMALE 50 | ``` 51 | 52 | 53 | ### Custom rule file 54 | 55 | You can replace default rules file with some custom one. Only JSON format is supported. 56 | ```python 57 | maker = PetrovichDeclinationMaker("/path/to/custom/rules.file.json") 58 | ``` 59 | E.g. if `pytrovich` fails on `PetrovichDeclinationMaker` creation, 60 | one may consider downloading `rules.json` directly from 61 | [petrovich-rules repo](https://github.com/petrovich/petrovich-rules) as a fix (please create an issue if that actually happens). 62 | 63 | ### How to cite 64 | 65 | Not neccessary, but greatly appreciated, if you use this work. 66 | 67 | ```latex 68 | @misc{Pytrovich, 69 | title = {{petrovich/pytrovich: Python3 port of Petrovich, an inflector for Russian anthroponyms}}, 70 | year = {2020}, 71 | url = {https://github.com/petrovich/pytrovich}, 72 | language = {english}, 73 | } 74 | ``` 75 | 76 | ### More info 77 | 78 | For more information on the project please refer to other [petrovich](https://github.com/petrovich/) repos. 79 | 80 | ### TODO 81 | 82 | - efficiency was not a top priority, the time has come for faster algorithms, RegEx and data structures 83 | - evaluation based on [petrovich-eval](https://github.com/petrovich/petrovich-eval/) 84 | 85 | ## License 86 | 87 | This project is available under MIT license. 88 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import pytrovich 3 | from pytrovich.detector import PetrovichGenderDetector 4 | from pytrovich.enums import NamePart, Gender, Case 5 | from pytrovich.maker import PetrovichDeclinationMaker 6 | 7 | print(pytrovich.__version__) 8 | 9 | if __name__ == "__main__": 10 | maker = PetrovichDeclinationMaker() 11 | print(maker.make(NamePart.FIRSTNAME, Gender.MALE, Case.GENITIVE, "Иван")) # Ивана 12 | print(maker.make(NamePart.LASTNAME, Gender.MALE, Case.INSTRUMENTAL, "Иванов")) # Ивановым 13 | print(maker.make(NamePart.MIDDLENAME, Gender.FEMALE, Case.DATIVE, "Ивановна")) # Ивановне 14 | print(maker.make(NamePart.FIRSTNAME, Gender.MALE, Case.ACCUSATIVE, "Александр")) # Ивана 15 | print(maker.make(NamePart.LASTNAME, Gender.FEMALE, Case.INSTRUMENTAL, "Герман")) # Ивановым 16 | print(maker.make(NamePart.LASTNAME, Gender.FEMALE, Case.DATIVE, "Дюма")) # Ивановне 17 | 18 | detector = PetrovichGenderDetector() 19 | print(detector.detect(firstname="Иван")) # Gender.MALE 20 | print(detector.detect(firstname="Иван", middlename="Семёнович")) # Gender.MALE 21 | print(detector.detect(firstname="Арзу", middlename="Лутфияр кызы")) # Gender.FEMALE 22 | -------------------------------------------------------------------------------- /pytrovich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petrovich/pytrovich/81c8d254f8b233abe275eaea1fc05e1e6dc0edd2/pytrovich.png -------------------------------------------------------------------------------- /pytrovich/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from . import meta 4 | 5 | 6 | __version__ = meta.version 7 | __author__ = meta.authors[0] 8 | __license__ = meta.license 9 | __copyright__ = meta.copyright 10 | 11 | -------------------------------------------------------------------------------- /pytrovich/detector.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import sys 4 | from os import path 5 | 6 | from pytrovich import rules_data 7 | from pytrovich.enums import Gender 8 | from pytrovich.gender_models import Root, Name 9 | 10 | 11 | class PetrovichGenderDetector(object): 12 | DEFAULT_PATH_TO_RULES_FILE = path.join(path.dirname(__file__), "petrovich-rules", "gender.json") 13 | 14 | def __init__(self, path_to_rules_file: str = DEFAULT_PATH_TO_RULES_FILE): 15 | 16 | try: 17 | with open(path_to_rules_file, "r", encoding="utf-8") as fp: 18 | self._root_rules_bean = Root.parse(json.load(fp=fp)["gender"]) 19 | except Exception as e: 20 | print("Error occurred: %s" % str(e), file=sys.stderr) 21 | print("Using possibly outdated rules", file=sys.stderr) 22 | self._root_rules_bean = Root.parse(rules_data.gender()["gender"]) 23 | 24 | @staticmethod 25 | def _check_against_exceptions(name: Name, str_name: str) -> set: 26 | results = [] 27 | 28 | if name.exceptions and name.exceptions.male and str_name in name.exceptions.male: 29 | results.append(Gender.MALE) 30 | if name.exceptions and name.exceptions.female and str_name in name.exceptions.female: 31 | results.append(Gender.FEMALE) 32 | if name.exceptions and name.exceptions.andro and str_name in name.exceptions.andro: 33 | results.append(Gender.ANDROGYNOUS) 34 | return set(results) 35 | 36 | @staticmethod 37 | def _check_again_suffixes(name: Name, str_name: str) -> set: 38 | 39 | results = [] 40 | 41 | if name.suffixes and name.suffixes.male: 42 | for possible_suffix in name.suffixes.male: 43 | if str_name.endswith(possible_suffix): 44 | results.append(Gender.MALE) 45 | break 46 | 47 | if name.suffixes and name.suffixes.female: 48 | for possible_suffix in name.suffixes.female: 49 | if str_name.endswith(possible_suffix): 50 | results.append(Gender.FEMALE) 51 | break 52 | 53 | if name.suffixes and name.suffixes.andro: 54 | for possible_suffix in name.suffixes.andro: 55 | if str_name.endswith(possible_suffix): 56 | results.append(Gender.ANDROGYNOUS) 57 | break 58 | 59 | return set(results) 60 | 61 | def detect(self, firstname=None, lastname=None, middlename=None): 62 | 63 | assert not (firstname is None and lastname is None and middlename is None), \ 64 | "At least one part of the name should be given." 65 | 66 | results_middlename, results_firstname, results_lastname = set([]), set([]), set([]) 67 | 68 | if middlename: 69 | results_middlename.update(self._check_against_exceptions(self._root_rules_bean.middlename, middlename)) 70 | results_middlename.update(self._check_again_suffixes(self._root_rules_bean.middlename, middlename)) 71 | 72 | if len(results_middlename) > 0 and next(iter(results_middlename)) != Gender.ANDROGYNOUS: 73 | return next(iter(results_middlename)) 74 | 75 | if firstname: 76 | results_firstname.update(self._check_against_exceptions(self._root_rules_bean.firstname, firstname)) 77 | results_firstname.update(self._check_again_suffixes(self._root_rules_bean.firstname, firstname)) 78 | 79 | if lastname: 80 | results_lastname.update(self._check_against_exceptions(self._root_rules_bean.lastname, lastname)) 81 | results_lastname.update(self._check_again_suffixes(self._root_rules_bean.lastname, lastname)) 82 | 83 | if firstname and lastname: 84 | if results_firstname and results_lastname: 85 | fn, ln = next(iter(results_firstname)), next(iter(results_lastname)) 86 | if fn != Gender.ANDROGYNOUS and ln == Gender.ANDROGYNOUS: 87 | return fn 88 | if ln != Gender.ANDROGYNOUS and fn == Gender.ANDROGYNOUS: 89 | return ln 90 | 91 | joined_set = results_firstname.union(results_middlename).union(results_lastname) 92 | 93 | if len(joined_set) == 1: 94 | return next(iter(joined_set)) 95 | else: 96 | print("Gender prediction was confused, possible gender options: %s" % str(joined_set), file=sys.stderr) 97 | return next(iter(joined_set)) 98 | 99 | 100 | if __name__ == "__main__": 101 | detector = PetrovichGenderDetector() 102 | print(detector.detect(firstname="Иван", lastname="Голубцов")) 103 | print(detector.detect(firstname="Арзу", middlename="Лутфияр кызы")) 104 | -------------------------------------------------------------------------------- /pytrovich/enums.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from enum import Enum 4 | 5 | 6 | class LowerCaseNameEnum(Enum): 7 | def str(self): 8 | return self.name.lower() 9 | 10 | 11 | class Case(LowerCaseNameEnum): 12 | GENITIVE = 0 13 | DATIVE = 1 14 | ACCUSATIVE = 2 15 | INSTRUMENTAL = 3 16 | PREPOSITIONAL = 4 17 | 18 | 19 | class Gender(LowerCaseNameEnum): 20 | MALE = 0 21 | FEMALE = 1 22 | ANDROGYNOUS = 2 23 | 24 | 25 | class NamePart(LowerCaseNameEnum): 26 | LASTNAME = 0 27 | FIRSTNAME = 1 28 | MIDDLENAME = 2 29 | -------------------------------------------------------------------------------- /pytrovich/gender_models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # well I've tried to use jsonpickle or something of the like but without much luck 3 | 4 | 5 | class Rule(object): 6 | """ 7 | Exceptions/suffices as lists of strings for checking matches against ones 8 | """ 9 | 10 | def __init__(self, male: list = None, female: list = None, androgynous: list = None): 11 | assert not male is None or not female is None or not androgynous is None 12 | self.male = set(male) if not male is None else [] 13 | self.female = set(female) if not female is None else [] 14 | self.andro = set(androgynous) if not androgynous is None else [] 15 | 16 | def serialize(self): 17 | builder = {} 18 | if self.male and len(self.male) > 0: builder["male"] = self.male 19 | if self.female and len(self.female) > 0: builder["female"] = self.female 20 | if self.andro and len(self.andro) > 0: builder["androgynous"] = self.andro 21 | return builder 22 | 23 | @staticmethod 24 | def parse(o: dict): 25 | return Rule(male=o.get("male", None), female=o.get("female", None), androgynous=o.get("androgynous", None)) 26 | 27 | 28 | class Name(object): 29 | 30 | def __init__(self, exceptions: Rule=None, suffixes: Rule=None): 31 | """ 32 | :param exceptions: list(Rule): 33 | :param suffixes: list(Rule) 34 | """ 35 | assert exceptions is not None or suffixes is not None 36 | self.exceptions = exceptions 37 | self.suffixes = suffixes 38 | 39 | def serialize(self): 40 | builder = {} 41 | if self.exceptions is not None: builder["exceptions"] = self.exceptions.serialize() 42 | if self.suffixes is not None: builder["suffixes"] = self.suffixes.serialize() 43 | return builder 44 | 45 | @staticmethod 46 | def parse(o: dict): 47 | 48 | return Name(exceptions=Rule.parse(o["exceptions"]) if "exceptions" in o else None, 49 | suffixes=Rule.parse(o["suffixes"]) if "suffixes" in o else None) 50 | 51 | 52 | class Root(object): 53 | 54 | def __init__(self, firstname: Name = None, lastname: Name = None, middlename: Name = None): 55 | assert not firstname is None or not lastname is None or not middlename is None 56 | self.firstname = firstname 57 | self.lastname = lastname 58 | self.middlename = middlename 59 | 60 | def serialize(self): 61 | builder = {} 62 | if not self.firstname is None: builder["firstname"] = self.firstname.serialize() 63 | if not self.lastname is None: builder["lastname"] = self.lastname.serialize() 64 | if not self.middlename is None: builder["middlename"] = self.middlename.serialize() 65 | return builder 66 | 67 | @staticmethod 68 | def parse(a: dict): 69 | return Root(firstname=Name.parse(a["firstname"]) if "firstname" in a else None, 70 | lastname=Name.parse(a["lastname"]) if "lastname" in a else None, 71 | middlename=Name.parse(a["middlename"]) if "middlename" in a else None) 72 | 73 | def __str__(self): 74 | return str(self.serialize()) 75 | -------------------------------------------------------------------------------- /pytrovich/maker.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import sys 4 | from os import path 5 | 6 | from pytrovich import rules_data 7 | from pytrovich.enums import NamePart, Gender, Case 8 | from pytrovich.rule_models import Root, Name, Rule 9 | 10 | 11 | class PetrovichDeclinationMaker(object): 12 | DEFAULT_PATH_TO_RULES_FILE = path.join(path.dirname(__file__), "petrovich-rules", "rules.json") 13 | MODS_KEEP_IT_ALL_SYMBOL = "." 14 | MODS_REMOVE_LETTER_SYMBOL = "-" 15 | 16 | def __init__(self, path_to_rules_file: str = DEFAULT_PATH_TO_RULES_FILE): 17 | 18 | try: 19 | with open(path_to_rules_file, "r", encoding="utf-8") as fp: 20 | self._root_rules_bean = Root.parse(json.load(fp=fp)) 21 | except Exception as e: 22 | print("Error occurred: %s" % str(e), file=sys.stderr) 23 | print("Using possibly outdated rules", file=sys.stderr) 24 | self._root_rules_bean = Root.parse(rules_data.rules()) 25 | 26 | def make(self, name_part: NamePart, gender: Gender, case_to_use: Case, original_name: str) -> str: 27 | 28 | result = original_name 29 | 30 | if name_part == NamePart.FIRSTNAME: 31 | name_bean: Name = self._root_rules_bean.firstname 32 | elif name_part == NamePart.LASTNAME: 33 | name_bean: Name = self._root_rules_bean.lastname 34 | elif name_part == NamePart.MIDDLENAME: 35 | name_bean: Name = self._root_rules_bean.middlename 36 | else: 37 | name_bean: Name = self._root_rules_bean.middlename 38 | 39 | exception_rule_bean: Rule = \ 40 | PetrovichDeclinationMaker.find_in_rule_bean_list(name_bean.exceptions, gender, original_name) 41 | suffix_rule_bean: Rule = \ 42 | PetrovichDeclinationMaker.find_in_rule_bean_list(name_bean.suffixes, gender, original_name) 43 | 44 | if exception_rule_bean and exception_rule_bean.gender == gender.str(): 45 | rule_to_use: Rule = exception_rule_bean 46 | elif suffix_rule_bean and suffix_rule_bean.gender == gender.str(): 47 | rule_to_use: Rule = suffix_rule_bean 48 | else: 49 | rule_to_use: Rule = exception_rule_bean if exception_rule_bean else suffix_rule_bean 50 | 51 | if rule_to_use: 52 | mod2apply: str = rule_to_use.mods[case_to_use.value] 53 | result = PetrovichDeclinationMaker.apply_mod2name(mod2apply=mod2apply, name=original_name) 54 | 55 | return result 56 | 57 | @staticmethod 58 | def apply_mod2name(mod2apply: str, name: str) -> str: 59 | 60 | result = name 61 | 62 | # if modification is not needed 63 | if mod2apply != PetrovichDeclinationMaker.MODS_KEEP_IT_ALL_SYMBOL: 64 | # if modification is needed according to rules 65 | if PetrovichDeclinationMaker.MODS_REMOVE_LETTER_SYMBOL in mod2apply: 66 | for i in range(len(mod2apply)): 67 | # if special character "-", removing the last letter 68 | if mod2apply[i] == PetrovichDeclinationMaker.MODS_REMOVE_LETTER_SYMBOL: 69 | result = result[0:len(result) - 1] 70 | # if not a special character "-", adding the rest of the modifier to the result 71 | else: 72 | result += mod2apply[i:] 73 | break 74 | else: 75 | result = name + mod2apply 76 | 77 | return result 78 | 79 | @staticmethod 80 | def find_in_rule_bean_list(rule_bean_list: list, gender: Gender, original_name: str) -> Rule: 81 | 82 | result = None 83 | done = False 84 | 85 | if rule_bean_list is not None: 86 | # traversing all rules available 87 | for rule_bean in rule_bean_list: 88 | if done: 89 | break 90 | # traversing all available checks for word ends 91 | for test in rule_bean.test: 92 | # if match found 93 | if original_name.endswith(test): 94 | # if angrogynous OR gender match -- we're done, escaping both loops 95 | if rule_bean.gender == Gender.ANDROGYNOUS.str() or rule_bean.gender == gender.str(): 96 | result = rule_bean 97 | done = True 98 | break 99 | return result 100 | -------------------------------------------------------------------------------- /pytrovich/meta.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | package = "pytrovich" 4 | version = "0.0.2" 5 | authors = ["Anton Alekseev"] 6 | authors_string = ", ".join(authors) 7 | emails = ["anton.m.alexeyev@gmail.com"] 8 | license = "MIT" 9 | copyright = "2020 " + authors_string 10 | -------------------------------------------------------------------------------- /pytrovich/rule_models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # well I've tried to use jsonpickle or something of the like but without much luck 3 | 4 | 5 | class Rule(object): 6 | 7 | def __init__(self, gender: str, mods: list, test: list): 8 | """ 9 | :param gender: grammatical gender 10 | :param mods: modifications rules list 11 | :param test: search rules list 12 | """ 13 | self.gender = gender 14 | self.mods = mods 15 | self.test = test 16 | 17 | def serialize(self): 18 | return {"gender": self.gender, 19 | "mods": self.mods, 20 | "test": self.test} 21 | 22 | @staticmethod 23 | def parse(o: dict): 24 | return Rule(gender=o["gender"], mods=o["mods"], test=o["test"]) 25 | 26 | 27 | class Name(object): 28 | 29 | def __init__(self, exceptions: list, suffixes: list): 30 | """ 31 | :param exceptions: list(Rule): 32 | :param suffixes: list(Rule) 33 | """ 34 | self.exceptions = exceptions 35 | self.suffixes = suffixes 36 | 37 | def serialize(self): 38 | return {"exceptions": [e.serialize() for e in self.exceptions], 39 | "suffixes": [s.serialize() for s in self.suffixes]} 40 | 41 | @staticmethod 42 | def parse(o: dict): 43 | return Name(exceptions=[Rule.parse(e) for e in o.get("exceptions", [])], 44 | suffixes=[Rule.parse(s) for s in o.get("suffixes", [])]) 45 | 46 | 47 | class Root(object): 48 | 49 | def __init__(self, firstname, lastname, middlename): 50 | self.firstname = firstname 51 | self.lastname = lastname 52 | self.middlename = middlename 53 | 54 | def serialize(self): 55 | return {"firstname": self.firstname.serialize(), 56 | "lastname": self.lastname.serialize(), 57 | "middlename": self.middlename.serialize()} 58 | 59 | @staticmethod 60 | def parse(a: dict): 61 | return Root(firstname=Name.parse(a["firstname"]), 62 | lastname=Name.parse(a["lastname"]), 63 | middlename=Name.parse(a["middlename"])) -------------------------------------------------------------------------------- /pytrovich/rules_data.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | def rules(): 5 | # NOTA BENE: outdated, works only in case `petrovich-rules` are not accessible for some reason 6 | return { 7 | "lastname": { 8 | "exceptions": [ 9 | { 10 | "gender": "androgynous", 11 | "test": [ 12 | "бонч", 13 | "абдул", 14 | "белиц", 15 | "гасан", 16 | "дюссар", 17 | "дюмон", 18 | "книппер", 19 | "корвин", 20 | "ван", 21 | "шолом", 22 | "тер", 23 | "призван", 24 | "мелик", 25 | "вар", 26 | "фон" 27 | ], 28 | "mods": [ 29 | ".", 30 | ".", 31 | ".", 32 | ".", 33 | "." 34 | ], 35 | "tags": [ 36 | "first_word" 37 | ] 38 | }, 39 | { 40 | "gender": "androgynous", 41 | "test": [ 42 | "дюма", 43 | "тома", 44 | "дега", 45 | "люка", 46 | "ферма", 47 | "гамарра", 48 | "петипа", 49 | "шандра", 50 | "скаля", 51 | "каруана" 52 | ], 53 | "mods": [ 54 | ".", 55 | ".", 56 | ".", 57 | ".", 58 | "." 59 | ] 60 | }, 61 | { 62 | "gender": "androgynous", 63 | "test": [ 64 | "гусь", 65 | "ремень", 66 | "камень", 67 | "онук", 68 | "богода", 69 | "нечипас", 70 | "долгопалец", 71 | "маненок", 72 | "рева", 73 | "кива" 74 | ], 75 | "mods": [ 76 | ".", 77 | ".", 78 | ".", 79 | ".", 80 | "." 81 | ] 82 | }, 83 | { 84 | "gender": "androgynous", 85 | "test": [ 86 | "вий", 87 | "сой", 88 | "цой", 89 | "хой" 90 | ], 91 | "mods": [ 92 | "-я", 93 | "-ю", 94 | "-я", 95 | "-ем", 96 | "-е" 97 | ] 98 | }, 99 | { 100 | "gender": "androgynous", 101 | "test": [ 102 | "я" 103 | ], 104 | "mods": [ 105 | ".", 106 | ".", 107 | ".", 108 | ".", 109 | "." 110 | ] 111 | } 112 | ], 113 | "suffixes": [ 114 | { 115 | "gender": "female", 116 | "test": [ 117 | "б", 118 | "в", 119 | "г", 120 | "д", 121 | "ж", 122 | "з", 123 | "й", 124 | "к", 125 | "л", 126 | "м", 127 | "н", 128 | "п", 129 | "р", 130 | "с", 131 | "т", 132 | "ф", 133 | "х", 134 | "ц", 135 | "ч", 136 | "ш", 137 | "щ", 138 | "ъ", 139 | "ь" 140 | ], 141 | "mods": [ 142 | ".", 143 | ".", 144 | ".", 145 | ".", 146 | "." 147 | ] 148 | }, 149 | { 150 | "gender": "androgynous", 151 | "test": [ 152 | "гава", 153 | "орота" 154 | ], 155 | "mods": [ 156 | ".", 157 | ".", 158 | ".", 159 | ".", 160 | "." 161 | ] 162 | }, 163 | { 164 | "gender": "female", 165 | "test": [ 166 | "ска", 167 | "цка" 168 | ], 169 | "mods": [ 170 | "-ой", 171 | "-ой", 172 | "-ую", 173 | "-ой", 174 | "-ой" 175 | ] 176 | }, 177 | { 178 | "gender": "female", 179 | "test": [ 180 | "цкая", 181 | "ская", 182 | "ная", 183 | "ая" 184 | ], 185 | "mods": [ 186 | "--ой", 187 | "--ой", 188 | "--ую", 189 | "--ой", 190 | "--ой" 191 | ] 192 | }, 193 | { 194 | "gender": "female", 195 | "test": [ 196 | "яя" 197 | ], 198 | "mods": [ 199 | "--ей", 200 | "--ей", 201 | "--юю", 202 | "--ей", 203 | "--ей" 204 | ] 205 | }, 206 | { 207 | "gender": "female", 208 | "test": [ 209 | "на" 210 | ], 211 | "mods": [ 212 | "-ой", 213 | "-ой", 214 | "-у", 215 | "-ой", 216 | "-ой" 217 | ] 218 | }, 219 | { 220 | "gender": "male", 221 | "test": [ 222 | "иной" 223 | ], 224 | "mods": [ 225 | "-я", 226 | "-ю", 227 | "-я", 228 | "-ем", 229 | "-е" 230 | ] 231 | }, 232 | { 233 | "gender": "male", 234 | "test": [ 235 | "уй" 236 | ], 237 | "mods": [ 238 | "-я", 239 | "-ю", 240 | "-я", 241 | "-ем", 242 | "-е" 243 | ] 244 | }, 245 | { 246 | "gender": "androgynous", 247 | "test": [ 248 | "ца" 249 | ], 250 | "mods": [ 251 | "-ы", 252 | "-е", 253 | "-у", 254 | "-ей", 255 | "-е" 256 | ] 257 | }, 258 | { 259 | "gender": "male", 260 | "test": [ 261 | "рих" 262 | ], 263 | "mods": [ 264 | "а", 265 | "у", 266 | "а", 267 | "ом", 268 | "е" 269 | ] 270 | }, 271 | { 272 | "gender": "androgynous", 273 | "test": [ 274 | "ия" 275 | ], 276 | "mods": [ 277 | ".", 278 | ".", 279 | ".", 280 | ".", 281 | "." 282 | ] 283 | }, 284 | { 285 | "gender": "androgynous", 286 | "test": [ 287 | "иа", 288 | "аа", 289 | "оа", 290 | "уа", 291 | "ыа", 292 | "еа", 293 | "юа", 294 | "эа" 295 | ], 296 | "mods": [ 297 | ".", 298 | ".", 299 | ".", 300 | ".", 301 | "." 302 | ] 303 | }, 304 | { 305 | "gender": "male", 306 | "test": [ 307 | "их", 308 | "ых" 309 | ], 310 | "mods": [ 311 | ".", 312 | ".", 313 | ".", 314 | ".", 315 | "." 316 | ] 317 | }, 318 | { 319 | "gender": "androgynous", 320 | "test": [ 321 | "о", 322 | "е", 323 | "э", 324 | "и", 325 | "ы", 326 | "у", 327 | "ю" 328 | ], 329 | "mods": [ 330 | ".", 331 | ".", 332 | ".", 333 | ".", 334 | "." 335 | ] 336 | }, 337 | { 338 | "gender": "female", 339 | "test": [ 340 | "ова", 341 | "ева" 342 | ], 343 | "mods": [ 344 | "-ой", 345 | "-ой", 346 | "-у", 347 | "-ой", 348 | "-ой" 349 | ] 350 | }, 351 | { 352 | "gender": "androgynous", 353 | "test": [ 354 | "га", 355 | "ка", 356 | "ха", 357 | "ча", 358 | "ща", 359 | "жа", 360 | "ша" 361 | ], 362 | "mods": [ 363 | "-и", 364 | "-е", 365 | "-у", 366 | "-ой", 367 | "-е" 368 | ] 369 | }, 370 | { 371 | "gender": "androgynous", 372 | "test": [ 373 | "а" 374 | ], 375 | "mods": [ 376 | "-ы", 377 | "-е", 378 | "-у", 379 | "-ой", 380 | "-е" 381 | ] 382 | }, 383 | { 384 | "gender": "male", 385 | "test": [ 386 | "ь" 387 | ], 388 | "mods": [ 389 | "-я", 390 | "-ю", 391 | "-я", 392 | "-ем", 393 | "-е" 394 | ] 395 | }, 396 | { 397 | "gender": "androgynous", 398 | "test": [ 399 | "ия" 400 | ], 401 | "mods": [ 402 | "-и", 403 | "-и", 404 | "-ю", 405 | "-ей", 406 | "-и" 407 | ] 408 | }, 409 | { 410 | "gender": "androgynous", 411 | "test": [ 412 | "я" 413 | ], 414 | "mods": [ 415 | "-и", 416 | "-е", 417 | "-ю", 418 | "-ей", 419 | "-е" 420 | ] 421 | }, 422 | { 423 | "gender": "male", 424 | "test": [ 425 | "ей" 426 | ], 427 | "mods": [ 428 | "-я", 429 | "-ю", 430 | "-я", 431 | "-ем", 432 | "-е" 433 | ] 434 | }, 435 | { 436 | "gender": "male", 437 | "test": [ 438 | "ян", 439 | "ан", 440 | "йн" 441 | ], 442 | "mods": [ 443 | "а", 444 | "у", 445 | "а", 446 | "ом", 447 | "е" 448 | ] 449 | }, 450 | { 451 | "gender": "male", 452 | "test": [ 453 | "ынец", 454 | "обец" 455 | ], 456 | "mods": [ 457 | "--ца", 458 | "--цу", 459 | "--ца", 460 | "--цем", 461 | "--це" 462 | ] 463 | }, 464 | { 465 | "gender": "male", 466 | "test": [ 467 | "онец", 468 | "овец" 469 | ], 470 | "mods": [ 471 | "--ца", 472 | "--цу", 473 | "--ца", 474 | "--цом", 475 | "--це" 476 | ] 477 | }, 478 | { 479 | "gender": "male", 480 | "test": [ 481 | "ай" 482 | ], 483 | "mods": [ 484 | "-я", 485 | "-ю", 486 | "-я", 487 | "-ем", 488 | "-е" 489 | ] 490 | }, 491 | { 492 | "gender": "male", 493 | "test": [ 494 | "кой" 495 | ], 496 | "mods": [ 497 | "-го", 498 | "-му", 499 | "-го", 500 | "--им", 501 | "-м" 502 | ] 503 | }, 504 | { 505 | "gender": "male", 506 | "test": [ 507 | "гой" 508 | ], 509 | "mods": [ 510 | "-го", 511 | "-му", 512 | "-го", 513 | "--им", 514 | "-м" 515 | ] 516 | }, 517 | { 518 | "gender": "male", 519 | "test": [ 520 | "ой" 521 | ], 522 | "mods": [ 523 | "-го", 524 | "-му", 525 | "-го", 526 | "--ым", 527 | "-м" 528 | ] 529 | }, 530 | { 531 | "gender": "male", 532 | "test": [ 533 | "ах", 534 | "ив" 535 | ], 536 | "mods": [ 537 | "а", 538 | "у", 539 | "а", 540 | "ом", 541 | "е" 542 | ] 543 | }, 544 | { 545 | "gender": "male", 546 | "test": [ 547 | "ший", 548 | "щий", 549 | "жий", 550 | "ний" 551 | ], 552 | "mods": [ 553 | "--его", 554 | "--ему", 555 | "--его", 556 | "-м", 557 | "--ем" 558 | ] 559 | }, 560 | { 561 | "gender": "male", 562 | "test": [ 563 | "ый" 564 | ], 565 | "mods": [ 566 | "--ого", 567 | "--ому", 568 | "--ого", 569 | "-м", 570 | "--ом" 571 | ] 572 | }, 573 | { 574 | "gender": "male", 575 | "test": [ 576 | "кий" 577 | ], 578 | "mods": [ 579 | "--ого", 580 | "--ому", 581 | "--ого", 582 | "-м", 583 | "--ом" 584 | ] 585 | }, 586 | { 587 | "gender": "male", 588 | "test": [ 589 | "ий" 590 | ], 591 | "mods": [ 592 | "-я", 593 | "-ю", 594 | "-я", 595 | "-ем", 596 | "-и" 597 | ] 598 | }, 599 | { 600 | "gender": "male", 601 | "test": [ 602 | "ок" 603 | ], 604 | "mods": [ 605 | "--ка", 606 | "--ку", 607 | "--ка", 608 | "--ком", 609 | "--ке" 610 | ] 611 | }, 612 | { 613 | "gender": "male", 614 | "test": [ 615 | "ец" 616 | ], 617 | "mods": [ 618 | "--ца", 619 | "--цу", 620 | "--ца", 621 | "--цом", 622 | "--це" 623 | ] 624 | }, 625 | { 626 | "gender": "male", 627 | "test": [ 628 | "ц", 629 | "ч", 630 | "ш", 631 | "щ" 632 | ], 633 | "mods": [ 634 | "а", 635 | "у", 636 | "а", 637 | "ем", 638 | "е" 639 | ] 640 | }, 641 | { 642 | "gender": "male", 643 | "test": [ 644 | "ен", 645 | "нн", 646 | "он", 647 | "ун" 648 | ], 649 | "mods": [ 650 | "а", 651 | "у", 652 | "а", 653 | "ом", 654 | "е" 655 | ] 656 | }, 657 | { 658 | "gender": "male", 659 | "test": [ 660 | "в", 661 | "н" 662 | ], 663 | "mods": [ 664 | "а", 665 | "у", 666 | "а", 667 | "ым", 668 | "е" 669 | ] 670 | }, 671 | { 672 | "gender": "male", 673 | "test": [ 674 | "б", 675 | "г", 676 | "д", 677 | "ж", 678 | "з", 679 | "к", 680 | "л", 681 | "м", 682 | "п", 683 | "р", 684 | "с", 685 | "т", 686 | "ф", 687 | "х" 688 | ], 689 | "mods": [ 690 | "а", 691 | "у", 692 | "а", 693 | "ом", 694 | "е" 695 | ] 696 | } 697 | ] 698 | }, 699 | "firstname": { 700 | "exceptions": [ 701 | { 702 | "gender": "male", 703 | "test": [ 704 | "лев" 705 | ], 706 | "mods": [ 707 | "--ьва", 708 | "--ьву", 709 | "--ьва", 710 | "--ьвом", 711 | "--ьве" 712 | ] 713 | }, 714 | { 715 | "gender": "male", 716 | "test": [ 717 | "пётр" 718 | ], 719 | "mods": [ 720 | "---етра", 721 | "---етру", 722 | "---етра", 723 | "---етром", 724 | "---етре" 725 | ] 726 | }, 727 | { 728 | "gender": "male", 729 | "test": [ 730 | "павел" 731 | ], 732 | "mods": [ 733 | "--ла", 734 | "--лу", 735 | "--ла", 736 | "--лом", 737 | "--ле" 738 | ] 739 | }, 740 | { 741 | "gender": "male", 742 | "test": [ 743 | "яша" 744 | ], 745 | "mods": [ 746 | "-и", 747 | "-е", 748 | "-у", 749 | "-ей", 750 | "-е" 751 | ] 752 | }, 753 | { 754 | "gender": "male", 755 | "test": [ 756 | "шота" 757 | ], 758 | "mods": [ 759 | ".", 760 | ".", 761 | ".", 762 | ".", 763 | "." 764 | ] 765 | }, 766 | { 767 | "gender": "female", 768 | "test": [ 769 | "рашель", 770 | "нинель", 771 | "николь", 772 | "габриэль", 773 | "даниэль" 774 | ], 775 | "mods": [ 776 | ".", 777 | ".", 778 | ".", 779 | ".", 780 | "." 781 | ] 782 | } 783 | ], 784 | "suffixes": [ 785 | { 786 | "gender": "androgynous", 787 | "test": [ 788 | "е", 789 | "ё", 790 | "и", 791 | "о", 792 | "у", 793 | "ы", 794 | "э", 795 | "ю" 796 | ], 797 | "mods": [ 798 | ".", 799 | ".", 800 | ".", 801 | ".", 802 | "." 803 | ] 804 | }, 805 | { 806 | "gender": "female", 807 | "test": [ 808 | "б", 809 | "в", 810 | "г", 811 | "д", 812 | "ж", 813 | "з", 814 | "й", 815 | "к", 816 | "л", 817 | "м", 818 | "н", 819 | "п", 820 | "р", 821 | "с", 822 | "т", 823 | "ф", 824 | "х", 825 | "ц", 826 | "ч", 827 | "ш", 828 | "щ", 829 | "ъ" 830 | ], 831 | "mods": [ 832 | ".", 833 | ".", 834 | ".", 835 | ".", 836 | "." 837 | ] 838 | }, 839 | { 840 | "gender": "female", 841 | "test": [ 842 | "ь" 843 | ], 844 | "mods": [ 845 | "-и", 846 | "-и", 847 | ".", 848 | "ю", 849 | "-и" 850 | ] 851 | }, 852 | { 853 | "gender": "male", 854 | "test": [ 855 | "ь" 856 | ], 857 | "mods": [ 858 | "-я", 859 | "-ю", 860 | "-я", 861 | "-ем", 862 | "-е" 863 | ] 864 | }, 865 | { 866 | "gender": "androgynous", 867 | "test": [ 868 | "га", 869 | "ка", 870 | "ха", 871 | "ча", 872 | "ща", 873 | "жа" 874 | ], 875 | "mods": [ 876 | "-и", 877 | "-е", 878 | "-у", 879 | "-ой", 880 | "-е" 881 | ] 882 | }, 883 | { 884 | "gender": "female", 885 | "test": [ 886 | "ша" 887 | ], 888 | "mods": [ 889 | "-и", 890 | "-е", 891 | "-у", 892 | "-ей", 893 | "-е" 894 | ] 895 | }, 896 | { 897 | "gender": "androgynous", 898 | "test": [ 899 | "а" 900 | ], 901 | "mods": [ 902 | "-ы", 903 | "-е", 904 | "-у", 905 | "-ой", 906 | "-е" 907 | ] 908 | }, 909 | { 910 | "gender": "female", 911 | "test": [ 912 | "ия" 913 | ], 914 | "mods": [ 915 | "-и", 916 | "-и", 917 | "-ю", 918 | "-ей", 919 | "-и" 920 | ] 921 | }, 922 | { 923 | "gender": "female", 924 | "test": [ 925 | "а" 926 | ], 927 | "mods": [ 928 | "-ы", 929 | "-е", 930 | "-у", 931 | "-ой", 932 | "-е" 933 | ] 934 | }, 935 | { 936 | "gender": "female", 937 | "test": [ 938 | "я" 939 | ], 940 | "mods": [ 941 | "-и", 942 | "-е", 943 | "-ю", 944 | "-ей", 945 | "-е" 946 | ] 947 | }, 948 | { 949 | "gender": "male", 950 | "test": [ 951 | "ия" 952 | ], 953 | "mods": [ 954 | "-и", 955 | "-и", 956 | "-ю", 957 | "-ей", 958 | "-и" 959 | ] 960 | }, 961 | { 962 | "gender": "male", 963 | "test": [ 964 | "я" 965 | ], 966 | "mods": [ 967 | "-и", 968 | "-е", 969 | "-ю", 970 | "-ей", 971 | "-е" 972 | ] 973 | }, 974 | { 975 | "gender": "male", 976 | "test": [ 977 | "ей" 978 | ], 979 | "mods": [ 980 | "-я", 981 | "-ю", 982 | "-я", 983 | "-ем", 984 | "-е" 985 | ] 986 | }, 987 | { 988 | "gender": "male", 989 | "test": [ 990 | "ий" 991 | ], 992 | "mods": [ 993 | "-я", 994 | "-ю", 995 | "-я", 996 | "-ем", 997 | "-и" 998 | ] 999 | }, 1000 | { 1001 | "gender": "male", 1002 | "test": [ 1003 | "й" 1004 | ], 1005 | "mods": [ 1006 | "-я", 1007 | "-ю", 1008 | "-я", 1009 | "-ем", 1010 | "-е" 1011 | ] 1012 | }, 1013 | { 1014 | "gender": "male", 1015 | "test": [ 1016 | "б", 1017 | "в", 1018 | "г", 1019 | "д", 1020 | "ж", 1021 | "з", 1022 | "к", 1023 | "л", 1024 | "м", 1025 | "н", 1026 | "п", 1027 | "р", 1028 | "с", 1029 | "т", 1030 | "ф", 1031 | "х", 1032 | "ц", 1033 | "ч" 1034 | ], 1035 | "mods": [ 1036 | "а", 1037 | "у", 1038 | "а", 1039 | "ом", 1040 | "е" 1041 | ] 1042 | }, 1043 | { 1044 | "gender": "androgynous", 1045 | "test": [ 1046 | "ния", 1047 | "рия", 1048 | "вия" 1049 | ], 1050 | "mods": [ 1051 | "-и", 1052 | "-и", 1053 | "-ю", 1054 | "-ем", 1055 | "-ем" 1056 | ] 1057 | } 1058 | ] 1059 | }, 1060 | "middlename": { 1061 | "suffixes": [ 1062 | { 1063 | "gender": "male", 1064 | "test": [ 1065 | "ич" 1066 | ], 1067 | "mods": [ 1068 | "а", 1069 | "у", 1070 | "а", 1071 | "ем", 1072 | "е" 1073 | ] 1074 | }, 1075 | { 1076 | "gender": "female", 1077 | "test": [ 1078 | "на" 1079 | ], 1080 | "mods": [ 1081 | "-ы", 1082 | "-е", 1083 | "-у", 1084 | "-ой", 1085 | "-е" 1086 | ] 1087 | } 1088 | ] 1089 | } 1090 | } 1091 | 1092 | 1093 | def gender(): 1094 | return { 1095 | "gender": { 1096 | "lastname": { 1097 | "exceptions": { 1098 | "androgynous": [ 1099 | "бова", 1100 | "регин", 1101 | "дарвин", 1102 | "пэйлин", 1103 | "грин", 1104 | "цин", 1105 | "шенгелая" 1106 | ] 1107 | }, 1108 | "suffixes": { 1109 | "female": [ 1110 | "ова", 1111 | "ая", 1112 | "ына", 1113 | "ина", 1114 | "ева", 1115 | "ска", 1116 | "ёва" 1117 | ], 1118 | "male": [ 1119 | "кий", 1120 | "ов", 1121 | "ын", 1122 | "ев", 1123 | "ин", 1124 | "ёв", 1125 | "хий", 1126 | "ний", 1127 | "ый", 1128 | "ой" 1129 | ] 1130 | } 1131 | }, 1132 | "firstname": { 1133 | "exceptions": { 1134 | "androgynous": [ 1135 | "сева", 1136 | "иона", 1137 | "муса", 1138 | "саша", 1139 | "алвард", 1140 | "валери", 1141 | "кири", 1142 | "анри", 1143 | "ким", 1144 | "райхон", 1145 | "закия", 1146 | "захария", 1147 | "женя" 1148 | ], 1149 | "male": [ 1150 | "абиба", 1151 | "савва", 1152 | "лёва", 1153 | "вова", 1154 | "ага", 1155 | "ахмедага", 1156 | "алиага", 1157 | "амирага", 1158 | "агга", 1159 | "серега", 1160 | "фейга", 1161 | "гога", 1162 | "алиада", 1163 | "муктада", 1164 | "абида", 1165 | "алда", 1166 | "маджуда", 1167 | "нурлыхуда", 1168 | "гиа", 1169 | "элиа", 1170 | "гарсиа", 1171 | "вавила", 1172 | "гавриила", 1173 | "генка", 1174 | "лука", 1175 | "дима", 1176 | "зосима", 1177 | "тима", 1178 | "фима", 1179 | "фома", 1180 | "кузьма", 1181 | "жора", 1182 | "миша", 1183 | "ермила", 1184 | "данила", 1185 | "гаврила", 1186 | "абдалла", 1187 | "аталла", 1188 | "абдилла", 1189 | "атилла", 1190 | "кайролла", 1191 | "абулла", 1192 | "абула", 1193 | "свитлана", 1194 | "бена", 1195 | "гена", 1196 | "агелина", 1197 | "джанна", 1198 | "кришна", 1199 | "степа", 1200 | "дра", 1201 | "назера", 1202 | "валера", 1203 | "эстера", 1204 | "двойра", 1205 | "калистра", 1206 | "заратустра", 1207 | "юра", 1208 | "иса", 1209 | "аиса", 1210 | "халиса", 1211 | "холиса", 1212 | "валенса", 1213 | "мусса", 1214 | "ата", 1215 | "паата", 1216 | "алета", 1217 | "никита", 1218 | "мота", 1219 | "шота", 1220 | "фаста", 1221 | "коста", 1222 | "маритта", 1223 | "малюта", 1224 | "васюта", 1225 | "вафа", 1226 | "мустафа", 1227 | "ганифа", 1228 | "лев", 1229 | "яков", 1230 | "шелли", 1231 | "константин", 1232 | "марсель", 1233 | "рамиль", 1234 | "эмиль", 1235 | "бактыгуль", 1236 | "даниэль", 1237 | "игорь", 1238 | "арминэ", 1239 | "изя", 1240 | "кузя", 1241 | "гия", 1242 | "мазия", 1243 | "кирикия", 1244 | "ркия", 1245 | "еркия", 1246 | "эркия", 1247 | "гулия", 1248 | "аксания", 1249 | "закария", 1250 | "зекерия", 1251 | "гарсия", 1252 | "шендля", 1253 | "филя", 1254 | "вилля", 1255 | "толя", 1256 | "ваня", 1257 | "саня", 1258 | "загиря", 1259 | "боря", 1260 | "цайся", 1261 | "вася", 1262 | "ося", 1263 | "петя", 1264 | "витя", 1265 | "митя", 1266 | "костя", 1267 | "алья", 1268 | "илья", 1269 | "ларья" 1270 | ], 1271 | "female": [ 1272 | "судаба", 1273 | "сураба", 1274 | "любава", 1275 | "джанлука", 1276 | "варвара", 1277 | "наташа", 1278 | "зайнаб", 1279 | "любов", 1280 | "сольвейг", 1281 | "шакед", 1282 | "аннаид", 1283 | "ингрид", 1284 | "синди", 1285 | "аллаберди", 1286 | "сандали", 1287 | "лали", 1288 | "натали", 1289 | "гулькай", 1290 | "алтынай", 1291 | "гюнай", 1292 | "гюльчитай", 1293 | "нурангиз", 1294 | "лиз", 1295 | "элиз", 1296 | "ботагоз", 1297 | "юлдуз", 1298 | "диляфруз", 1299 | "габи", 1300 | "сажи", 1301 | "фанни", 1302 | "мери", 1303 | "элдари", 1304 | "эльдари", 1305 | "хилари", 1306 | "хиллари", 1307 | "аннемари", 1308 | "розмари", 1309 | "товсари", 1310 | "ансари", 1311 | "одри", 1312 | "тери", 1313 | "ири", 1314 | "катри", 1315 | "мэри", 1316 | "сатаней", 1317 | "ефтений", 1318 | "верунчик", 1319 | "гюзел", 1320 | "этел", 1321 | "рэйчел", 1322 | "джил", 1323 | "мерил", 1324 | "нинелл", 1325 | "бурул", 1326 | "ахлам", 1327 | "майрам", 1328 | "махаррам", 1329 | "мириам", 1330 | "дилярам", 1331 | "асем", 1332 | "мерьем", 1333 | "мирьем", 1334 | "эркаим", 1335 | "гулаим", 1336 | "айгерим", 1337 | "марьям", 1338 | "мирьям", 1339 | "эван", 1340 | "гульжиган", 1341 | "айдан", 1342 | "айжан", 1343 | "вивиан", 1344 | "гульжиан", 1345 | "лилиан", 1346 | "мариан", 1347 | "саиман", 1348 | "джоан", 1349 | "чулпан", 1350 | "лоран", 1351 | "моран", 1352 | "джохан", 1353 | "гульшан", 1354 | "аделин", 1355 | "жаклин", 1356 | "карин", 1357 | "каролин", 1358 | "каталин", 1359 | "катрин", 1360 | "керстин", 1361 | "кэтрин", 1362 | "мэрилин", 1363 | "рузалин", 1364 | "хелин", 1365 | "цеткин", 1366 | "ширин", 1367 | "элисон", 1368 | "дурсун", 1369 | "кристин", 1370 | "гульжиян", 1371 | "марьян", 1372 | "ренато", 1373 | "зейнеп", 1374 | "санабар", 1375 | "дильбар", 1376 | "гулизар", 1377 | "гульзар", 1378 | "пилар", 1379 | "дагмар", 1380 | "элинар", 1381 | "нилуфар", 1382 | "анхар", 1383 | "гаухар", 1384 | "естер", 1385 | "эстер", 1386 | "дженнифер", 1387 | "линор", 1388 | "элинор", 1389 | "элеонор", 1390 | "айнур", 1391 | "гульнур", 1392 | "шамсинур", 1393 | "элнур", 1394 | "ильсияр", 1395 | "нигяр", 1396 | "сигитас", 1397 | "агнес", 1398 | "анес", 1399 | "долорес", 1400 | "инес", 1401 | "анаис", 1402 | "таис", 1403 | "эллис", 1404 | "элис", 1405 | "кларис", 1406 | "амнерис", 1407 | "айрис", 1408 | "дорис", 1409 | "беатрис", 1410 | "грейс", 1411 | "грэйс", 1412 | "ботагос", 1413 | "маргос", 1414 | "джулианс", 1415 | "арус", 1416 | "диляфрус", 1417 | "саодат", 1418 | "зулхижат", 1419 | "хамат", 1420 | "патимат", 1421 | "хатимат", 1422 | "альжанат", 1423 | "маймунат", 1424 | "гульшат", 1425 | "биргит", 1426 | "рут", 1427 | "иргаш", 1428 | "айнаш", 1429 | "агнеш", 1430 | "зауреш", 1431 | "тэрбиш", 1432 | "ануш", 1433 | "азгануш", 1434 | "гаруш", 1435 | "николь", 1436 | "адась", 1437 | "афиля", 1438 | "тафиля", 1439 | "фаня", 1440 | "аня" 1441 | ] 1442 | }, 1443 | "suffixes": { 1444 | "androgynous": [ 1445 | "улла" 1446 | ], 1447 | "male": [ 1448 | "аба", 1449 | "б", 1450 | "ав", 1451 | "ев", 1452 | "ов", 1453 | "г", 1454 | "д", 1455 | "ж", 1456 | "з", 1457 | "би", 1458 | "ди", 1459 | "жи", 1460 | "али", 1461 | "ри", 1462 | "ай", 1463 | "ей", 1464 | "ий", 1465 | "ой", 1466 | "ый", 1467 | "к", 1468 | "л", 1469 | "ам", 1470 | "ем", 1471 | "им", 1472 | "ом", 1473 | "ум", 1474 | "ым", 1475 | "ям", 1476 | "ан", 1477 | "бен", 1478 | "вен", 1479 | "ген", 1480 | "ден", 1481 | "ин", 1482 | "сейн", 1483 | "он", 1484 | "ун", 1485 | "ян", 1486 | "ио", 1487 | "ло", 1488 | "ро", 1489 | "то", 1490 | "шо", 1491 | "п", 1492 | "ар", 1493 | "др", 1494 | "ер", 1495 | "ир", 1496 | "ор", 1497 | "тр", 1498 | "ур", 1499 | "ыр", 1500 | "яр", 1501 | "ас", 1502 | "ес", 1503 | "ис", 1504 | "йс", 1505 | "кс", 1506 | "мс", 1507 | "ос", 1508 | "нс", 1509 | "рс", 1510 | "ус", 1511 | "юс", 1512 | "яс", 1513 | "ат", 1514 | "мет", 1515 | "кт", 1516 | "нт", 1517 | "рт", 1518 | "ст", 1519 | "ут", 1520 | "ф", 1521 | "х", 1522 | "ш", 1523 | "ы", 1524 | "сь", 1525 | "емеля", 1526 | "коля" 1527 | ], 1528 | "female": [ 1529 | "иба", 1530 | "люба", 1531 | "лава", 1532 | "ева", 1533 | "га", 1534 | "да", 1535 | "еа", 1536 | "иза", 1537 | "иа", 1538 | "ика", 1539 | "нка", 1540 | "ска", 1541 | "ела", 1542 | "ила", 1543 | "лла", 1544 | "эла", 1545 | "има", 1546 | "на", 1547 | "ра", 1548 | "са", 1549 | "та", 1550 | "фа", 1551 | "елли", 1552 | "еса", 1553 | "сса", 1554 | "гуль", 1555 | "нуэль", 1556 | "гюль", 1557 | "нэ", 1558 | "ая", 1559 | "ея", 1560 | "ия", 1561 | "йя", 1562 | "ля", 1563 | "мя", 1564 | "оя", 1565 | "ря", 1566 | "ся", 1567 | "вья", 1568 | "лья", 1569 | "мья", 1570 | "нья", 1571 | "рья", 1572 | "сья", 1573 | "тья", 1574 | "фья", 1575 | "зя" 1576 | ] 1577 | } 1578 | }, 1579 | "middlename": { 1580 | "suffixes": { 1581 | "female": [ 1582 | "на", 1583 | "кызы", 1584 | "гызы" 1585 | ], 1586 | "male": [ 1587 | "ич", 1588 | "оглы", 1589 | "улы", 1590 | "уулу" 1591 | ] 1592 | } 1593 | } 1594 | } 1595 | } 1596 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from distutils.core import setup 4 | 5 | import setuptools 6 | 7 | with open("README.md", "r", encoding="utf-8") as fh: 8 | long_description = fh.read() 9 | 10 | setup( 11 | name="pytrovich", 12 | packages=setuptools.find_packages(), 13 | version="0.0.2", 14 | description="pytrovich: a Python port of an inflector for Russian anthroponyms developed by petrovich team: " 15 | "https://github.com/petrovich", 16 | long_description=long_description, 17 | long_description_content_type="text/markdown", 18 | author="Anton Alekseev", 19 | author_email="anton.m.alexeye@gmail.com", 20 | url="https://github.com/petrovich/pytrovich", 21 | keywords=["nlp", "morphology", "russian language"], 22 | classifiers=[ 23 | "Programming Language :: Python :: 3", 24 | "License :: OSI Approved :: MIT License", 25 | "Operating System :: OS Independent", 26 | ], 27 | zip_safe=False, 28 | include_package_data=True, 29 | python_requires=">=3.6", 30 | ) 31 | --------------------------------------------------------------------------------