Include Macedonian language (#6230)

* Include Macedonian language

* Fix indentation at char_classes.py

* Fix indentation at char_classes.py

* Add Macedonian tests, update lex_attrs and char_classes

* Import unicode literals for python 2
This commit is contained in:
Borijan Georgievski 2020-10-15 15:55:01 +02:00 committed by GitHub
parent bc027dc35c
commit 2311192ba1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1931 additions and 3 deletions

106
.github/contributors/borijang.md vendored Normal file
View File

@ -0,0 +1,106 @@
# spaCy contributor agreement
This spaCy Contributor Agreement (**"SCA"**) is based on the
[Oracle Contributor Agreement](http://www.oracle.com/technetwork/oca-405177.pdf).
The SCA applies to any contribution that you make to any product or project
managed by us (the **"project"**), and sets out the intellectual property rights
you grant to us in the contributed materials. The term **"us"** shall mean
[ExplosionAI GmbH](https://explosion.ai/legal). The term
**"you"** shall mean the person or entity identified below.
If you agree to be bound by these terms, fill in the information requested
below and include the filled-in version with your first pull request, under the
folder [`.github/contributors/`](/.github/contributors/). The name of the file
should be your GitHub username, with the extension `.md`. For example, the user
example_user would create the file `.github/contributors/example_user.md`.
Read this agreement carefully before signing. These terms and conditions
constitute a binding legal agreement.
## Contributor Agreement
1. The term "contribution" or "contributed materials" means any source code,
object code, patch, tool, sample, graphic, specification, manual,
documentation, or any other material posted or submitted by you to the project.
2. With respect to any worldwide copyrights, or copyright applications and
registrations, in your contribution:
* you hereby assign to us joint ownership, and to the extent that such
assignment is or becomes invalid, ineffective or unenforceable, you hereby
grant to us a perpetual, irrevocable, non-exclusive, worldwide, no-charge,
royalty-free, unrestricted license to exercise all rights under those
copyrights. This includes, at our option, the right to sublicense these same
rights to third parties through multiple levels of sublicensees or other
licensing arrangements;
* you agree that each of us can do all things in relation to your
contribution as if each of us were the sole owners, and if one of us makes
a derivative work of your contribution, the one who makes the derivative
work (or has it made will be the sole owner of that derivative work;
* you agree that you will not assert any moral rights in your contribution
against us, our licensees or transferees;
* you agree that we may register a copyright in your contribution and
exercise all ownership rights associated with it; and
* you agree that neither of us has any duty to consult with, obtain the
consent of, pay or render an accounting to the other for any use or
distribution of your contribution.
3. With respect to any patents you own, or that you can license without payment
to any third party, you hereby grant to us a perpetual, irrevocable,
non-exclusive, worldwide, no-charge, royalty-free license to:
* make, have made, use, sell, offer to sell, import, and otherwise transfer
your contribution in whole or in part, alone or in combination with or
included in any product, work or materials arising out of the project to
which your contribution was submitted, and
* at our option, to sublicense these same rights to third parties through
multiple levels of sublicensees or other licensing arrangements.
4. Except as set out above, you keep all right, title, and interest in your
contribution. The rights that you grant to us under these terms are effective
on the date you first submitted a contribution to us, even if your submission
took place before the date you sign these terms.
5. You covenant, represent, warrant and agree that:
* Each contribution that you submit is and shall be an original work of
authorship and you can legally grant the rights set out in this SCA;
* to the best of your knowledge, each contribution will not violate any
third party's copyrights, trademarks, patents, or other intellectual
property rights; and
* each contribution shall be in compliance with U.S. export control laws and
other applicable export and import laws. You agree to notify us if you
become aware of any circumstance which would make any of the foregoing
representations inaccurate in any respect. We may publicly disclose your
participation in the project, including the fact that you have signed the SCA.
6. This SCA is governed by the laws of the State of California and applicable
U.S. Federal law. Any choice of law rules will not apply.
7. Please place an “x” on one of the applicable statement below. Please do NOT
mark both statements:
* [ ] I am signing on behalf of myself as an individual and no other person
or entity, including my employer, has or will have rights with respect to my
contributions.
* [x] I am signing on behalf of my employer or a legal entity and I have the
actual authority to contractually bind that entity.
## Contributor Details
| Field | Entry |
|------------------------------- | -------------------- |
| Name | Borijan Georgievski |
| Company name (if applicable) | Netcetera |
| Title or role (if applicable) | Deta Scientist |
| Date | 2020.10.09 |
| GitHub username | borijang |
| Website (optional) | |

View File

@ -213,8 +213,12 @@ _ukrainian_lower = r"а-щюяіїєґ"
_ukrainian_upper = r"А-ЩЮЯІЇЄҐ" _ukrainian_upper = r"А-ЩЮЯІЇЄҐ"
_ukrainian = r"а-щюяіїєґА-ЩЮЯІЇЄҐ" _ukrainian = r"а-щюяіїєґА-ЩЮЯІЇЄҐ"
_upper = LATIN_UPPER + _russian_upper + _tatar_upper + _greek_upper + _ukrainian_upper _macedonian_lower = r"ѓѕјљњќѐѝ"
_lower = LATIN_LOWER + _russian_lower + _tatar_lower + _greek_lower + _ukrainian_lower _macedonian_upper = r"ЃЅЈЉЊЌЀЍ"
_macedonian = r"ѓѕјљњќѐѝЃЅЈЉЊЌЀЍ"
_upper = LATIN_UPPER + _russian_upper + _tatar_upper + _greek_upper + _ukrainian_upper + _macedonian_upper
_lower = LATIN_LOWER + _russian_lower + _tatar_lower + _greek_lower + _ukrainian_lower + _macedonian_lower
_uncased = ( _uncased = (
_bengali _bengali
@ -229,7 +233,7 @@ _uncased = (
+ _cjk + _cjk
) )
ALPHA = group_chars(LATIN + _russian + _tatar + _greek + _ukrainian + _uncased) ALPHA = group_chars(LATIN + _russian + _tatar + _greek + _ukrainian + _macedonian + _uncased)
ALPHA_LOWER = group_chars(_lower + _uncased) ALPHA_LOWER = group_chars(_lower + _uncased)
ALPHA_UPPER = group_chars(_upper + _uncased) ALPHA_UPPER = group_chars(_upper + _uncased)

41
spacy/lang/mk/__init__.py Normal file
View File

@ -0,0 +1,41 @@
# coding: utf8
from __future__ import unicode_literals
from .lemmatizer import MacedonianLemmatizer
from .stop_words import STOP_WORDS
from .tokenizer_exceptions import TOKENIZER_EXCEPTIONS
from .lex_attrs import LEX_ATTRS
from ..tokenizer_exceptions import BASE_EXCEPTIONS
from .morph_rules import MORPH_RULES
from ...language import Language
from ...attrs import LANG
from ...util import update_exc
from ...lookups import Lookups
class MacedonianDefaults(Language.Defaults):
lex_attr_getters = dict(Language.Defaults.lex_attr_getters)
lex_attr_getters[LANG] = lambda text: "mk"
# Optional: replace flags with custom functions, e.g. like_num()
lex_attr_getters.update(LEX_ATTRS)
# Merge base exceptions and custom tokenizer exceptions
tokenizer_exceptions = update_exc(BASE_EXCEPTIONS, TOKENIZER_EXCEPTIONS)
stop_words = STOP_WORDS
morph_rules = MORPH_RULES
@classmethod
def create_lemmatizer(cls, nlp=None, lookups=None):
if lookups is None:
lookups = Lookups()
return MacedonianLemmatizer(lookups)
class Macedonian(Language):
lang = "mk"
Defaults = MacedonianDefaults
__all__ = ["Macedonian"]

View File

@ -0,0 +1,64 @@
# coding: utf8
from __future__ import unicode_literals
from collections import OrderedDict
from ...lemmatizer import Lemmatizer
from ...parts_of_speech import NAMES as UPOS_NAMES
class MacedonianLemmatizer(Lemmatizer):
def __call__(self, string, univ_pos, morphology=None):
lookup_table = self.lookups.get_table("lemma_lookup", {})
if "lemma_rules" not in self.lookups:
return [lookup_table.get(string, string)]
if isinstance(univ_pos, int):
univ_pos = UPOS_NAMES.get(univ_pos, "X")
univ_pos = univ_pos.lower()
if univ_pos in ("", "eol", "space"):
return [string.lower()]
if string[-3:] == 'јќи':
string = string[:-3]
univ_pos = "verb"
if callable(self.is_base_form) and self.is_base_form(univ_pos, morphology):
return [string.lower()]
index_table = self.lookups.get_table("lemma_index", {})
exc_table = self.lookups.get_table("lemma_exc", {})
rules_table = self.lookups.get_table("lemma_rules", {})
if not any((index_table.get(univ_pos), exc_table.get(univ_pos), rules_table.get(univ_pos))):
if univ_pos == "propn":
return [string]
else:
return [string.lower()]
lemmas = self.lemmatize(
string,
index_table.get(univ_pos, {}),
exc_table.get(univ_pos, {}),
rules_table.get(univ_pos, []),
)
return lemmas
def lemmatize(self, string, index, exceptions, rules):
orig = string
string = string.lower()
forms = []
for old, new in rules:
if string.endswith(old):
form = string[: len(string) - len(old)] + new
if not form:
continue
if form in index or not form.isalpha():
forms.append(form)
forms = list(OrderedDict.fromkeys(forms))
for form in exceptions.get(string, []):
if form not in forms:
forms.insert(0, form)
if not forms:
forms.append(orig)
return forms

View File

@ -0,0 +1,58 @@
# coding: utf8
from __future__ import unicode_literals
from ...attrs import LIKE_NUM
_num_words = [
"нула", "еден", "една", "едно", "два", "две", "три", "четири", "пет", "шест", "седум", "осум", "девет", "десет",
"единаесет", "дванаесет", "тринаесет", "четиринаесет", "петнаесет", "шеснаесет", "седумнаесет", "осумнаесет",
"деветнаесет", "дваесет", "триесет", "четириесет", "педесет", "шеесет", "седумдесет", "осумдесет", "деведесет",
"сто", "двесте", "триста", "четиристотини", "петстотини", "шестотини", "седумстотини", "осумстотини",
"деветстотини", "илјада", "илјади", 'милион', 'милиони', 'милијарда', 'милијарди', 'билион', 'билиони',
"двајца", "тројца", "четворица", "петмина", "шестмина", "седуммина", "осуммина", "деветмина", "обата", "обајцата",
"прв", "втор", "трет", "четврт", "седм", "осм", "двестоти",
"два-три", "два-триесет", "два-триесетмина", "два-тринаесет", "два-тројца", "две-три", "две-тристотини",
"пет-шеесет", "пет-шеесетмина", "пет-шеснаесетмина", "пет-шест", "пет-шестмина", "пет-шестотини", "петина",
"осмина", "седум-осум", "седум-осумдесет", "седум-осуммина", "седум-осумнаесет", "седум-осумнаесетмина",
"три-четириесет", "три-четиринаесет", "шеесет", "шеесетина", "шеесетмина", "шеснаесет", "шеснаесетмина",
"шест-седум", "шест-седумдесет", "шест-седумнаесет", "шест-седумстотини", "шестоти", "шестотини"
]
def like_num(text):
if text.startswith(("+", "-", "±", "~")):
text = text[1:]
text = text.replace(",", "").replace(".", "")
if text.isdigit():
return True
if text.count("/") == 1:
num, denom = text.split("/")
if num.isdigit() and denom.isdigit():
return True
text_lower = text.lower()
if text_lower in _num_words:
return True
if text_lower.endswith(("а", "о", "и")):
if text_lower[:-1] in _num_words:
return True
if text_lower.endswith(("ти", "та", "то", "на")):
if text_lower[:-2] in _num_words:
return True
if text_lower.endswith(("ата", "иот", "ите", "ина", "чки")):
if text_lower[:-3] in _num_words:
return True
if text_lower.endswith(("мина", "тина")):
if text_lower[:-4] in _num_words:
return True
return False
LEX_ATTRS = {LIKE_NUM: like_num}

View File

@ -0,0 +1,641 @@
# coding: utf8
from __future__ import unicode_literals
from ...symbols import LEMMA, PRON_LEMMA
_subordinating_conjunctions = [
"кога",
"штом",
"штотуку",
"тукушто",
"откако",
"откога",
"пред да ",
"дури",
"додека",
"затоа што",
"зашто",
"бидејќи",
"поради тоа што",
"дека",
"оти",
"така што",
"да",
"за да",
"ако",
"без да",
"ли",
"иако",
"макар што",
"и покрај тоа што",
"и да",
"така како што",
"како да",
"како божем",
"што",
"кој",
"којшто",
"чиј",
"чијшто",
"дали",
"каков што",
"колкав што",
"каде што",
"како што",
"колку што",
"како",
]
_part = [
"де",
"бе",
"ма",
"барем",
"пак",
"меѓутоа",
"просто",
"да",
"не",
"ниту",
"зар",
"ли",
"дали",
"единствено",
"само",
"точно",
"токму",
"скоро",
"речиси",
"рамно",
"нека",
"ќе",
"уште",
"притоа",
"исто така",
"би",
]
_modal_verbs = [
"може",
"мора",
"треба",
]
sum_aux = [
"сум",
"си",
"е",
"сме",
"сте",
"се",
]
MORPH_RULES = {
"SUM": {word: {"POS": "AUX"} for word in sum_aux},
"IMA": {
"има": {"POS": "VERB"},
"имала": {"POS": "VERB"},
"имало": {"POS": "VERB"},
"имал": {"POS": "VERB"},
"имале": {"POS": "VERB"},
"имав": {"POS": "VERB"},
"имавте": {"POS": "VERB"},
"имаа": {"POS": "VERB"},
"имаше": {"POS": "VERB"},
"имам": {"POS": "AUX"},
"имаш": {"POS": "AUX"},
"имаме": {"POS": "AUX"},
"имате": {"POS": "AUX"},
"имаат": {"POS": "AUX"},
"имавме": {"POS": "AUX"},
},
"MD": {word: {"POS": "VERB"} for word in _modal_verbs},
"NN": {
"нешто": {"POS": "PRON"},
"некој": {"POS": "PRON"},
"некоја": {"POS": "PRON"},
"некое": {"POS": "PRON"},
"некои": {"POS": "PRON"},
"ништо": {"POS": "PRON"},
},
"PRP": {
"јас": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Sing",
"Case": "Nom",
},
"мене": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Sing",
"Case": "Acc",
},
"ме": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Sing",
"Case": "Acc",
},
"ми": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Sing",
"Case": "Dat",
},
"ти": {LEMMA: PRON_LEMMA, "POS": "PRON", "PronType": "Prs", "Person": "Two", "Number": "Sing", "Case": "Nom"},
"тебе": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Sing",
"Case": "Acc",
},
"те": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Sing",
"Case": "Acc",
},
"тој": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Masc",
"Case": "Nom",
},
"него": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Masc",
"Case": "Acc",
},
"го": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Masc",
"Case": "Acc",
},
"нему": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Masc",
"Case": "Dat",
},
"му": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Masc",
"Case": "Dat",
},
"таа": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Fem",
"Case": "Nom",
},
"неа": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Fem",
"Case": "Acc",
},
"ја": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Fem",
"Case": "Acc",
},
"нејзе": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Fem",
"Case": "Dat",
},
"ѝ": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Fem",
"Case": "Dat",
},
"тоа": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Sing",
"Gender": "Neut",
},
"ние": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Plur",
"Case": "Nom",
},
"нас": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Plur",
"Case": "Acc",
},
"нѐ": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Plur",
"Case": "Acc",
},
"нам": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Plur",
"Case": "Dat",
},
"ни": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "One",
"Number": "Plur",
"Case": "Dat",
},
"вие": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Plur",
"Case": "Nom",
},
"вас": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Plur",
"Case": "Acc",
},
"ве": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Plur",
"Case": "Acc",
},
"вам": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Plur",
"Case": "Dat",
},
"ви": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Two",
"Number": "Plur",
"Case": "Dat",
},
"тие": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Plur",
"Case": "Nom",
},
"нив": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Plur",
"Case": "Acc",
},
"ги": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Plur",
"Case": "Acc",
},
"ним": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Plur",
"Case": "Dat",
},
"им": {
LEMMA: PRON_LEMMA,
"POS": "PRON",
"PronType": "Prs",
"Person": "Three",
"Number": "Plur",
"Case": "Dat",
},
},
"VB": {
word: {"POS": "AUX"}
for word in ["сум", "има"]
},
"VBT": {
"бев ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "one"
},
"имав": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "one"
},
},
"VBM": {
"беше ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "two"
},
"имаше": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "two"
},
},
"VBK": {
"било ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Gender": "Neut",
"Person": "three",
},
"била ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Gender": "Fem",
"Person": "three",
},
"бил ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Gender": "Masc",
"Person": "three",
},
"беше ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "three",
"Person": "three",
},
"имаше": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Person": "three",
},
},
"VBTT": {
"бевме ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
"имавме": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
},
"VBMM": {
"бевте ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
"имавте": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
},
"VBKK": {
"биле ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Gender": "Plur",
},
"беа ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
"имаа": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
},
},
"VBP": {
"сум ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
"имам": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
},
"VBV": {
"си ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
"имаш": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
},
"VBZ": {
"е ": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
"има": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
},
},
"VBPP": {
"сме": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
"Number": "Plur",
},
"имаме": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
"Number": "Plur",
},
},
"VBVV": {
"сте": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
"Number": "Plur",
},
"имате": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
"Number": "Plur",
},
},
"VBZZ": {
"се": {
LEMMA: "сум",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Pres",
"Number": "Plur",
},
"имаат": {
LEMMA: "има",
"POS": "AUX",
"VerbForm": "Fin",
"Tense": "Past",
"Number": "Plur",
},
},
}
for tag, rules in MORPH_RULES.items():
for key, attrs in dict(rules).items():
rules[key.title()] = attrs

