mirror of
https://github.com/explosion/spaCy.git
synced 2025-01-11 17:56:30 +03:00
Ukrainian language added. Small fixes in Russian (#3241)
* Classes for Ukrainian; small fix in Russian. * Contributor agreement
This commit is contained in:
parent
4684195822
commit
b41d64825a
106
.github/contributors/juliamakogon.md
vendored
Normal file
106
.github/contributors/juliamakogon.md
vendored
Normal 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 UG (haftungsbeschränkt)](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.
|
||||||
|
|
||||||
|
* [ ] 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 | Julia Makogon |
|
||||||
|
| Company name (if applicable) | Semantrum |
|
||||||
|
| Title or role (if applicable) | |
|
||||||
|
| Date | 07.02.2019 |
|
||||||
|
| GitHub username | juliamakogon |
|
||||||
|
| Website (optional) | |
|
|
@ -21,9 +21,11 @@ _tatar_lower = r'[әөүҗңһ]'
|
||||||
_tatar_upper = r'[ӘӨҮҖҢҺ]'
|
_tatar_upper = r'[ӘӨҮҖҢҺ]'
|
||||||
_greek_lower = r'[α-ωάέίόώήύ]'
|
_greek_lower = r'[α-ωάέίόώήύ]'
|
||||||
_greek_upper = r'[Α-ΩΆΈΊΌΏΉΎ]'
|
_greek_upper = r'[Α-ΩΆΈΊΌΏΉΎ]'
|
||||||
|
_ukrainian_lower = r'[а-щюяіїєґ]'
|
||||||
|
_ukrainian_upper = r'[А-ЩЮЯІЇЄҐ]'
|
||||||
|
|
||||||
_upper = [_latin_upper, _russian_upper, _tatar_upper, _greek_upper]
|
_upper = [_latin_upper, _russian_upper, _tatar_upper, _greek_upper, _ukrainian_upper]
|
||||||
_lower = [_latin_lower, _russian_lower, _tatar_lower, _greek_lower]
|
_lower = [_latin_lower, _russian_lower, _tatar_lower, _greek_lower, _ukrainian_lower]
|
||||||
_uncased = [_bengali, _hebrew, _persian, _sinhala]
|
_uncased = [_bengali, _hebrew, _persian, _sinhala]
|
||||||
|
|
||||||
ALPHA = merge_char_classes(_upper + _lower + _uncased)
|
ALPHA = merge_char_classes(_upper + _lower + _uncased)
|
||||||
|
@ -35,7 +37,7 @@ _units = ('km km² km³ m m² m³ dm dm² dm³ cm cm² cm³ mm mm² mm³ ha µm
|
||||||
'TB T G M K % км км² км³ м м² м³ дм дм² дм³ см см² см³ мм мм² мм³ нм '
|
'TB T G M K % км км² км³ м м² м³ дм дм² дм³ см см² см³ мм мм² мм³ нм '
|
||||||
'кг г мг м/с км/ч кПа Па мбар Кб КБ кб Мб МБ мб Гб ГБ гб Тб ТБ тб'
|
'кг г мг м/с км/ч кПа Па мбар Кб КБ кб Мб МБ мб Гб ГБ гб Тб ТБ тб'
|
||||||
'كم كم² كم³ م م² م³ سم سم² سم³ مم مم² مم³ كم غرام جرام جم كغ ملغ كوب اكواب')
|
'كم كم² كم³ م م² م³ سم سم² سم³ مم مم² مم³ كم غرام جرام جم كغ ملغ كوب اكواب')
|
||||||
_currency = r'\$ £ € ¥ ฿ US\$ C\$ A\$ ₽ ﷼'
|
_currency = r'\$ £ € ¥ ฿ US\$ C\$ A\$ ₽ ﷼ ₴'
|
||||||
|
|
||||||
# These expressions contain various unicode variations, including characters
|
# These expressions contain various unicode variations, including characters
|
||||||
# used in Chinese (see #1333, #1340, #1351) – unless there are cross-language
|
# used in Chinese (see #1333, #1340, #1351) – unless there are cross-language
|
||||||
|
|
|
@ -8,7 +8,7 @@ from ...lemmatizer import Lemmatizer
|
||||||
class RussianLemmatizer(Lemmatizer):
|
class RussianLemmatizer(Lemmatizer):
|
||||||
_morph = None
|
_morph = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, pymorphy2_lang='ru'):
|
||||||
super(RussianLemmatizer, self).__init__()
|
super(RussianLemmatizer, self).__init__()
|
||||||
try:
|
try:
|
||||||
from pymorphy2 import MorphAnalyzer
|
from pymorphy2 import MorphAnalyzer
|
||||||
|
@ -18,7 +18,7 @@ class RussianLemmatizer(Lemmatizer):
|
||||||
'try to fix it with "pip install pymorphy2==0.8"')
|
'try to fix it with "pip install pymorphy2==0.8"')
|
||||||
|
|
||||||
if RussianLemmatizer._morph is None:
|
if RussianLemmatizer._morph is None:
|
||||||
RussianLemmatizer._morph = MorphAnalyzer()
|
RussianLemmatizer._morph = MorphAnalyzer(lang=pymorphy2_lang)
|
||||||
|
|
||||||
def __call__(self, string, univ_pos, morphology=None):
|
def __call__(self, string, univ_pos, morphology=None):
|
||||||
univ_pos = self.normalize_univ_pos(univ_pos)
|
univ_pos = self.normalize_univ_pos(univ_pos)
|
||||||
|
|
|
@ -69,7 +69,9 @@ TAG_MAP = {
|
||||||
'ADJ__Degree=Pos|Number=Plur|Variant=Short': {POS: ADJ, 'Degree': 'Pos', 'Number': 'Plur', 'Variant': 'Short'},
|
'ADJ__Degree=Pos|Number=Plur|Variant=Short': {POS: ADJ, 'Degree': 'Pos', 'Number': 'Plur', 'Variant': 'Short'},
|
||||||
'ADJ__Foreign=Yes': {POS: ADJ, 'Foreign': 'Yes'},
|
'ADJ__Foreign=Yes': {POS: ADJ, 'Foreign': 'Yes'},
|
||||||
'ADJ___': {POS: ADJ},
|
'ADJ___': {POS: ADJ},
|
||||||
|
'ADJ': {POS: ADJ},
|
||||||
'ADP___': {POS: ADP},
|
'ADP___': {POS: ADP},
|
||||||
|
'ADP': {POS: ADP},
|
||||||
'ADV__Degree=Cmp': {POS: ADV, 'Degree': 'Cmp'},
|
'ADV__Degree=Cmp': {POS: ADV, 'Degree': 'Cmp'},
|
||||||
'ADV__Degree=Pos': {POS: ADV, 'Degree': 'Pos'},
|
'ADV__Degree=Pos': {POS: ADV, 'Degree': 'Pos'},
|
||||||
'ADV__Polarity=Neg': {POS: ADV, 'Polarity': 'Neg'},
|
'ADV__Polarity=Neg': {POS: ADV, 'Polarity': 'Neg'},
|
||||||
|
@ -91,6 +93,7 @@ TAG_MAP = {
|
||||||
'AUX__Aspect=Imp|Tense=Pres|VerbForm=Conv|Voice=Act': {POS: AUX, 'Aspect': 'Imp', 'Tense': 'Pres', 'VerbForm': 'Conv', 'Voice': 'Act'},
|
'AUX__Aspect=Imp|Tense=Pres|VerbForm=Conv|Voice=Act': {POS: AUX, 'Aspect': 'Imp', 'Tense': 'Pres', 'VerbForm': 'Conv', 'Voice': 'Act'},
|
||||||
'AUX__Aspect=Imp|VerbForm=Inf|Voice=Act': {POS: AUX, 'Aspect': 'Imp', 'VerbForm': 'Inf', 'Voice': 'Act'},
|
'AUX__Aspect=Imp|VerbForm=Inf|Voice=Act': {POS: AUX, 'Aspect': 'Imp', 'VerbForm': 'Inf', 'Voice': 'Act'},
|
||||||
'CCONJ___': {POS: CCONJ},
|
'CCONJ___': {POS: CCONJ},
|
||||||
|
'CCONJ': {POS: CCONJ},
|
||||||
'DET__Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing'},
|
'DET__Animacy=Inan|Case=Acc|Gender=Masc|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing'},
|
||||||
'DET__Animacy=Inan|Case=Acc|Gender=Neut|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Acc', 'Gender': 'Neut', 'Number': 'Sing'},
|
'DET__Animacy=Inan|Case=Acc|Gender=Neut|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Acc', 'Gender': 'Neut', 'Number': 'Sing'},
|
||||||
'DET__Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Gen', 'Gender': 'Fem', 'Number': 'Sing'},
|
'DET__Animacy=Inan|Case=Gen|Gender=Fem|Number=Sing': {POS: DET, 'Animacy': 'Inan', 'Case': 'Gen', 'Gender': 'Fem', 'Number': 'Sing'},
|
||||||
|
@ -124,6 +127,7 @@ TAG_MAP = {
|
||||||
'DET__Case=Nom|Number=Plur': {POS: DET, 'Case': 'Nom', 'Number': 'Plur'},
|
'DET__Case=Nom|Number=Plur': {POS: DET, 'Case': 'Nom', 'Number': 'Plur'},
|
||||||
'DET__Gender=Masc|Number=Sing': {POS: DET, 'Gender': 'Masc', 'Number': 'Sing'},
|
'DET__Gender=Masc|Number=Sing': {POS: DET, 'Gender': 'Masc', 'Number': 'Sing'},
|
||||||
'INTJ___': {POS: INTJ},
|
'INTJ___': {POS: INTJ},
|
||||||
|
'INTJ': {POS: INTJ},
|
||||||
'NOUN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Plur': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Plur'},
|
'NOUN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Plur': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Plur'},
|
||||||
'NOUN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Sing': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Sing'},
|
'NOUN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Sing': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Sing'},
|
||||||
'NOUN__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
'NOUN__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: NOUN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
||||||
|
@ -216,6 +220,7 @@ TAG_MAP = {
|
||||||
'NOUN__Case=Gen|Degree=Pos|Gender=Fem|Number=Sing': {POS: NOUN, 'Case': 'Gen', 'Degree': 'Pos', 'Gender': 'Fem', 'Number': 'Sing'},
|
'NOUN__Case=Gen|Degree=Pos|Gender=Fem|Number=Sing': {POS: NOUN, 'Case': 'Gen', 'Degree': 'Pos', 'Gender': 'Fem', 'Number': 'Sing'},
|
||||||
'NOUN__Foreign=Yes': {POS: NOUN, 'Foreign': 'Yes'},
|
'NOUN__Foreign=Yes': {POS: NOUN, 'Foreign': 'Yes'},
|
||||||
'NOUN___': {POS: NOUN},
|
'NOUN___': {POS: NOUN},
|
||||||
|
'NOUN': {POS: NOUN},
|
||||||
'NUM__Animacy=Anim|Case=Acc': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc'},
|
'NUM__Animacy=Anim|Case=Acc': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc'},
|
||||||
'NUM__Animacy=Anim|Case=Acc|Gender=Fem': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem'},
|
'NUM__Animacy=Anim|Case=Acc|Gender=Fem': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem'},
|
||||||
'NUM__Animacy=Anim|Case=Acc|Gender=Masc': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc'},
|
'NUM__Animacy=Anim|Case=Acc|Gender=Masc': {POS: NUM, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc'},
|
||||||
|
@ -247,9 +252,11 @@ TAG_MAP = {
|
||||||
'NUM__Case=Nom|Gender=Masc': {POS: NUM, 'Case': 'Nom', 'Gender': 'Masc'},
|
'NUM__Case=Nom|Gender=Masc': {POS: NUM, 'Case': 'Nom', 'Gender': 'Masc'},
|
||||||
'NUM__Case=Nom|Gender=Neut': {POS: NUM, 'Case': 'Nom', 'Gender': 'Neut'},
|
'NUM__Case=Nom|Gender=Neut': {POS: NUM, 'Case': 'Nom', 'Gender': 'Neut'},
|
||||||
'NUM___': {POS: NUM},
|
'NUM___': {POS: NUM},
|
||||||
|
'NUM': {POS: NUM},
|
||||||
'PART__Mood=Cnd': {POS: PART, 'Mood': 'Cnd'},
|
'PART__Mood=Cnd': {POS: PART, 'Mood': 'Cnd'},
|
||||||
'PART__Polarity=Neg': {POS: PART, 'Polarity': 'Neg'},
|
'PART__Polarity=Neg': {POS: PART, 'Polarity': 'Neg'},
|
||||||
'PART___': {POS: PART},
|
'PART___': {POS: PART},
|
||||||
|
'PART': {POS: PART},
|
||||||
'PRON__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
'PRON__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
||||||
'PRON__Animacy=Anim|Case=Acc|Number=Plur': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Acc', 'Number': 'Plur'},
|
'PRON__Animacy=Anim|Case=Acc|Number=Plur': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Acc', 'Number': 'Plur'},
|
||||||
'PRON__Animacy=Anim|Case=Dat|Gender=Masc|Number=Sing': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Dat', 'Gender': 'Masc', 'Number': 'Sing'},
|
'PRON__Animacy=Anim|Case=Dat|Gender=Masc|Number=Sing': {POS: PRON, 'Animacy': 'Anim', 'Case': 'Dat', 'Gender': 'Masc', 'Number': 'Sing'},
|
||||||
|
@ -327,6 +334,7 @@ TAG_MAP = {
|
||||||
'PRON__Case=Nom|Number=Sing|Person=2': {POS: PRON, 'Case': 'Nom', 'Number': 'Sing', 'Person': '2'},
|
'PRON__Case=Nom|Number=Sing|Person=2': {POS: PRON, 'Case': 'Nom', 'Number': 'Sing', 'Person': '2'},
|
||||||
'PRON__Number=Sing|Person=1': {POS: PRON, 'Number': 'Sing', 'Person': '1'},
|
'PRON__Number=Sing|Person=1': {POS: PRON, 'Number': 'Sing', 'Person': '1'},
|
||||||
'PRON___': {POS: PRON},
|
'PRON___': {POS: PRON},
|
||||||
|
'PRON': {POS: PRON},
|
||||||
'PROPN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Plur': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Plur'},
|
'PROPN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Plur': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Plur'},
|
||||||
'PROPN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Sing': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Sing'},
|
'PROPN__Animacy=Anim|Case=Acc|Gender=Fem|Number=Sing': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Fem', 'Number': 'Sing'},
|
||||||
'PROPN__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
'PROPN__Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur': {POS: PROPN, 'Animacy': 'Anim', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Plur'},
|
||||||
|
@ -422,10 +430,14 @@ TAG_MAP = {
|
||||||
'PROPN__Foreign=Yes': {POS: PROPN, 'Foreign': 'Yes'},
|
'PROPN__Foreign=Yes': {POS: PROPN, 'Foreign': 'Yes'},
|
||||||
'PROPN__Number=Sing': {POS: PROPN, 'Number': 'Sing'},
|
'PROPN__Number=Sing': {POS: PROPN, 'Number': 'Sing'},
|
||||||
'PROPN___': {POS: PROPN},
|
'PROPN___': {POS: PROPN},
|
||||||
|
'PROPN': {POS: PROPN},
|
||||||
'PUNCT___': {POS: PUNCT},
|
'PUNCT___': {POS: PUNCT},
|
||||||
|
'PUNCT': {POS: PUNCT},
|
||||||
'SCONJ__Mood=Cnd': {POS: SCONJ, 'Mood': 'Cnd'},
|
'SCONJ__Mood=Cnd': {POS: SCONJ, 'Mood': 'Cnd'},
|
||||||
'SCONJ___': {POS: SCONJ},
|
'SCONJ___': {POS: SCONJ},
|
||||||
|
'SCONJ': {POS: SCONJ},
|
||||||
'SYM___': {POS: SYM},
|
'SYM___': {POS: SYM},
|
||||||
|
'SYM': {POS: SYM},
|
||||||
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part|Voice=Act': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Past', 'VerbForm': 'Part', 'Voice': 'Act'},
|
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part|Voice=Act': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Past', 'VerbForm': 'Part', 'Voice': 'Act'},
|
||||||
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part|Voice=Mid': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Past', 'VerbForm': 'Part', 'Voice': 'Mid'},
|
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part|Voice=Mid': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Past', 'VerbForm': 'Part', 'Voice': 'Mid'},
|
||||||
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Pres|VerbForm=Part|Voice=Act': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Pres', 'VerbForm': 'Part', 'Voice': 'Act'},
|
'VERB__Animacy=Anim|Aspect=Imp|Case=Acc|Gender=Masc|Number=Sing|Tense=Pres|VerbForm=Part|Voice=Act': {POS: VERB, 'Animacy': 'Anim', 'Aspect': 'Imp', 'Case': 'Acc', 'Gender': 'Masc', 'Number': 'Sing', 'Tense': 'Pres', 'VerbForm': 'Part', 'Voice': 'Act'},
|
||||||
|
@ -726,6 +738,8 @@ TAG_MAP = {
|
||||||
'VERB__Aspect=Perf|VerbForm=Inf|Voice=Mid': {POS: VERB, 'Aspect': 'Perf', 'VerbForm': 'Inf', 'Voice': 'Mid'},
|
'VERB__Aspect=Perf|VerbForm=Inf|Voice=Mid': {POS: VERB, 'Aspect': 'Perf', 'VerbForm': 'Inf', 'Voice': 'Mid'},
|
||||||
'VERB__Voice=Act': {POS: VERB, 'Voice': 'Act'},
|
'VERB__Voice=Act': {POS: VERB, 'Voice': 'Act'},
|
||||||
'VERB___': {POS: VERB},
|
'VERB___': {POS: VERB},
|
||||||
|
'VERB': {POS: VERB},
|
||||||
'X__Foreign=Yes': {POS: X, 'Foreign': 'Yes'},
|
'X__Foreign=Yes': {POS: X, 'Foreign': 'Yes'},
|
||||||
'X___': {POS: X},
|
'X___': {POS: X},
|
||||||
|
'X': {POS: X},
|
||||||
}
|
}
|
||||||
|
|
75
spacy/lang/uk/__init__.py
Normal file
75
spacy/lang/uk/__init__.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# coding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .tokenizer_exceptions import TOKENIZER_EXCEPTIONS
|
||||||
|
from .stop_words import STOP_WORDS
|
||||||
|
from .lex_attrs import LEX_ATTRS
|
||||||
|
|
||||||
|
# uncomment if files are available
|
||||||
|
# from .norm_exceptions import NORM_EXCEPTIONS
|
||||||
|
# from .tag_map import TAG_MAP
|
||||||
|
# from .morph_rules import MORPH_RULES
|
||||||
|
|
||||||
|
# uncomment if lookup-based lemmatizer is available
|
||||||
|
# from .lemmatizer import LOOKUP
|
||||||
|
# from ...lemmatizerlookup import Lemmatizer
|
||||||
|
|
||||||
|
from ..tokenizer_exceptions import BASE_EXCEPTIONS
|
||||||
|
from ..norm_exceptions import BASE_NORMS
|
||||||
|
from ...util import update_exc, add_lookups
|
||||||
|
from ...language import Language
|
||||||
|
from ...attrs import LANG, LIKE_NUM, NORM
|
||||||
|
# from .tag_map import TAG_MAP
|
||||||
|
from .lemmatizer import UkrainianLemmatizer
|
||||||
|
|
||||||
|
|
||||||
|
# Create a Language subclass
|
||||||
|
# Documentation: https://spacy.io/docs/usage/adding-languages
|
||||||
|
|
||||||
|
# This file should be placed in spacy/lang/xx (ISO code of language).
|
||||||
|
# Before submitting a pull request, make sure the remove all comments from the
|
||||||
|
# language data files, and run at least the basic tokenizer tests. Simply add the
|
||||||
|
# language ID to the list of languages in spacy/tests/conftest.py to include it
|
||||||
|
# in the basic tokenizer sanity tests. You can optionally add a fixture for the
|
||||||
|
# language's tokenizer and add more specific tests. For more info, see the
|
||||||
|
# tests documentation: https://github.com/explosion/spaCy/tree/master/spacy/tests
|
||||||
|
|
||||||
|
|
||||||
|
class UkrainianDefaults(Language.Defaults):
|
||||||
|
lex_attr_getters = dict(Language.Defaults.lex_attr_getters)
|
||||||
|
lex_attr_getters[LANG] = lambda text: 'uk' # ISO code
|
||||||
|
# add more norm exception dictionaries here
|
||||||
|
lex_attr_getters[NORM] = add_lookups(Language.Defaults.lex_attr_getters[NORM], BASE_NORMS)
|
||||||
|
|
||||||
|
# overwrite functions for lexical attributes
|
||||||
|
lex_attr_getters.update(LEX_ATTRS)
|
||||||
|
|
||||||
|
# add custom tokenizer exceptions to base exceptions
|
||||||
|
tokenizer_exceptions = update_exc(BASE_EXCEPTIONS, TOKENIZER_EXCEPTIONS)
|
||||||
|
|
||||||
|
# add stop words
|
||||||
|
stop_words = STOP_WORDS
|
||||||
|
|
||||||
|
# if available: add tag map
|
||||||
|
# tag_map = dict(TAG_MAP)
|
||||||
|
|
||||||
|
# if available: add morph rules
|
||||||
|
# morph_rules = dict(MORPH_RULES)
|
||||||
|
|
||||||
|
# if available: add lookup lemmatizer
|
||||||
|
# @classmethod
|
||||||
|
# def create_lemmatizer(cls, nlp=None):
|
||||||
|
# return Lemmatizer(LOOKUP)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_lemmatizer(cls, nlp=None):
|
||||||
|
return UkrainianLemmatizer()
|
||||||
|
|
||||||
|
|
||||||
|
class Ukrainian(Language):
|
||||||
|
lang = 'uk' # ISO code
|
||||||
|
Defaults = UkrainianDefaults # set Defaults to custom language defaults
|
||||||
|
|
||||||
|
|
||||||
|
# set default export – this allows the language class to be lazy-loaded
|
||||||
|
__all__ = ['Ukrainian']
|
23
spacy/lang/uk/examples.py
Normal file
23
spacy/lang/uk/examples.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# coding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Example sentences to test spaCy and its language models.
|
||||||
|
|
||||||
|
>>> from spacy.lang.uk.examples import sentences
|
||||||
|
>>> docs = nlp.pipe(sentences)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
sentences = [
|
||||||
|
"Ніч на середу буде морозною.",
|
||||||
|
"Чим кращі книги ти читав, тим гірше спиш.", # Serhiy Zhadan
|
||||||
|
"Найстаріші ґудзики, відомі людству, археологи знайшли в долині ріки Інд.",
|
||||||
|
"Слов'янське слово «Україна» вперше згадується у Київському літописному зводі за Іпатіївським списком під 1187 роком.", # wikipedia
|
||||||
|
"Де у Києві найсмачніша кава?",
|
||||||
|
"Від Нижнього озера довгими дерев’яними сходами, над якими синьо й біло горіли маленькі коробочки-ліхтарики, підіймалися до нього двоє стовусів: найкращий друг Вертутій і його дванадцятилітній онук Чублик.", # blyznets_viktor_semenovych/zemlia_svitliachkiv
|
||||||
|
"Китайський космічний зонд \"Чан'е-4\" вперше в історії здійснив м'яку посадку на зворотному боці Місяця.",
|
||||||
|
"Коли до губ твоїх лишається півподиху, коли до губ твоїх лишається півкроку – зіниці твої виткані із подиву, в очах у тебе синьо і широко.", # Hryhorij Czubaj
|
||||||
|
"Дорогу сестру збираю у дорогу, а брати вирішили не брати машину." # homographs
|
||||||
|
]
|
12
spacy/lang/uk/lemmatizer.py
Normal file
12
spacy/lang/uk/lemmatizer.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from ..ru.lemmatizer import RussianLemmatizer
|
||||||
|
|
||||||
|
|
||||||
|
class UkrainianLemmatizer(RussianLemmatizer):
|
||||||
|
|
||||||
|
def __init__(self, pymorphy2_lang='ru'):
|
||||||
|
try:
|
||||||
|
super(UkrainianLemmatizer, self).__init__(pymorphy2_lang='uk')
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'The Ukrainian lemmatizer requires the pymorphy2 library and dictionaries: '
|
||||||
|
'try to fix it with "pip install git+https://github.com/kmike/pymorphy2.git pymorphy2-dicts-uk"')
|
42
spacy/lang/uk/lex_attrs.py
Normal file
42
spacy/lang/uk/lex_attrs.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# coding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# import the symbols for the attrs you want to overwrite
|
||||||
|
from ...attrs import LIKE_NUM
|
||||||
|
|
||||||
|
|
||||||
|
# Overwriting functions for lexical attributes
|
||||||
|
# Documentation: https://localhost:1234/docs/usage/adding-languages#lex-attrs
|
||||||
|
# Most of these functions, like is_lower or like_url should be language-
|
||||||
|
# independent. Others, like like_num (which includes both digits and number
|
||||||
|
# words), requires customisation.
|
||||||
|
|
||||||
|
|
||||||
|
# Example: check if token resembles a number
|
||||||
|
_num_words = ["більйон", "вісім", "вісімдесят", "вісімнадцять", "вісімсот", "восьмий", "два", "двадцять", "дванадцять",
|
||||||
|
"двісті", "дев'яносто", "дев'ятнадцять", "дев'ятсот", "дев'ять", "десять", "децильйон", "квадрильйон",
|
||||||
|
"квінтильйон", "мільйон", "мільярд", "нонильйон", "один", "одинадцять", "октильйон", "п'ятий",
|
||||||
|
"п'ятисотий", "п'ятнадцять", "п'ятсот", "п'ять", "секстильйон", "септильйон", "сім", "сімдесят",
|
||||||
|
"сімнадцять", "сімсот", "сорок", "сто", "тисяча", "три", "тридцять", "трильйон", "тринадцять", "триста",
|
||||||
|
"чотири", "чотириста", "чотирнадцять", "шістдесят", "шістнадцять", "шістсот", "шість"]
|
||||||
|
|
||||||
|
|
||||||
|
def like_num(text):
|
||||||
|
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
|
||||||
|
if text in _num_words:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# Create dictionary of functions to overwrite. The default lex_attr_getters are
|
||||||
|
# updated with this one, so only the functions defined here are overwritten.
|
||||||
|
|
||||||
|
LEX_ATTRS = {
|
||||||
|
LIKE_NUM: like_num
|
||||||
|
}
|
404
spacy/lang/uk/stop_words.py
Normal file
404
spacy/lang/uk/stop_words.py
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
# encoding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
# Add stop words
|
||||||
|
# Documentation: https://spacy.io/docs/usage/adding-languages#stop-words
|
||||||
|
# To improve readability, words should be ordered alphabetically and separated
|
||||||
|
# by spaces and newlines. When adding stop words from an online source, always
|
||||||
|
# include the link in a comment. Make sure to proofread and double-check the
|
||||||
|
# words – lists available online are often known to contain mistakes.
|
||||||
|
|
||||||
|
|
||||||
|
STOP_WORDS = set("""а
|
||||||
|
або
|
||||||
|
адже
|
||||||
|
але
|
||||||
|
алло
|
||||||
|
багато
|
||||||
|
без
|
||||||
|
безперервно
|
||||||
|
би
|
||||||
|
більш
|
||||||
|
більше
|
||||||
|
біля
|
||||||
|
близько
|
||||||
|
був
|
||||||
|
буває
|
||||||
|
буде
|
||||||
|
будемо
|
||||||
|
будете
|
||||||
|
будеш
|
||||||
|
буду
|
||||||
|
будуть
|
||||||
|
будь
|
||||||
|
була
|
||||||
|
були
|
||||||
|
було
|
||||||
|
бути
|
||||||
|
бывь
|
||||||
|
в
|
||||||
|
важлива
|
||||||
|
важливе
|
||||||
|
важливий
|
||||||
|
важливі
|
||||||
|
вам
|
||||||
|
вами
|
||||||
|
вас
|
||||||
|
ваш
|
||||||
|
ваша
|
||||||
|
ваше
|
||||||
|
ваші
|
||||||
|
вгорі
|
||||||
|
вгору
|
||||||
|
вдалині
|
||||||
|
вже
|
||||||
|
ви
|
||||||
|
від
|
||||||
|
відсотків
|
||||||
|
він
|
||||||
|
вісім
|
||||||
|
вісімнадцятий
|
||||||
|
вісімнадцять
|
||||||
|
вниз
|
||||||
|
внизу
|
||||||
|
вона
|
||||||
|
вони
|
||||||
|
воно
|
||||||
|
восьмий
|
||||||
|
всього
|
||||||
|
втім
|
||||||
|
г
|
||||||
|
геть
|
||||||
|
говорив
|
||||||
|
говорить
|
||||||
|
давно
|
||||||
|
далеко
|
||||||
|
далі
|
||||||
|
дарма
|
||||||
|
два
|
||||||
|
двадцятий
|
||||||
|
двадцять
|
||||||
|
дванадцятий
|
||||||
|
дванадцять
|
||||||
|
дві
|
||||||
|
двох
|
||||||
|
де
|
||||||
|
дев'ятий
|
||||||
|
дев'ятнадцятий
|
||||||
|
дев'ятнадцять
|
||||||
|
дев'ять
|
||||||
|
декілька
|
||||||
|
день
|
||||||
|
десятий
|
||||||
|
десять
|
||||||
|
дійсно
|
||||||
|
для
|
||||||
|
дня
|
||||||
|
до
|
||||||
|
добре
|
||||||
|
довго
|
||||||
|
доки
|
||||||
|
досить
|
||||||
|
другий
|
||||||
|
дуже
|
||||||
|
же
|
||||||
|
життя
|
||||||
|
з
|
||||||
|
за
|
||||||
|
завжди
|
||||||
|
зазвичай
|
||||||
|
зайнята
|
||||||
|
зайнятий
|
||||||
|
зайняті
|
||||||
|
зайнято
|
||||||
|
занадто
|
||||||
|
зараз
|
||||||
|
зате
|
||||||
|
звичайно
|
||||||
|
звідси
|
||||||
|
звідусіль
|
||||||
|
здається
|
||||||
|
значить
|
||||||
|
знову
|
||||||
|
зовсім
|
||||||
|
ім'я
|
||||||
|
іноді
|
||||||
|
інша
|
||||||
|
інше
|
||||||
|
інший
|
||||||
|
інших
|
||||||
|
інші
|
||||||
|
її
|
||||||
|
їй
|
||||||
|
їх
|
||||||
|
його
|
||||||
|
йому
|
||||||
|
ким
|
||||||
|
кого
|
||||||
|
кожен
|
||||||
|
кожна
|
||||||
|
кожне
|
||||||
|
кожні
|
||||||
|
коли
|
||||||
|
кому
|
||||||
|
краще
|
||||||
|
крейдуючи
|
||||||
|
кругом
|
||||||
|
куди
|
||||||
|
ласка
|
||||||
|
лише
|
||||||
|
люди
|
||||||
|
людина
|
||||||
|
майже
|
||||||
|
мало
|
||||||
|
мати
|
||||||
|
мене
|
||||||
|
мені
|
||||||
|
менш
|
||||||
|
менше
|
||||||
|
ми
|
||||||
|
мимо
|
||||||
|
міг
|
||||||
|
між
|
||||||
|
мій
|
||||||
|
мільйонів
|
||||||
|
мною
|
||||||
|
могти
|
||||||
|
моє
|
||||||
|
мож
|
||||||
|
може
|
||||||
|
можна
|
||||||
|
можно
|
||||||
|
можуть
|
||||||
|
можхо
|
||||||
|
мої
|
||||||
|
мор
|
||||||
|
моя
|
||||||
|
на
|
||||||
|
навіть
|
||||||
|
навіщо
|
||||||
|
навкруги
|
||||||
|
нагорі
|
||||||
|
над
|
||||||
|
назад
|
||||||
|
найбільш
|
||||||
|
нам
|
||||||
|
нами
|
||||||
|
нарешті
|
||||||
|
нас
|
||||||
|
наш
|
||||||
|
наша
|
||||||
|
наше
|
||||||
|
наші
|
||||||
|
не
|
||||||
|
небагато
|
||||||
|
недалеко
|
||||||
|
немає
|
||||||
|
нерідко
|
||||||
|
нещодавно
|
||||||
|
нею
|
||||||
|
нибудь
|
||||||
|
нижче
|
||||||
|
низько
|
||||||
|
ним
|
||||||
|
ними
|
||||||
|
них
|
||||||
|
ні
|
||||||
|
ніби
|
||||||
|
ніколи
|
||||||
|
нікуди
|
||||||
|
нічого
|
||||||
|
ну
|
||||||
|
нх
|
||||||
|
нього
|
||||||
|
о
|
||||||
|
обоє
|
||||||
|
один
|
||||||
|
одинадцятий
|
||||||
|
одинадцять
|
||||||
|
однієї
|
||||||
|
одній
|
||||||
|
одного
|
||||||
|
означає
|
||||||
|
окрім
|
||||||
|
он
|
||||||
|
особливо
|
||||||
|
ось
|
||||||
|
перед
|
||||||
|
перший
|
||||||
|
під
|
||||||
|
пізніше
|
||||||
|
пір
|
||||||
|
по
|
||||||
|
повинно
|
||||||
|
подів
|
||||||
|
поки
|
||||||
|
пора
|
||||||
|
поруч
|
||||||
|
посеред
|
||||||
|
потім
|
||||||
|
потрібно
|
||||||
|
почала
|
||||||
|
прекрасне
|
||||||
|
прекрасно
|
||||||
|
при
|
||||||
|
про
|
||||||
|
просто
|
||||||
|
проте
|
||||||
|
проти
|
||||||
|
п'ятий
|
||||||
|
п'ятнадцятий
|
||||||
|
п'ятнадцять
|
||||||
|
п'ять
|
||||||
|
раз
|
||||||
|
раніше
|
||||||
|
рано
|
||||||
|
раптом
|
||||||
|
рік
|
||||||
|
роки
|
||||||
|
років
|
||||||
|
року
|
||||||
|
сам
|
||||||
|
сама
|
||||||
|
саме
|
||||||
|
самим
|
||||||
|
самими
|
||||||
|
самих
|
||||||
|
самі
|
||||||
|
самій
|
||||||
|
само
|
||||||
|
самого
|
||||||
|
самому
|
||||||
|
саму
|
||||||
|
світу
|
||||||
|
свого
|
||||||
|
своє
|
||||||
|
свої
|
||||||
|
своїй
|
||||||
|
своїх
|
||||||
|
свою
|
||||||
|
сеаой
|
||||||
|
себе
|
||||||
|
сім
|
||||||
|
сімнадцятий
|
||||||
|
сімнадцять
|
||||||
|
сказав
|
||||||
|
сказала
|
||||||
|
сказати
|
||||||
|
скільки
|
||||||
|
скрізь
|
||||||
|
собі
|
||||||
|
собою
|
||||||
|
спасибі
|
||||||
|
спочатку
|
||||||
|
справ
|
||||||
|
став
|
||||||
|
суть
|
||||||
|
сьогодні
|
||||||
|
сьомий
|
||||||
|
т
|
||||||
|
та
|
||||||
|
так
|
||||||
|
така
|
||||||
|
таке
|
||||||
|
такий
|
||||||
|
такі
|
||||||
|
також
|
||||||
|
там
|
||||||
|
твій
|
||||||
|
твоє
|
||||||
|
твоя
|
||||||
|
те
|
||||||
|
тебе
|
||||||
|
теж
|
||||||
|
тепер
|
||||||
|
ти
|
||||||
|
тим
|
||||||
|
тими
|
||||||
|
тисяч
|
||||||
|
тих
|
||||||
|
ті
|
||||||
|
тією
|
||||||
|
тільки
|
||||||
|
тобі
|
||||||
|
тобою
|
||||||
|
того
|
||||||
|
тоді
|
||||||
|
той
|
||||||
|
том
|
||||||
|
тому
|
||||||
|
треба
|
||||||
|
третій
|
||||||
|
три
|
||||||
|
тринадцятий
|
||||||
|
тринадцять
|
||||||
|
трохи
|
||||||
|
ту
|
||||||
|
туди
|
||||||
|
тут
|
||||||
|
у
|
||||||
|
увесь
|
||||||
|
уміти
|
||||||
|
усе
|
||||||
|
усі
|
||||||
|
усім
|
||||||
|
усіма
|
||||||
|
усіх
|
||||||
|
усію
|
||||||
|
усього
|
||||||
|
усьому
|
||||||
|
усю
|
||||||
|
усюди
|
||||||
|
уся
|
||||||
|
хіба
|
||||||
|
хотіти
|
||||||
|
хоч
|
||||||
|
хоча
|
||||||
|
хочеш
|
||||||
|
хто
|
||||||
|
це
|
||||||
|
цей
|
||||||
|
цим
|
||||||
|
цими
|
||||||
|
цих
|
||||||
|
ці
|
||||||
|
цій
|
||||||
|
цього
|
||||||
|
цьому
|
||||||
|
цю
|
||||||
|
ця
|
||||||
|
час
|
||||||
|
частіше
|
||||||
|
часто
|
||||||
|
часу
|
||||||
|
через
|
||||||
|
четвертий
|
||||||
|
чи
|
||||||
|
чим
|
||||||
|
численна
|
||||||
|
численне
|
||||||
|
численний
|
||||||
|
численні
|
||||||
|
чого
|
||||||
|
чому
|
||||||
|
чотири
|
||||||
|
чотирнадцятий
|
||||||
|
чотирнадцять
|
||||||
|
шістнадцятий
|
||||||
|
шістнадцять
|
||||||
|
шість
|
||||||
|
шостий
|
||||||
|
ще
|
||||||
|
що
|
||||||
|
щоб
|
||||||
|
я
|
||||||
|
як
|
||||||
|
яка
|
||||||
|
який
|
||||||
|
яких
|
||||||
|
які
|
||||||
|
якій
|
||||||
|
якого
|
||||||
|
якщо
|
||||||
|
""".split())
|
36
spacy/lang/uk/tag_map.py
Normal file
36
spacy/lang/uk/tag_map.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# coding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ..symbols import POS, ADV, NOUN, ADP, PRON, SCONJ, PROPN, DET, SYM, INTJ
|
||||||
|
from ..symbols import PUNCT, NUM, AUX, X, CONJ, ADJ, VERB, PART, SPACE, CCONJ
|
||||||
|
|
||||||
|
|
||||||
|
# Add a tag map
|
||||||
|
# Documentation: https://spacy.io/docs/usage/adding-languages#tag-map
|
||||||
|
# Universal Dependencies: http://universaldependencies.org/u/pos/all.html
|
||||||
|
# The keys of the tag map should be strings in your tag set. The dictionary must
|
||||||
|
# have an entry POS whose value is one of the Universal Dependencies tags.
|
||||||
|
# Optionally, you can also include morphological features or other attributes.
|
||||||
|
|
||||||
|
|
||||||
|
TAG_MAP = {
|
||||||
|
"ADV": {POS: ADV},
|
||||||
|
"NOUN": {POS: NOUN},
|
||||||
|
"ADP": {POS: ADP},
|
||||||
|
"PRON": {POS: PRON},
|
||||||
|
"SCONJ": {POS: SCONJ},
|
||||||
|
"PROPN": {POS: PROPN},
|
||||||
|
"DET": {POS: DET},
|
||||||
|
"SYM": {POS: SYM},
|
||||||
|
"INTJ": {POS: INTJ},
|
||||||
|
"PUNCT": {POS: PUNCT},
|
||||||
|
"NUM": {POS: NUM},
|
||||||
|
"AUX": {POS: AUX},
|
||||||
|
"X": {POS: X},
|
||||||
|
"CONJ": {POS: CONJ},
|
||||||
|
"CCONJ": {POS: CCONJ},
|
||||||
|
"ADJ": {POS: ADJ},
|
||||||
|
"VERB": {POS: VERB},
|
||||||
|
"PART": {POS: PART},
|
||||||
|
"SP": {POS: SPACE}
|
||||||
|
}
|
38
spacy/lang/uk/tokenizer_exceptions.py
Normal file
38
spacy/lang/uk/tokenizer_exceptions.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# coding: utf8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# import symbols – if you need to use more, add them here
|
||||||
|
from ...symbols import ORTH, LEMMA, POS, NORM, NOUN
|
||||||
|
|
||||||
|
|
||||||
|
# Add tokenizer exceptions
|
||||||
|
# Documentation: https://spacy.io/docs/usage/adding-languages#tokenizer-exceptions
|
||||||
|
# Feel free to use custom logic to generate repetitive exceptions more efficiently.
|
||||||
|
# If an exception is split into more than one token, the ORTH values combined always
|
||||||
|
# need to match the original string.
|
||||||
|
|
||||||
|
# Exceptions should be added in the following format:
|
||||||
|
|
||||||
|
_exc = {}
|
||||||
|
|
||||||
|
for exc_data in [
|
||||||
|
{ORTH: "вул.", LEMMA: "вулиця", NORM: "вулиця", POS: NOUN},
|
||||||
|
{ORTH: "ім.", LEMMA: "ім'я", NORM: "імені", POS: NOUN},
|
||||||
|
{ORTH: "просп.", LEMMA: "проспект", NORM: "проспект", POS: NOUN},
|
||||||
|
{ORTH: "бул.", LEMMA: "бульвар", NORM: "бульвар", POS: NOUN},
|
||||||
|
{ORTH: "пров.", LEMMA: "провулок", NORM: "провулок", POS: NOUN},
|
||||||
|
{ORTH: "пл.", LEMMA: "площа", NORM: "площа", POS: NOUN},
|
||||||
|
{ORTH: "г.", LEMMA: "гора", NORM: "гора", POS: NOUN},
|
||||||
|
{ORTH: "п.", LEMMA: "пан", NORM: "пан", POS: NOUN},
|
||||||
|
{ORTH: "м.", LEMMA: "місто", NORM: "місто", POS: NOUN},
|
||||||
|
{ORTH: "проф.", LEMMA: "професор", NORM: "професор", POS: NOUN},
|
||||||
|
{ORTH: "акад.", LEMMA: "академік", NORM: "академік", POS: NOUN},
|
||||||
|
{ORTH: "доц.", LEMMA: "доцент", NORM: "доцент", POS: NOUN},
|
||||||
|
{ORTH: "оз.", LEMMA: "озеро", NORM: "озеро", POS: NOUN}]:
|
||||||
|
_exc[exc_data[ORTH]] = [exc_data]
|
||||||
|
|
||||||
|
|
||||||
|
# To keep things clean and readable, it's recommended to only declare the
|
||||||
|
# TOKENIZER_EXCEPTIONS at the bottom:
|
||||||
|
|
||||||
|
TOKENIZER_EXCEPTIONS = _exc
|
|
@ -15,7 +15,7 @@ from .. import util
|
||||||
# here if it's using spaCy's tokenizer (not a different library)
|
# here if it's using spaCy's tokenizer (not a different library)
|
||||||
# TODO: re-implement generic tokenizer tests
|
# TODO: re-implement generic tokenizer tests
|
||||||
_languages = ['bn', 'ca', 'da', 'de', 'el', 'en', 'es', 'fi', 'fr', 'ga', 'he', 'hu', 'id',
|
_languages = ['bn', 'ca', 'da', 'de', 'el', 'en', 'es', 'fi', 'fr', 'ga', 'he', 'hu', 'id',
|
||||||
'it', 'nb', 'nl', 'pl', 'pt', 'ro', 'ru', 'sv', 'tr', 'ar', 'ur', 'tt',
|
'it', 'nb', 'nl', 'pl', 'pt', 'ro', 'ru', 'sv', 'tr', 'ar', 'ur', 'tt', 'uk',
|
||||||
'xx']
|
'xx']
|
||||||
|
|
||||||
_models = {'en': ['en_core_web_sm'],
|
_models = {'en': ['en_core_web_sm'],
|
||||||
|
@ -49,6 +49,11 @@ def RU(request):
|
||||||
pymorphy = pytest.importorskip('pymorphy2')
|
pymorphy = pytest.importorskip('pymorphy2')
|
||||||
return util.get_lang_class('ru')()
|
return util.get_lang_class('ru')()
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def UK(request):
|
||||||
|
pymorphy = pytest.importorskip('pymorphy2')
|
||||||
|
return util.get_lang_class('uk')()
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def JA(request):
|
def JA(request):
|
||||||
mecab = pytest.importorskip("MeCab")
|
mecab = pytest.importorskip("MeCab")
|
||||||
|
@ -175,6 +180,11 @@ def ru_tokenizer():
|
||||||
pymorphy = pytest.importorskip('pymorphy2')
|
pymorphy = pytest.importorskip('pymorphy2')
|
||||||
return util.get_lang_class('ru').Defaults.create_tokenizer()
|
return util.get_lang_class('ru').Defaults.create_tokenizer()
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def uk_tokenizer():
|
||||||
|
pymorphy = pytest.importorskip('pymorphy2')
|
||||||
|
return util.get_lang_class('uk').Defaults.create_tokenizer()
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def ca_tokenizer():
|
def ca_tokenizer():
|
||||||
return util.get_lang_class('ca').Defaults.create_tokenizer()
|
return util.get_lang_class('ca').Defaults.create_tokenizer()
|
||||||
|
|
0
spacy/tests/lang/uk/__init__.py
Normal file
0
spacy/tests/lang/uk/__init__.py
Normal file
128
spacy/tests/lang/uk/test_tokenizer.py
Normal file
128
spacy/tests/lang/uk/test_tokenizer.py
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# coding: utf-8
|
||||||
|
"""Test that open, closed and paired punctuation is split off correctly."""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
PUNCT_OPEN = ['(', '[', '{', '*']
|
||||||
|
PUNCT_CLOSE = [')', ']', '}', '*']
|
||||||
|
PUNCT_PAIRED = [('(', ')'), ('[', ']'), ('{', '}'), ('*', '*')]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('text', ["(", "((", "<"])
|
||||||
|
def test_uk_tokenizer_handles_only_punct(uk_tokenizer, text):
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert len(tokens) == len(text)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_OPEN)
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_open_punct(uk_tokenizer, punct, text):
|
||||||
|
tokens = uk_tokenizer(punct + text)
|
||||||
|
assert len(tokens) == 2
|
||||||
|
assert tokens[0].text == punct
|
||||||
|
assert tokens[1].text == text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_CLOSE)
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_close_punct(uk_tokenizer, punct, text):
|
||||||
|
tokens = uk_tokenizer(text + punct)
|
||||||
|
assert len(tokens) == 2
|
||||||
|
assert tokens[0].text == text
|
||||||
|
assert tokens[1].text == punct
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_OPEN)
|
||||||
|
@pytest.mark.parametrize('punct_add', ["`"])
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_two_diff_open_punct(uk_tokenizer, punct, punct_add, text):
|
||||||
|
tokens = uk_tokenizer(punct + punct_add + text)
|
||||||
|
assert len(tokens) == 3
|
||||||
|
assert tokens[0].text == punct
|
||||||
|
assert tokens[1].text == punct_add
|
||||||
|
assert tokens[2].text == text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_CLOSE)
|
||||||
|
@pytest.mark.parametrize('punct_add', ["'"])
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_two_diff_close_punct(uk_tokenizer, punct, punct_add, text):
|
||||||
|
tokens = uk_tokenizer(text + punct + punct_add)
|
||||||
|
assert len(tokens) == 3
|
||||||
|
assert tokens[0].text == text
|
||||||
|
assert tokens[1].text == punct
|
||||||
|
assert tokens[2].text == punct_add
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_OPEN)
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_same_open_punct(uk_tokenizer, punct, text):
|
||||||
|
tokens = uk_tokenizer(punct + punct + punct + text)
|
||||||
|
assert len(tokens) == 4
|
||||||
|
assert tokens[0].text == punct
|
||||||
|
assert tokens[3].text == text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct', PUNCT_CLOSE)
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_same_close_punct(uk_tokenizer, punct, text):
|
||||||
|
tokens = uk_tokenizer(text + punct + punct + punct)
|
||||||
|
assert len(tokens) == 4
|
||||||
|
assert tokens[0].text == text
|
||||||
|
assert tokens[1].text == punct
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('text', ["'Тест"])
|
||||||
|
def test_uk_tokenizer_splits_open_appostrophe(uk_tokenizer, text):
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert len(tokens) == 2
|
||||||
|
assert tokens[0].text == "'"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('text', ["Тест''"])
|
||||||
|
def test_uk_tokenizer_splits_double_end_quote(uk_tokenizer, text):
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert len(tokens) == 2
|
||||||
|
tokens_punct = uk_tokenizer("''")
|
||||||
|
assert len(tokens_punct) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct_open,punct_close', PUNCT_PAIRED)
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_splits_open_close_punct(uk_tokenizer, punct_open,
|
||||||
|
punct_close, text):
|
||||||
|
tokens = uk_tokenizer(punct_open + text + punct_close)
|
||||||
|
assert len(tokens) == 3
|
||||||
|
assert tokens[0].text == punct_open
|
||||||
|
assert tokens[1].text == text
|
||||||
|
assert tokens[2].text == punct_close
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('punct_open,punct_close', PUNCT_PAIRED)
|
||||||
|
@pytest.mark.parametrize('punct_open2,punct_close2', [("`", "'")])
|
||||||
|
@pytest.mark.parametrize('text', ["Привет", "Привіт", "Ґелґотати", "З'єднання", "Єдність", "їхні"])
|
||||||
|
def test_uk_tokenizer_two_diff_punct(uk_tokenizer, punct_open, punct_close,
|
||||||
|
punct_open2, punct_close2, text):
|
||||||
|
tokens = uk_tokenizer(punct_open2 + punct_open + text + punct_close + punct_close2)
|
||||||
|
assert len(tokens) == 5
|
||||||
|
assert tokens[0].text == punct_open2
|
||||||
|
assert tokens[1].text == punct_open
|
||||||
|
assert tokens[2].text == text
|
||||||
|
assert tokens[3].text == punct_close
|
||||||
|
assert tokens[4].text == punct_close2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('text', ["Привет.", "Привіт.", "Ґелґотати.", "З'єднання.", "Єдність.", "їхні."])
|
||||||
|
def test_uk_tokenizer_splits_trailing_dot(uk_tokenizer, text):
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert tokens[1].text == "."
|
||||||
|
|
||||||
|
|
||||||
|
def test_uk_tokenizer_splits_bracket_period(uk_tokenizer):
|
||||||
|
text = "(Раз, два, три, проверка)."
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert tokens[len(tokens) - 1].text == "."
|
18
spacy/tests/lang/uk/test_tokenizer_exc.py
Normal file
18
spacy/tests/lang/uk/test_tokenizer_exc.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# coding: utf-8
|
||||||
|
"""Test that tokenizer exceptions are parsed correctly."""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('text,norms,lemmas', [("ім.", ["імені"], ["ім'я"]),
|
||||||
|
("проф.", ["професор"], ["професор"])])
|
||||||
|
def test_uk_tokenizer_abbrev_exceptions(uk_tokenizer, text, norms, lemmas):
|
||||||
|
tokens = uk_tokenizer(text)
|
||||||
|
assert len(tokens) == 1
|
||||||
|
assert [token.norm_ for token in tokens] == norms
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user