819
spacy/lang/mk/stop_words.py Normal file
View File

@ -0,0 +1,819 @@
# coding: utf8
from __future__ import unicode_literals
STOP_WORDS = set(
"""
а
абре
аи
ако
алало
ам
ама
аман
ами
амин
априли-ли-ли
ау
аух
ауч
ах
аха
аха-ха
аш
ашколсум
ашколсун
ај
ајде
ајс
аџаба
бавно
бам
бам-бум
бап
бар
баре
барем
бау
бау-бау
баш
бај
бе
беа
бев
бевме
бевте
без
безбели
бездруго
белки
беше
би
бидејќи
бим
бис
бла
блазе
богами
божем
боц
браво
бравос
бре
бреј
брзо
бришка
бррр
бу
бум
буф
буц
бујрум
ваа
вам
варај
варда
вас
вај
ве
велат
вели
версус
веќе
ви
виа
види
вие
вистина
витос
внатре
во
воз
вон
впрочем
врв
вред
време
врз
всушност
втор
галиба
ги
гитла
го
годе
годишник
горе
гра
гуц
гљу
да
даан
дава
дал
дали
дан
два
дваесет
дванаесет
двајца
две
двесте
движам
движат
движи
движиме
движите
движиш
де
деведесет
девет
деветнаесет
деветстотини
деветти
дека
дел
делми
демек
десет
десетина
десетти
деситици
дејгиди
дејди
ди
дилми
дин
дип
дно
до
доволно
додека
додуша
докај
доколку
доправено
доправи
досамоти
доста
држи
дрн
друг
друга
другата
други
другиот
другите
друго
другото
дум
дур
дури
е
евала
еве
евет
ега
егиди
еден
едикојси
единаесет
единствено
еднаш
едно
ексик
ела
елбете
елем
ели
ем
еми
ене
ете
еурека
ех
еј
жими
жити
за
завал
заврши
зад
задека
задоволна
задржи
заедно
зар
зарад
заради
заре
зарем
затоа
зашто
згора
зема
земе
земува
зер
значи
зошто
зуј
и
иако
из
извезен
изгледа
измеѓу
износ
или
или-или
илјада
илјади
им
има
имаа
имаат
имавме
имавте
имам
имаме
имате
имаш
имаше
име
имено
именува
имплицира
имплицираат
имплицирам
имплицираме
имплицирате
имплицираш
инаку
индицира
исечок
исклучен
исклучена
исклучени
исклучено
искористен
искористена
искористени
искористено
искористи
искрај
исти
исто
итака
итн
их
иха
ихуу
иш
ишала
иј
ка
каде
кажува
како
каков
камоли
кај
ква
ки
кит
кло
клум
кога
кого
кого-годе
кое
кои
количество
количина
колку
кому
кон
користена
користени
користено
користи
кот
котрр
кош-кош
кој
која
којзнае
којшто
кр-кр-кр
крај
крек
крз
крк
крц
куку
кукуригу
куш
ле
лебами
леле
лели
ли
лиду
луп
ма
макар
малку
марш
мат
мац
машала
ме
мене
место
меѓу
меѓувреме
меѓутоа
ми
мое
може
можеби
молам
моли
мор
мора
море
мори
мразец
му
муклец
мутлак
муц
мјау
на
навидум
навистина
над
надвор
назад
накај
накрај
нали
нам
наместо
наоколу
направено
направи
напред
нас
наспоред
наспрема
наспроти
насред
натаму
натема
начин
наш
наша
наше
наши
нај
најдоцна
најмалку
најмногу
не
неа
него
негов
негова
негови
негово
незе
нека
некаде
некако
некаков
некого
некое
некои
неколку
некому
некој
некојси
нели
немој
нему
неоти
нечиј
нешто
нејзе
нејзин
нејзини
нејзино
нејсе
ни
нив
нивен
нивна
нивни
нивно
ние
низ
никаде
никако
никогаш
никого
никому
никој
ним
нити
нито
ниту
ничиј
ништо
но
нѐ
о
обр
ова
ова-она
оваа
овај
овде
овега
овие
овој
од
одавде
оди
однесува
односно
одошто
околу
олеле
олкацок
он
она
онаа
онака
онаков
онде
они
оние
оно
оној
оп
освем
освен
осем
осми
осум
осумдесет
осумнаесет
осумстотитни
отаде
оти
откако
откај
откога
отколку
оттаму
оттука
оф
ох
ој
па
пак
папа
пардон
пате-ќуте
пати
пау
паче
пеесет
пеки
пет
петнаесет
петстотини
петти
пи
пи-пи
пис
плас
плус
по
побавно
поблиску
побрзо
побуни
повеќе
повторно
под
подалеку
подолу
подоцна
подруго
позади
поинаква
поинакви
поинакво
поинаков
поинаку
покаже
покажува
покрај
полно
помалку
помеѓу
понатаму
понекогаш
понекој
поради
поразличен
поразлична
поразлични
поразлично
поседува
после
последен
последна
последни
последно
поспоро
потег
потоа
пошироко
прави
празно
прв
пред
през
преку
претежно
претходен
претходна
претходни
претходник
претходно
при
присвои
притоа
причинува
пријатно
просто
против
прр
пст
пук
пусто
пуф
пуј
пфуј
пшт
ради
различен
различна
различни
различно
разни
разоружен
разредлив
рамките
рамнообразно
растревожено
растреперено
расчувствувано
ратоборно
рече
роден
с
сакан
сам
сама
сами
самите
само
самоти
свое
свои
свој
своја
се
себе
себеси
сега
седми
седум
седумдесет
седумнаесет
седумстотини
секаде
секаков
секи
секогаш
секого
секому
секој
секојдневно
сем
сенешто
сепак
сериозен
сериозна
сериозни
сериозно
сет
сечиј
сешто
си
сиктер
сиот
сип
сиреч
сите
сичко
скок
скоро
скрц
следбеник
следбеничка
следен
следователно
следствено
сме
со
соне
сопствен
сопствена
сопствени
сопствено
сосе
сосем
сполај
според
споро
спрема
спроти
спротив
сред
среде
среќно
срочен
сст
става
ставаат
ставам
ставаме
ставате
ставаш
стави
сте
сто
стоп
страна
сум
сума
супер
сус
сѐ
та
таа
така
таква
такви
таков
тамам
таму
тангар-мангар
тандар-мандар
тап
твое
те
тебе
тебека
тек
текот
ти
тие
тизе
тик-так
тики
тоа
тогаш
тој
трак
трака-трука
трас
треба
трет
три
триесет
тринаест
триста
труп
трупа
трус
ту
тука
туку
тукушто
туф
у
уа
убаво
уви
ужасно
уз
ура
уу
уф
уха
уш
уште
фазен
фала
фил
филан
фис
фиу
фиљан
фоб
фон
ха
ха-ха
хе
хеј
хеј
хи
хм
хо
цак
цап
целина
цело
цигу-лигу
циц
чекај
често
четврт
четири
четириесет
четиринаесет
четирстотини
чие
чии
чик
чик-чирик
чини
чиш
чиј
чија
чијшто
чкрап
чому
чук
чукш
чуму
чунки
шеесет
шеснаесет
шест
шести
шестотини
ширум
шлак
шлап
шлапа-шлупа
шлуп
шмрк
што
штогоде
штом
штотуку
штрак
штрап
штрап-штруп
шуќур
ѓиди
ѓоа
ѓоамити
ѕан
ѕе
ѕин
ја
јадец
јазе
јали
јас
јаска
јок
ќе
ќешки
ѝ
џагара-магара
џанам
џив-џив
""".split()
)

View File

@ -0,0 +1,103 @@
# coding: utf8
from __future__ import unicode_literals
from ...symbols import ORTH, LEMMA, TAG, NORM, PRON_LEMMA
_exc = {}
_abbr_exc = [
{ORTH: "м", LEMMA: "метар", NORM: "метар"},
{ORTH: "мм", LEMMA: "милиметар", NORM: "милиметар"},
{ORTH: "цм", LEMMA: "центиметар", NORM: "центиметар"},
{ORTH: "см", LEMMA: "сантиметар", NORM: "сантиметар"},
{ORTH: "дм", LEMMA: "дециметар", NORM: "дециметар"},
{ORTH: "км", LEMMA: "километар", NORM: "километар"},
{ORTH: "кг", LEMMA: "килограм", NORM: "килограм"},
{ORTH: "дкг", LEMMA: "декаграм", NORM: "декаграм"},
{ORTH: "дг", LEMMA: "дециграм", NORM: "дециграм"},
{ORTH: "мг", LEMMA: "милиграм", NORM: "милиграм"},
{ORTH: "г", LEMMA: "грам", NORM: "грам"},
{ORTH: "т", LEMMA: "тон", NORM: "тон"},
{ORTH: "кл", LEMMA: "килолитар", NORM: "килолитар"},
{ORTH: "хл", LEMMA: "хектолитар", NORM: "хектолитар"},
{ORTH: "дкл", LEMMA: "декалитар", NORM: "декалитар"},
{ORTH: "л", LEMMA: "литар", NORM: "литар"},
{ORTH: "дл", LEMMA: "децилитар", NORM: "децилитар"}
]
for abbr in _abbr_exc:
_exc[abbr[ORTH]] = [abbr]
_abbr_line_exc = [
{ORTH: "д-р", LEMMA: "доктор", NORM: "доктор"},
{ORTH: "м-р", LEMMA: "магистер", NORM: "магистер"},
{ORTH: "г-ѓа", LEMMA: "госпоѓа", NORM: "госпоѓа"},
{ORTH: "г-ца", LEMMA: "госпоѓица", NORM: "госпоѓица"},
{ORTH: "г-дин", LEMMA: "господин", NORM: "господин"},
]
for abbr in _abbr_line_exc:
_exc[abbr[ORTH]] = [abbr]
_abbr_dot_exc = [
{ORTH: "в.", LEMMA: "век", NORM: "век"},
{ORTH: "в.д.", LEMMA: "вршител на должност", NORM: "вршител на должност"},
{ORTH: "г.", LEMMA: "година", NORM: "година"},
{ORTH: "г.г.", LEMMA: "господин господин", NORM: "господин господин"},
{ORTH: "м.р.", LEMMA: "машки род", NORM: "машки род"},
{ORTH: "год.", LEMMA: "женски род", NORM: "женски род"},
{ORTH: "с.р.", LEMMA: "среден род", NORM: "среден род"},
{ORTH: "н.е.", LEMMA: "наша ера", NORM: "наша ера"},
{ORTH: "о.г.", LEMMA: "оваа година", NORM: "оваа година"},
{ORTH: "о.м.", LEMMA: "овој месец", NORM: "овој месец"},
{ORTH: "с.", LEMMA: "село", NORM: "село"},
{ORTH: "т.", LEMMA: "точка", NORM: "точка"},
{ORTH: "т.е.", LEMMA: "то ест", NORM: "то ест"},
{ORTH: "т.н.", LEMMA: "таканаречен", NORM: "таканаречен"},
{ORTH: "бр.", LEMMA: "број", NORM: "број"},
{ORTH: "гр.", LEMMA: "град", NORM: "град"},
{ORTH: "др.", LEMMA: "другар", NORM: "другар"},
{ORTH: "и др.", LEMMA: "и друго", NORM: "и друго"},
{ORTH: "и сл.", LEMMA: "и слично", NORM: "и слично"},
{ORTH: "кн.", LEMMA: "книга", NORM: "книга"},
{ORTH: "мн.", LEMMA: "множина", NORM: "множина"},
{ORTH: "на пр.", LEMMA: "на пример", NORM: "на пример"},
{ORTH: "св.", LEMMA: "свети", NORM: "свети"},
{ORTH: "сп.", LEMMA: "списание", NORM: "списание"},
{ORTH: "с.", LEMMA: "страница", NORM: "страница"},
{ORTH: "стр.", LEMMA: "страница", NORM: "страница"},
{ORTH: "чл.", LEMMA: "член", NORM: "член"},
{ORTH: "арх.", LEMMA: "архитект", NORM: "архитект"},
{ORTH: "бел.", LEMMA: "белешка", NORM: "белешка"},
{ORTH: "гимн.", LEMMA: "гимназија", NORM: "гимназија"},
{ORTH: "ден.", LEMMA: "денар", NORM: "денар"},
{ORTH: "ул.", LEMMA: "улица", NORM: "улица"},
{ORTH: "инж.", LEMMA: "инженер", NORM: "инженер"},
{ORTH: "проф.", LEMMA: "професор", NORM: "професор"},
{ORTH: "студ.", LEMMA: "студент", NORM: "студент"},
{ORTH: "бот.", LEMMA: "ботаника", NORM: "ботаника"},
{ORTH: "мат.", LEMMA: "математика", NORM: "математика"},
{ORTH: "мед.", LEMMA: "медицина", NORM: "медицина"},
{ORTH: "прил.", LEMMA: "прилог", NORM: "прилог"},
{ORTH: "прид.", LEMMA: "придавка", NORM: "придавка"},
{ORTH: "сврз.", LEMMA: "сврзник", NORM: "сврзник"},
{ORTH: "физ.", LEMMA: "физика", NORM: "физика"},
{ORTH: "хем.", LEMMA: "хемија", NORM: "хемија"},
{ORTH: "пр. н.", LEMMA: "природни науки", NORM: "природни науки"},
{ORTH: "истор.", LEMMA: "историја", NORM: "историја"},
{ORTH: "геогр.", LEMMA: "географија", NORM: "географија"},
{ORTH: "литер.", LEMMA: "литература", NORM: "литература"},
]
for abbr in _abbr_dot_exc:
_exc[abbr[ORTH]] = [abbr]
TOKENIZER_EXCEPTIONS = _exc

View File

@ -170,6 +170,11 @@ def lt_tokenizer():
return get_lang_class("lt").Defaults.create_tokenizer() return get_lang_class("lt").Defaults.create_tokenizer()
@pytest.fixture(scope="session")
def mk_tokenizer():
return get_lang_class("mk").Defaults.create_tokenizer()
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def ml_tokenizer(): def ml_tokenizer():
return get_lang_class("ml").Defaults.create_tokenizer() return get_lang_class("ml").Defaults.create_tokenizer()

View File

View File

@ -0,0 +1,87 @@
# coding: utf8
from __future__ import unicode_literals
import pytest
from spacy.lang.mk.lex_attrs import like_num
def test_tokenizer_handles_long_text(mk_tokenizer):
text = """
Во организациските работи или на нашите собранија со членството, никој од нас не зборуваше за
организацијата и идеологијата. Работна беше нашата работа, а не идеолошка. Што се однесува до социјализмот на
Делчев, неговата дејност зборува сама за себе - спротивно. Во суштина, водачите си имаа свои основни погледи и
свои разбирања за положбата и работите, коишто стоеја пред нив и ги завршуваа со голема упорност, настојчивост и
насоченост. Значи, идеологија имаше, само што нивната идеологија имаше своја оригиналност. Македонија денеска,
чиста рожба на животот и положбата во Македонија, кои му служеа како база на неговите побуди, беше дејност која
имаше потреба од ум за да си најде своја смисла. Таквата идеологија и заемното дејство на умот и срцето му
помогнаа на Делчев да не се занесе по патот на својата идеологија... Во суштина, Организацијата и нејзините
водачи имаа свои разбирања за работите и положбата во идеен поглед, но тоа беше врската, животот и положбата во
Македонија и го внесуваа во својата идеологија гласот на своето срце, и на крај, прибегнуваа до умот,
за да најдат смисла или да ѝ дадат. Тоа содејство и заемен сооднос на умот и срцето му помогнаа на Делчев да ја
држи својата идеологија во сообразност со положбата на работите... Водачите навистина направија една жртва
бидејќи на населението не му зборуваа за своите мисли и идеи. Тие се одрекоа од секаква субјективност во своите
мисли. Целта беше да не се зголемуваат целите и задачите како и преданоста во работата. Населението не можеше да
ги разбере овие идеи...
"""
tokens = mk_tokenizer(text)
assert len(tokens) == 297
@pytest.mark.parametrize(
"word,match",
[
("10", True),
("1", True),
("10.000", True),
("1000", True),
("бројка", False),
("999,0", True),
("еден", True),
("два", True),
("цифра", False),
("десет", True),
("сто", True),
("број", False),
("илјада", True),
("илјади", True),
("милион", True),
(",", False),
("милијарда", True),
("билион", True),
]
)
def test_mk_lex_attrs_like_number(mk_tokenizer, word, match):
tokens = mk_tokenizer(word)
assert len(tokens) == 1
assert tokens[0].like_num == match
@pytest.mark.parametrize(
"word",
[
"двесте",
"два-три",
"пет-шест"
]
)
def test_mk_lex_attrs_capitals(word):
assert like_num(word)
assert like_num(word.upper())
@pytest.mark.parametrize(
"word",
[
"првиот",
"втора",
"четврт",
"четвртата",
"петти",
"петто",
"стоти",
"шеесетите",
"седумдесетите"
]
)
def test_mk_lex_attrs_like_number_for_ordinal(word):
assert like_num(word)