Improved Dutch language resources and Dutch lemmatization (#3409)

* Improved Dutch language resources and Dutch lemmatization

* Fix conftest

* Update punctuation.py

* Auto-format

* Format and fix tests

* Remove unused test file

* Re-add deleted test

* removed redundant infix regex pattern for ','; note: brackets + simple hyphen remains

* Cleaner lemmatization files
This commit is contained in:
Yves Peirsman 2019-04-03 14:13:26 +02:00 committed by Ines Montani
parent 6a4575a56c
commit 951825532c
28 changed files with 261835 additions and 47 deletions

106
.github/contributors/nlptown.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 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.
* [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 | Yves Peirsman |
| Company name (if applicable) | NLP Town (Island Constraints BVBA) |
| Title or role (if applicable) | Co-founder |
| Date | 14.03.2019 |
| GitHub username | nlptown |
| Website (optional) | http://www.nlp.town |

View File

@ -4,6 +4,11 @@ from __future__ import unicode_literals
from .stop_words import STOP_WORDS
from .lex_attrs import LEX_ATTRS
from .tag_map import TAG_MAP
from .tokenizer_exceptions import TOKENIZER_EXCEPTIONS
from .punctuation import TOKENIZER_INFIXES, TOKENIZER_SUFFIXES
from .lemmatizer import LOOKUP, LEMMA_EXC, LEMMA_INDEX, RULES
from .lemmatizer.lemmatizer import DutchLemmatizer
from ..tokenizer_exceptions import BASE_EXCEPTIONS
from ..norm_exceptions import BASE_NORMS
@ -13,20 +18,33 @@ from ...util import update_exc, add_lookups
class DutchDefaults(Language.Defaults):
lex_attr_getters = dict(Language.Defaults.lex_attr_getters)
lex_attr_getters.update(LEX_ATTRS)
lex_attr_getters[LANG] = lambda text: "nl"
lex_attr_getters[NORM] = add_lookups(
Language.Defaults.lex_attr_getters[NORM], BASE_NORMS
)
tokenizer_exceptions = update_exc(BASE_EXCEPTIONS)
lex_attr_getters[LANG] = lambda text: 'nl'
lex_attr_getters[NORM] = add_lookups(Language.Defaults.lex_attr_getters[NORM],
BASE_NORMS)
tokenizer_exceptions = update_exc(BASE_EXCEPTIONS, TOKENIZER_EXCEPTIONS)
stop_words = STOP_WORDS
tag_map = TAG_MAP
infixes = TOKENIZER_INFIXES
suffixes = TOKENIZER_SUFFIXES
@classmethod
def create_lemmatizer(cls, nlp=None):
rules = RULES
lemma_index = LEMMA_INDEX
lemma_exc = LEMMA_EXC
lemma_lookup = LOOKUP
return DutchLemmatizer(index=lemma_index,
exceptions=lemma_exc,
lookup=lemma_lookup,
rules=rules)
class Dutch(Language):
lang = "nl"
lang = 'nl'
Defaults = DutchDefaults
__all__ = ["Dutch"]
__all__ = ['Dutch']

View File

@ -14,5 +14,5 @@ sentences = [
"Apple overweegt om voor 1 miljard een U.K. startup te kopen",
"Autonome auto's verschuiven de verzekeringverantwoordelijkheid naar producenten",
"San Francisco overweegt robots op voetpaden te verbieden",
"Londen is een grote stad in het Verenigd Koninkrijk",
"Londen is een grote stad in het Verenigd Koninkrijk"
]

View File

@ -0,0 +1,40 @@
# coding: utf8
from __future__ import unicode_literals
from ._verbs_irreg import VERBS_IRREG
from ._nouns_irreg import NOUNS_IRREG
from ._adjectives_irreg import ADJECTIVES_IRREG
from ._adverbs_irreg import ADVERBS_IRREG
from ._adpositions_irreg import ADPOSITIONS_IRREG
from ._determiners_irreg import DETERMINERS_IRREG
from ._pronouns_irreg import PRONOUNS_IRREG
from ._verbs import VERBS
from ._nouns import NOUNS
from ._adjectives import ADJECTIVES
from ._adpositions import ADPOSITIONS
from ._determiners import DETERMINERS
from .lookup import LOOKUP
from ._lemma_rules import RULES
from .lemmatizer import DutchLemmatizer
LEMMA_INDEX = {"adj": ADJECTIVES,
"noun": NOUNS,
"verb": VERBS,
"adp": ADPOSITIONS,
"det": DETERMINERS}
LEMMA_EXC = {"adj": ADJECTIVES_IRREG,
"adv": ADVERBS_IRREG,
"adp": ADPOSITIONS_IRREG,
"noun": NOUNS_IRREG,
"verb": VERBS_IRREG,
"det": DETERMINERS_IRREG,
"pron": PRONOUNS_IRREG}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
# coding: utf8
from __future__ import unicode_literals
ADPOSITIONS = set(
('aan aangaande aanwezig achter af afgezien al als an annex anno anti '
'behalve behoudens beneden benevens benoorden beoosten betreffende bewesten '
'bezijden bezuiden bij binnen binnenuit binst bladzij blijkens boven bovenop '
'buiten conform contra cq daaraan daarbij daarbuiten daarin daarnaar '
'daaronder daartegenover daarvan dankzij deure dichtbij door doordat doorheen '
'echter eraf erop erover errond eruit ervoor evenals exclusief gedaan '
'gedurende gegeven getuige gezien halfweg halverwege heen hierdoorheen hierop '
'houdende in inclusief indien ingaande ingevolge inzake jegens kortweg '
'krachtens kralj langs langsheen langst lastens linksom lopende luidens mede '
'mee met middels midden middenop mits na naan naar naartoe naast naat nabij '
'nadat namens neer neffe neffen neven nevenst niettegenstaande nopens '
'officieel om omheen omstreeks omtrent onafgezien ondanks onder onderaan '
'ondere ongeacht ooit op open over per plus pro qua rechtover rond rondom '
"sedert sinds spijts strekkende te tegen tegenaan tegenop tegenover telde "
'teneinde terug tijdens toe tot totdat trots tussen tégen uit uitgenomen '
'ultimo van vanaf vandaan vandoor vanop vanuit vanwege versus via vinnen '
'vlakbij volgens voor voor- voorbij voordat voort voren vòòr vóór waaraan '
'waarbij waardoor waaronder weg wegens weleens zijdens zoals zodat zonder '
'zónder à').split())

View File

@ -0,0 +1,12 @@
# coding: utf8
from __future__ import unicode_literals
ADPOSITIONS_IRREG = {
"'t": ('te',),
'me': ('mee',),
'meer': ('mee',),
'on': ('om',),
'ten': ('te',),
'ter': ('te',)
}

View File

@ -0,0 +1,19 @@
# coding: utf8
from __future__ import unicode_literals
ADVERBS_IRREG = {
"'ns": ('eens',),
"'s": ('eens',),
"'t": ('het',),
"d'r": ('er',),
"d'raf": ('eraf',),
"d'rbij": ('erbij',),
"d'rheen": ('erheen',),
"d'rin": ('erin',),
"d'rna": ('erna',),
"d'rnaar": ('ernaar',),
'hele': ('heel',),
'nevenst': ('nevens',),
'overend': ('overeind',)
}

View File

@ -0,0 +1,17 @@
# coding: utf8
from __future__ import unicode_literals
DETERMINERS = set(
("al allebei allerhande allerminst alletwee"
"beide clip-on d'n d'r dat datgeen datgene de dees degeen degene den dewelke "
'deze dezelfde die diegeen diegene diehien dien diene diens diezelfde dit '
'ditgene e een eene eigen elk elkens elkes enig enkel enne ettelijke eure '
'euren evenveel ewe ge geen ginds géén haar haaren halfelf het hetgeen '
'hetwelk hetzelfde heur heure hulder hulle hullen hullie hun hunder hunderen '
'ieder iederes ja je jen jouw jouwen jouwes jullie junder keiveel keiweinig '
"m'ne me meer meerder meerdere menen menig mijn mijnes minst méér niemendal "
'oe ons onse se sommig sommigeder superveel telken teveel titulair ulder '
'uldere ulderen ulle under une uw vaak veel veels véél wat weinig welk welken '
"welkene welksten z'nen ze zenen zijn zo'n zo'ne zoiet zoveel zovele zovelen "
'zuk zulk zulkdanig zulken zulks zullie zíjn àlle álle').split())

View File

@ -0,0 +1,69 @@
# coding: utf8
from __future__ import unicode_literals
DETERMINERS_IRREG = {
"'r": ('haar',),
"'s": ('de',),
"'t": ('het',),
"'tgene": ('hetgeen',),
'alle': ('al',),
'allen': ('al',),
'aller': ('al',),
'beiden': ('beide',),
'beider': ('beide',),
"d'": ('het',),
"d'r": ('haar',),
'der': ('de',),
'des': ('de',),
'dezer': ('deze',),
'dienen': ('die',),
'dier': ('die',),
'elke': ('elk',),
'ene': ('een',),
'enen': ('een',),
'ener': ('een',),
'enige': ('enig',),
'enigen': ('enig',),
'er': ('haar',),
'gene': ('geen',),
'genen': ('geen',),
'hare': ('haar',),
'haren': ('haar',),
'harer': ('haar',),
'hunne': ('hun',),
'hunnen': ('hun',),
'jou': ('jouw',),
'jouwe': ('jouw',),
'julliejen': ('jullie',),
"m'n": ('mijn',),
'mee': ('meer',),
'meer': ('veel',),
'meerderen': ('meerdere',),
'meest': ('veel',),
'meesten': ('veel',),
'meet': ('veel',),
'menige': ('menig',),
'mij': ('mijn',),
'mijnen': ('mijn',),
'minder': ('weinig',),
'mindere': ('weinig',),
'minst': ('weinig',),
'minste': ('minst',),
'ne': ('een',),
'onze': ('ons',),
'onzent': ('ons',),
'onzer': ('ons',),
'ouw': ('uw',),
'sommige': ('sommig',),
'sommigen': ('sommig',),
'u': ('uw',),
'vaker': ('vaak',),
'vele': ('veel',),
'velen': ('veel',),
'welke': ('welk',),
'zijne': ('zijn',),
'zijnen': ('zijn',),
'zijns': ('zijn',),
'één': ('een',)
}

View File

@ -0,0 +1,79 @@
# coding: utf8
from __future__ import unicode_literals
ADJECTIVE_SUFFIX_RULES = [
["sten", ""],
["ste", ""],
["st", ""],
["er", ""],
["en", ""],
["e", ""],
["ende", "end"]
]
VERB_SUFFIX_RULES = [
["dt", "den"],
["de", "en"],
["te", "en"],
["dde", "den"],
["tte", "ten"],
["dden", "den"],
["tten", "ten"],
["end", "en"],
]
NOUN_SUFFIX_RULES = [
["en", ""],
["ën", ""],
["'er", ""],
["s", ""],
["tje", ""],
["kje", ""],
["'s", ""],
["ici", "icus"],
["heden", "heid"],
["elen", "eel"],
["ezen", "ees"],
["even", "eef"],
["ssen", "s"],
["rren", "r"],
["kken", "k"],
["bben", "b"]
]
NUM_SUFFIX_RULES = [
["ste", ""],
["sten", ""],
["ën", ""],
["en", ""],
["de", ""],
["er", ""],
["ër", ""],
["tjes", ""]
]
PUNCT_SUFFIX_RULES = [
["", "\""],
["", "\""],
["\u2018", "'"],
["\u2019", "'"]
]
# In-place sort guaranteeing that longer -- more specific -- rules are
# applied first.
for rule_set in (ADJECTIVE_SUFFIX_RULES,
NOUN_SUFFIX_RULES,
NUM_SUFFIX_RULES,
VERB_SUFFIX_RULES):
rule_set.sort(key=lambda r: len(r[0]), reverse=True)
RULES = {
"adj": ADJECTIVE_SUFFIX_RULES,
"noun": NOUN_SUFFIX_RULES,
"verb": VERB_SUFFIX_RULES,
"num": NUM_SUFFIX_RULES,
"punct": PUNCT_SUFFIX_RULES
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
# coding: utf8
from __future__ import unicode_literals
NUMBERS_IRREG = {
'achten': ('acht',),
'biljoenen': ('biljoen',),
'drieën': ('drie',),
'duizenden': ('duizend',),
'eentjes': ('één',),
'elven': ('elf',),
'miljoenen': ('miljoen',),
'negenen': ('negen',),
'negentiger': ('negentig',),
'tienduizenden': ('tienduizend',),
'tienen': ('tien',),
'tientjes': ('tien',),
'twaalven': ('twaalf',),
'tweeën': ('twee',),
'twintiger': ('twintig',),
'twintigsten': ('twintig',),
'vieren': ('vier',),
'vijftiger': ('vijftig',),
'vijven': ('vijf',),
'zessen': ('zes',),
'zestiger': ('zestig',),
'zevenen': ('zeven',),
'zeventiger': ('zeventig',),
'zovele': ('zoveel',),
'zovelen': ('zoveel',)
}

View File

@ -0,0 +1,35 @@
# coding: utf8
from __future__ import unicode_literals
PRONOUNS_IRREG = {
"'r": ('haar',),
"'rzelf": ('haarzelf',),
"'t": ('het',),
"d'r": ('haar',),
'da': ('dat',),
'dienen': ('die',),
'diens': ('die',),
'dies': ('die',),
'elkaars': ('elkaar',),
'elkanders': ('elkander',),
'ene': ('een',),
'enen': ('een',),
'fik': ('ik',),
'gaat': ('gaan',),
'gene': ('geen',),
'harer': ('haar',),
'ieders': ('ieder',),
'iemands': ('iemand',),
'ikke': ('ik',),
'mijnen': ('mijn',),
'oe': ('je',),
'onzer': ('ons',),
'wa': ('wat',),
'watte': ('wat',),
'wier': ('wie',),
'zijns': ('zijn',),
'zoietsken': ('zoietske',),
'zulks': ('zulk',),
'één': ('een',)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
# coding: utf8
from __future__ import unicode_literals
from ....symbols import POS, NOUN, VERB, ADJ, NUM, DET, PRON, ADP, AUX, ADV
class DutchLemmatizer(object):
# Note: CGN does not distinguish AUX verbs, so we treat AUX as VERB.
univ_pos_name_variants = {
NOUN: "noun", "NOUN": "noun", "noun": "noun",
VERB: "verb", "VERB": "verb", "verb": "verb",
AUX: "verb", "AUX": "verb", "aux": "verb",
ADJ: "adj", "ADJ": "adj", "adj": "adj",
ADV: "adv", "ADV": "adv", "adv": "adv",
PRON: "pron", "PRON": "pron", "pron": "pron",
DET: "det", "DET": "det", "det": "det",
ADP: "adp", "ADP": "adp", "adp": "adp",
NUM: "num", "NUM": "num", "num": "num"
}
@classmethod
def load(cls, path, index=None, exc=None, rules=None, lookup=None):
return cls(index, exc, rules, lookup)
def __init__(self, index=None, exceptions=None, rules=None, lookup=None):
self.index = index
self.exc = exceptions
self.rules = rules or {}
self.lookup_table = lookup if lookup is not None else {}
def __call__(self, string, univ_pos, morphology=None):
# Difference 1: self.rules is assumed to be non-None, so no
# 'is None' check required.
# String lowercased from the get-go. All lemmatization results in
# lowercased strings. For most applications, this shouldn't pose
# any problems, and it keeps the exceptions indexes small. If this
# creates problems for proper nouns, we can introduce a check for
# univ_pos == "PROPN".
string = string.lower()
try:
univ_pos = self.univ_pos_name_variants[univ_pos]
except KeyError:
# Because PROPN not in self.univ_pos_name_variants, proper names
# are not lemmatized. They are lowercased, however.
return [string]
# if string in self.lemma_index.get(univ_pos)
lemma_index = self.index.get(univ_pos, {})
# string is already lemma
if string in lemma_index:
return [string]
exceptions = self.exc.get(univ_pos, {})
# string is irregular token contained in exceptions index.
try:
lemma = exceptions[string]
return [lemma[0]]
except KeyError:
pass
# string corresponds to key in lookup table
lookup_table = self.lookup_table
looked_up_lemma = lookup_table.get(string)
if looked_up_lemma and looked_up_lemma in lemma_index:
return [looked_up_lemma]
forms, is_known = lemmatize(
string,
lemma_index,
exceptions,
self.rules.get(univ_pos, []))
# Back-off through remaining return value candidates.
if forms:
if is_known:
return forms
else:
for form in forms:
if form in exceptions:
return [form]
if looked_up_lemma:
return [looked_up_lemma]
else:
return forms
elif looked_up_lemma:
return [looked_up_lemma]
else:
return [string]
# Overrides parent method so that a lowercased version of the string is
# used to search the lookup table. This is necessary because our lookup
# table consists entirely of lowercase keys.
def lookup(self, string):
string = string.lower()
return self.lookup_table.get(string, string)
def noun(self, string, morphology=None):
return self(string, 'noun', morphology)
def verb(self, string, morphology=None):
return self(string, 'verb', morphology)
def adj(self, string, morphology=None):
return self(string, 'adj', morphology)
def det(self, string, morphology=None):
return self(string, 'det', morphology)
def pron(self, string, morphology=None):
return self(string, 'pron', morphology)
def adp(self, string, morphology=None):
return self(string, 'adp', morphology)
def punct(self, string, morphology=None):
return self(string, 'punct', morphology)
# Reimplemented to focus more on application of suffix rules and to return
# as early as possible.
def lemmatize(string, index, exceptions, rules):
# returns (forms, is_known: bool)
oov_forms = []
for old, new in rules:
if string.endswith(old):
form = string[:len(string) - len(old)] + new
if not form:
pass
elif form in index:
return [form], True # True = Is known (is lemma)
else:
oov_forms.append(form)
return list(set(oov_forms)), False

File diff suppressed because it is too large Load Diff

View File

@ -4,22 +4,18 @@ from __future__ import unicode_literals
from ...attrs import LIKE_NUM
_num_words = set(
"""
_num_words = set("""
nul een één twee drie vier vijf zes zeven acht negen tien elf twaalf dertien
veertien twintig dertig veertig vijftig zestig zeventig tachtig negentig honderd
duizend miljoen miljard biljoen biljard triljoen triljard
""".split()
)
""".split())
_ordinal_words = set(
"""
_ordinal_words = set("""
eerste tweede derde vierde vijfde zesde zevende achtste negende tiende elfde
twaalfde dertiende veertiende twintigste dertigste veertigste vijftigste
zestigste zeventigste tachtigste negentigste honderdste duizendste miljoenste
miljardste biljoenste biljardste triljoenste triljardste
""".split()
)
""".split())
def like_num(text):
@ -27,13 +23,11 @@ def like_num(text):
# or matches one of the number words. In order to handle numbers like
# "drieëntwintig", more work is required.
# See this discussion: https://github.com/explosion/spaCy/pull/1177
if text.startswith(("+", "-", "±", "~")):
text = text[1:]
text = text.replace(",", "").replace(".", "")
text = text.replace(',', '').replace('.', '')
if text.isdigit():
return True
if text.count("/") == 1:
num, denom = text.split("/")
if text.count('/') == 1:
num, denom = text.split('/')
if num.isdigit() and denom.isdigit():
return True
if text.lower() in _num_words:
@ -43,4 +37,6 @@ def like_num(text):
return False
LEX_ATTRS = {LIKE_NUM: like_num}
LEX_ATTRS = {
LIKE_NUM: like_num
}

View File

@ -0,0 +1,33 @@
# coding: utf8
from __future__ import unicode_literals
from ..char_classes import LIST_ELLIPSES, LIST_ICONS
from ..char_classes import CONCAT_QUOTES, ALPHA, ALPHA_LOWER, ALPHA_UPPER
from ..punctuation import TOKENIZER_SUFFIXES as DEFAULT_TOKENIZER_SUFFIXES
# Copied from `de` package. Main purpose is to ensure that hyphens are not
# split on.
_quotes = CONCAT_QUOTES.replace("'", '')
_infixes = (LIST_ELLIPSES + LIST_ICONS +
[r'(?<=[{}])\.(?=[{}])'.format(ALPHA_LOWER, ALPHA_UPPER),
r'(?<=[{a}])[,!?](?=[{a}])'.format(a=ALPHA),
r'(?<=[{a}"])[:<>=](?=[{a}])'.format(a=ALPHA),
r'(?<=[{a}]),(?=[{a}])'.format(a=ALPHA),
r'(?<=[{a}])([{q}\)\]\(\[])(?=[{a}])'.format(a=ALPHA, q=_quotes),
r'(?<=[{a}])--(?=[{a}])'.format(a=ALPHA),
r'(?<=[0-9])-(?=[0-9])'])
# Remove "'s" suffix from suffix list. In Dutch, "'s" is a plural ending when
# it occurs as a suffix and a clitic for "eens" in standalone use. To avoid
# ambiguity it's better to just leave it attached when it occurs as a suffix.
default_suffix_blacklist = ("'s", "'S", 's', 'S')
_suffixes = [suffix for suffix in DEFAULT_TOKENIZER_SUFFIXES
if suffix not in default_suffix_blacklist]
TOKENIZER_INFIXES = _infixes
TOKENIZER_SUFFIXES = _suffixes

View File

@ -1,45 +1,73 @@
# coding: utf8
from __future__ import unicode_literals
# The original stop words list (added in f46ffe3) was taken from
# http://www.damienvanholten.com/downloads/dutch-stop-words.txt
# and consisted of about 100 tokens.
# In order to achieve parity with some of the better-supported
# languages, e.g., English, French, and German, this original list has been
# extended with 200 additional tokens. The main source of inspiration was
# https://raw.githubusercontent.com/stopwords-iso/stopwords-nl/master/stopwords-nl.txt.
# However, quite a bit of manual editing has taken place as well.
# Tokens whose status as a stop word is not entirely clear were admitted or
# rejected by deferring to their counterparts in the stop words lists for English
# and French. Similarly, those lists were used to identify and fill in gaps so
# that -- in principle -- each token contained in the English stop words list
# should have a Dutch counterpart here.
# Stop words are retrieved from http://www.damienvanholten.com/downloads/dutch-stop-words.txt
STOP_WORDS = set(
"""
aan af al alles als altijd andere
STOP_WORDS = set("""
aan af al alle alles allebei alleen allen als altijd ander anders andere anderen aangaangde aangezien achter achterna
afgelopen aldus alhoewel anderzijds
ben bij
ben bij bijna bijvoorbeeld behalve beide beiden beneden bent bepaald beter betere betreffende binnen binnenin boven
bovenal bovendien bovenstaand buiten
daar dan dat de der deze die dit doch doen door dus
daar dan dat de der den deze die dit doch doen door dus daarheen daarin daarna daarnet daarom daarop des dezelfde dezen
dien dikwijls doet doorgaand doorgaans
een eens en er
een eens en er echter enige eerder eerst eerste eersten effe eigen elk elke enkel enkele enz erdoor etc even eveneens
evenwel
ge geen geweest
ff
haar had heb hebben heeft hem het hier hij hoe hun
ge geen geweest gauw gedurende gegeven gehad geheel gekund geleden gelijk gemogen geven geweest gewoon gewoonweg
geworden gij
iemand iets ik in is
haar had heb hebben heeft hem het hier hij hoe hun hadden hare hebt hele hen hierbeneden hierboven hierin hoewel hun
ja je
iemand iets ik in is idd ieder ikke ikzelf indien inmiddels inz inzake
kan kon kunnen
ja je jou jouw jullie jezelf jij jijzelf jouwe juist
maar me meer men met mij mijn moet
kan kon kunnen klaar konden krachtens kunnen kunt
na naar niet niets nog nu
lang later liet liever
of om omdat ons ook op over
maar me meer men met mij mijn moet mag mede meer meesten mezelf mijzelf min minder misschien mocht mochten moest moesten
moet moeten mogelijk mogen
reeds
na naar niet niets nog nu nabij nadat net nogal nooit nr nu
te tegen toch toen tot
of om omdat ons ook op over omhoog omlaag omstreeks omtrent omver onder ondertussen ongeveer onszelf onze ooit opdat
opnieuw opzij over overigens
u uit uw
pas pp precies prof publ
van veel voor
reeds rond rondom
want waren was wat we wel werd wezen wie wij wil worden
sedert sinds sindsdien slechts sommige spoedig steeds
zal ze zei zelf zich zij zijn zo zonder zou
""".split()
)
t 't te tegen toch toen tot tamelijk ten tenzij ter terwijl thans tijdens toe totdat tussen
u uit uw uitgezonderd uwe uwen
van veel voor vaak vanaf vandaan vanuit vanwege veeleer verder verre vervolgens vgl volgens vooraf vooral vooralsnog
voorbij voordat voordien voorheen voorop voort voorts vooruit vrij vroeg
want waren was wat we wel werd wezen wie wij wil worden waar waarom wanneer want weer weg wegens weinig weinige weldra
welk welke welken werd werden wiens wier wilde wordt
zal ze zei zelf zich zij zijn zo zonder zou zeer zeker zekere zelfde zelfs zichzelf zijnde zijne zon zoals zodra zouden
zoveel zowat zulk zulke zulks zullen zult
""".split())

View File

@ -5,7 +5,6 @@ from ...symbols import POS, PUNCT, ADJ, NUM, DET, ADV, ADP, X, VERB
from ...symbols import NOUN, PROPN, SPACE, PRON, CONJ
# fmt: off
TAG_MAP = {
"ADJ__Number=Sing": {POS: ADJ},
"ADJ___": {POS: ADJ},
@ -811,4 +810,3 @@ TAG_MAP = {
"X___": {POS: X},
"_SP": {POS: SPACE}
}
# fmt: on

View File

@ -0,0 +1,340 @@
# coding: utf8
from __future__ import unicode_literals
from ...symbols import ORTH, LEMMA, TAG, NORM, PRON_LEMMA
# Extensive list of both common and uncommon dutch abbreviations copied from
# github.com/diasks2/pragmatic_segmenter, a Ruby library for rule-based
# sentence boundary detection (MIT, Copyright 2015 Kevin S. Dias).
# Source file: https://github.com/diasks2/pragmatic_segmenter/blob/master/lib/pragmatic_segmenter/languages/dutch.rb
# (Last commit: 4d1477b)
# Main purpose of such an extensive list: considerably improved sentence
# segmentation.
# Note: This list has been copied over largely as-is. Some of the abbreviations
# are extremely domain-specific. Tokenizer performance may benefit from some
# slight pruning, although no performance regression has been observed so far.
abbrevs = ['a.2d.', 'a.a.', 'a.a.j.b.', 'a.f.t.', 'a.g.j.b.',
'a.h.v.', 'a.h.w.', 'a.hosp.', 'a.i.', 'a.j.b.', 'a.j.t.',
'a.m.', 'a.m.r.', 'a.p.m.', 'a.p.r.', 'a.p.t.', 'a.s.',
'a.t.d.f.', 'a.u.b.', 'a.v.a.', 'a.w.', 'aanbev.',
'aanbev.comm.', 'aant.', 'aanv.st.', 'aanw.', 'vnw.',
'aanw.vnw.', 'abd.', 'abm.', 'abs.', 'acc.act.',
'acc.bedr.m.', 'acc.bedr.t.', 'achterv.', 'act.dr.',
'act.dr.fam.', 'act.fisc.', 'act.soc.', 'adm.akk.',
'adm.besl.', 'adm.lex.', 'adm.onderr.', 'adm.ov.', 'adv.',
'adv.', 'gen.', 'adv.bl.', 'afd.', 'afl.', 'aggl.verord.',
'agr.', 'al.', 'alg.', 'alg.richts.', 'amén.', 'ann.dr.',
'ann.dr.lg.', 'ann.dr.sc.pol.', 'ann.ét.eur.',
'ann.fac.dr.lg.', 'ann.jur.créd.',
'ann.jur.créd.règl.coll.', 'ann.not.', 'ann.parl.',
'ann.prat.comm.', 'app.', 'arb.', 'aud.', 'arbbl.',
'arbh.', 'arbit.besl.', 'arbrb.', 'arr.', 'arr.cass.',
'arr.r.v.st.', 'arr.verbr.', 'arrondrb.', 'art.', 'artw.',
'aud.', 'b.', 'b.', 'b.&w.', 'b.a.', 'b.a.s.', 'b.b.o.',
'b.best.dep.', 'b.br.ex.', 'b.coll.fr.gem.comm.',
'b.coll.vl.gem.comm.', 'b.d.cult.r.', 'b.d.gem.ex.',
'b.d.gem.reg.', 'b.dep.', 'b.e.b.', 'b.f.r.',
'b.fr.gem.ex.', 'b.fr.gem.reg.', 'b.i.h.', 'b.inl.j.d.',
'b.inl.s.reg.', 'b.j.', 'b.l.', 'b.o.z.', 'b.prov.r.',
'b.r.h.', 'b.s.', 'b.sr.', 'b.stb.', 'b.t.i.r.',
'b.t.s.z.', 'b.t.w.rev.', 'b.v.',
'b.ver.coll.gem.gem.comm.', 'b.verg.r.b.', 'b.versl.',
'b.vl.ex.', 'b.voorl.reg.', 'b.w.', 'b.w.gew.ex.',
'b.z.d.g.', 'b.z.v.', 'bab.', 'bedr.org.', 'begins.',
'beheersov.', 'bekendm.comm.', 'bel.', 'bel.besch.',
'bel.w.p.', 'beleidsov.', 'belg.', 'grondw.', 'ber.',
'ber.w.', 'besch.', 'besl.', 'beslagr.', 'bestuurswet.',
'bet.', 'betr.', 'betr.', 'vnw.', 'bevest.', 'bew.',
'bijbl.', 'ind.', 'eig.', 'bijbl.n.bijdr.', 'bijl.',
'bijv.', 'bijw.', 'bijz.decr.', 'bin.b.', 'bkh.', 'bl.',
'blz.', 'bm.', 'bn.', 'rh.', 'bnw.', 'bouwr.', 'br.parl.',
'bs.', 'bull.', 'bull.adm.pénit.', 'bull.ass.',
'bull.b.m.m.', 'bull.bel.', 'bull.best.strafinr.',
'bull.bmm.', 'bull.c.b.n.', 'bull.c.n.c.', 'bull.cbn.',
'bull.centr.arb.', 'bull.cnc.', 'bull.contr.',
'bull.doc.min.fin.', 'bull.f.e.b.', 'bull.feb.',
'bull.fisc.fin.r.', 'bull.i.u.m.',
'bull.inf.ass.secr.soc.', 'bull.inf.i.e.c.',
'bull.inf.i.n.a.m.i.', 'bull.inf.i.r.e.', 'bull.inf.iec.',
'bull.inf.inami.', 'bull.inf.ire.', 'bull.inst.arb.',
'bull.ium.', 'bull.jur.imm.', 'bull.lég.b.', 'bull.off.',
'bull.trim.b.dr.comp.', 'bull.us.', 'bull.v.b.o.',
'bull.vbo.', 'bv.', 'bw.', 'bxh.', 'byz.', 'c.', 'c.a.',
'c.a.-a.', 'c.a.b.g.', 'c.c.', 'c.c.i.', 'c.c.s.',
'c.conc.jur.', 'c.d.e.', 'c.d.p.k.', 'c.e.', 'c.ex.',
'c.f.', 'c.h.a.', 'c.i.f.', 'c.i.f.i.c.', 'c.j.', 'c.l.',
'c.n.', 'c.o.d.', 'c.p.', 'c.pr.civ.', 'c.q.', 'c.r.',
'c.r.a.', 'c.s.', 'c.s.a.', 'c.s.q.n.', 'c.v.', 'c.v.a.',
'c.v.o.', 'ca.', 'cadeaust.', 'cah.const.',
'cah.dr.europ.', 'cah.dr.immo.', 'cah.dr.jud.', 'cal.',
'2d.', 'cal.', '3e.', 'cal.', 'rprt.', 'cap.', 'carg.',
'cass.', 'cass.', 'verw.', 'cert.', 'cf.', 'ch.', 'chron.',
'chron.d.s.', 'chron.dr.not.', 'cie.', 'cie.',
'verz.schr.', 'cir.', 'circ.', 'circ.z.', 'cit.',
'cit.loc.', 'civ.', 'cl.et.b.', 'cmt.', 'co.',
'cognoss.v.', 'coll.', 'v.', 'b.', 'colp.w.', 'com.',
'com.', 'cas.', 'com.v.min.', 'comm.', 'comm.', 'v.',
'comm.bijz.ov.', 'comm.erf.', 'comm.fin.', 'comm.ger.',
'comm.handel.', 'comm.pers.', 'comm.pub.', 'comm.straf.',
'comm.v.', 'comm.venn.', 'comm.verz.', 'comm.voor.',
'comp.', 'compt.w.', 'computerr.', 'con.m.', 'concl.',
'concr.', 'conf.', 'confl.w.', 'confl.w.huwbetr.', 'cons.',
'conv.', 'coöp.', 'ver.', 'corr.', 'corr.bl.',
'cour.fisc.', 'cour.immo.', 'cridon.', 'crim.', 'cur.',
'cur.', 'crt.', 'curs.', 'd.', 'd.-g.', 'd.a.', 'd.a.v.',
'd.b.f.', 'd.c.', 'd.c.c.r.', 'd.d.', 'd.d.p.', 'd.e.t.',
'd.gem.r.', 'd.h.', 'd.h.z.', 'd.i.', 'd.i.t.', 'd.j.',
'd.l.r.', 'd.m.', 'd.m.v.', 'd.o.v.', 'd.parl.', 'd.w.z.',
'dact.', 'dat.', 'dbesch.', 'dbesl.', 'decr.', 'decr.d.',
'decr.fr.', 'decr.vl.', 'decr.w.', 'def.', 'dep.opv.',
'dep.rtl.', 'derg.', 'desp.', 'det.mag.', 'deurw.regl.',
'dez.', 'dgl.', 'dhr.', 'disp.', 'diss.', 'div.',
'div.act.', 'div.bel.', 'dl.', 'dln.', 'dnotz.', 'doc.',
'hist.', 'doc.jur.b.', 'doc.min.fin.', 'doc.parl.',
'doctr.', 'dpl.', 'dpl.besl.', 'dr.', 'dr.banc.fin.',
'dr.circ.', 'dr.inform.', 'dr.mr.', 'dr.pén.entr.',
'dr.q.m.', 'drs.', 'dtp.', 'dwz.', 'dyn.', 'e.', 'e.a.',
'e.b.', 'tek.mod.', 'e.c.', 'e.c.a.', 'e.d.', 'e.e.',
'e.e.a.', 'e.e.g.', 'e.g.', 'e.g.a.', 'e.h.a.', 'e.i.',
'e.j.', 'e.m.a.', 'e.n.a.c.', 'e.o.', 'e.p.c.', 'e.r.c.',
'e.r.f.', 'e.r.h.', 'e.r.o.', 'e.r.p.', 'e.r.v.',
'e.s.r.a.', 'e.s.t.', 'e.v.', 'e.v.a.', 'e.w.', 'e&o.e.',
'ec.pol.r.', 'econ.', 'ed.', 'ed(s).', 'eff.', 'eig.',
'eig.mag.', 'eil.', 'elektr.', 'enmb.', 'enz.', 'err.',
'etc.', 'etq.', 'eur.', 'parl.', 'eur.t.s.', 'ev.', 'evt.',
'ex.', 'ex.crim.', 'exec.', 'f.', 'f.a.o.', 'f.a.q.',
'f.a.s.', 'f.i.b.', 'f.j.f.', 'f.o.b.', 'f.o.r.', 'f.o.s.',
'f.o.t.', 'f.r.', 'f.supp.', 'f.suppl.', 'fa.', 'facs.',
'fasc.', 'fg.', 'fid.ber.', 'fig.', 'fin.verh.w.', 'fisc.',
'fisc.', 'tijdschr.', 'fisc.act.', 'fisc.koer.', 'fl.',
'form.', 'foro.', 'it.', 'fr.', 'fr.cult.r.', 'fr.gem.r.',
'fr.parl.', 'fra.', 'ft.', 'g.', 'g.a.', 'g.a.v.',
'g.a.w.v.', 'g.g.d.', 'g.m.t.', 'g.o.', 'g.omt.e.', 'g.p.',
'g.s.', 'g.v.', 'g.w.w.', 'geb.', 'gebr.', 'gebrs.',
'gec.', 'gec.decr.', 'ged.', 'ged.st.', 'gedipl.',
'gedr.st.', 'geh.', 'gem.', 'gem.', 'gem.',
'gem.gem.comm.', 'gem.st.', 'gem.stem.', 'gem.w.',
'gemeensch.optr.', 'gemeensch.standp.', 'gemeensch.strat.',
'gemeent.', 'gemeent.b.', 'gemeent.regl.',
'gemeent.verord.', 'geol.', 'geopp.', 'gepubl.',
'ger.deurw.', 'ger.w.', 'gerekw.', 'gereq.', 'gesch.',
'get.', 'getr.', 'gev.m.', 'gev.maatr.', 'gew.', 'ghert.',
'gir.eff.verk.', 'gk.', 'gr.', 'gramm.', 'grat.w.',
'grootb.w.', 'grs.', 'grvm.', 'grw.', 'gst.', 'gw.',
'h.a.', 'h.a.v.o.', 'h.b.o.', 'h.e.a.o.', 'h.e.g.a.',
'h.e.geb.', 'h.e.gestr.', 'h.l.', 'h.m.', 'h.o.', 'h.r.',
'h.t.l.', 'h.t.m.', 'h.w.geb.', 'hand.', 'handelsn.w.',
'handelspr.', 'handelsr.w.', 'handelsreg.w.', 'handv.',
'harv.l.rev.', 'hc.', 'herald.', 'hert.', 'herz.',
'hfdst.', 'hfst.', 'hgrw.', 'hhr.', 'hist.', 'hooggel.',
'hoogl.', 'hosp.', 'hpw.', 'hr.', 'hr.', 'ms.', 'hr.ms.',
'hregw.', 'hrg.', 'hst.', 'huis.just.', 'huisv.w.',
'huurbl.', 'hv.vn.', 'hw.', 'hyp.w.', 'i.b.s.', 'i.c.',
'i.c.m.h.', 'i.e.', 'i.f.', 'i.f.p.', 'i.g.v.', 'i.h.',
'i.h.a.', 'i.h.b.', 'i.l.pr.', 'i.o.', 'i.p.o.', 'i.p.r.',
'i.p.v.', 'i.pl.v.', 'i.r.d.i.', 'i.s.m.', 'i.t.t.',
'i.v.', 'i.v.m.', 'i.v.s.', 'i.w.tr.', 'i.z.', 'ib.',
'ibid.', 'icip-ing.cons.', 'iem.', 'indic.soc.', 'indiv.',
'inf.', 'inf.i.d.a.c.', 'inf.idac.', 'inf.r.i.z.i.v.',
'inf.riziv.', 'inf.soc.secr.', 'ing.', 'ing.', 'cons.',
'ing.cons.', 'inst.', 'int.', 'int.', 'rechtsh.',
'strafz.', 'interm.', 'intern.fisc.act.',
'intern.vervoerr.', 'inv.', 'inv.', 'f.', 'inv.w.',
'inv.wet.', 'invord.w.', 'inz.', 'ir.', 'irspr.', 'iwtr.',
'j.', 'j.-cl.', 'j.c.b.', 'j.c.e.', 'j.c.fl.', 'j.c.j.',
'j.c.p.', 'j.d.e.', 'j.d.f.', 'j.d.s.c.', 'j.dr.jeun.',
'j.j.d.', 'j.j.p.', 'j.j.pol.', 'j.l.', 'j.l.m.b.',
'j.l.o.', 'j.p.a.', 'j.r.s.', 'j.t.', 'j.t.d.e.',
'j.t.dr.eur.', 'j.t.o.', 'j.t.t.', 'jaarl.', 'jb.hand.',
'jb.kred.', 'jb.kred.c.s.', 'jb.l.r.b.', 'jb.lrb.',
'jb.markt.', 'jb.mens.', 'jb.t.r.d.', 'jb.trd.',
'jeugdrb.', 'jeugdwerkg.w.', 'jg.', 'jis.', 'jl.',
'journ.jur.', 'journ.prat.dr.fisc.fin.', 'journ.proc.',
'jrg.', 'jur.', 'jur.comm.fl.', 'jur.dr.soc.b.l.n.',
'jur.f.p.e.', 'jur.fpe.', 'jur.niv.', 'jur.trav.brux.',
'jurambt.', 'jv.cass.', 'jv.h.r.j.', 'jv.hrj.', 'jw.',
'k.', 'k.', 'k.b.', 'k.g.', 'k.k.', 'k.m.b.o.', 'k.o.o.',
'k.v.k.', 'k.v.v.v.', 'kadasterw.', 'kaderb.', 'kador.',
'kbo-nr.', 'kg.', 'kh.', 'kiesw.', 'kind.bes.v.', 'kkr.',
'koopv.', 'kr.', 'krankz.w.', 'ksbel.', 'kt.', 'ktg.',
'ktr.', 'kvdm.', 'kw.r.', 'kymr.', 'kzr.', 'kzw.', 'l.',
'l.b.', 'l.b.o.', 'l.bas.', 'l.c.', 'l.gew.', 'l.j.',
'l.k.', 'l.l.', 'l.o.', 'l.r.b.', 'l.u.v.i.', 'l.v.r.',
'l.v.w.', 'l.w.', "l'exp.-compt.b..", 'lexp.-compt.b.',
'landinr.w.', 'landscrt.', 'lat.', 'law.ed.', 'lett.',
'levensverz.', 'lgrs.', 'lidw.', 'limb.rechtsl.', 'lit.',
'litt.', 'liw.', 'liwet.', 'lk.', 'll.', 'll.(l.)l.r.',
'loonw.', 'losbl.', 'ltd.', 'luchtv.', 'luchtv.w.', 'm.',
'm.', 'not.', 'm.a.v.o.', 'm.a.w.', 'm.b.', 'm.b.o.',
'm.b.r.', 'm.b.t.', 'm.d.g.o.', 'm.e.a.o.', 'm.e.r.',
'm.h.', 'm.h.d.', 'm.i.v.', 'm.j.t.', 'm.k.', 'm.m.',
'm.m.a.', 'm.m.h.h.', 'm.m.v.', 'm.n.', 'm.not.fisc.',
'm.nt.', 'm.o.', 'm.r.', 'm.s.a.', 'm.u.p.', 'm.v.a.',
'm.v.h.n.', 'm.v.t.', 'm.z.', 'maatr.teboekgest.luchtv.',
'maced.', 'mand.', 'max.', 'mbl.not.', 'me.', 'med.',
'med.', 'v.b.o.', 'med.b.u.f.r.', 'med.bufr.', 'med.vbo.',
'meerv.', 'meetbr.w.', 'mém.adm.', 'mgr.', 'mgrs.', 'mhd.',
'mi.verantw.', 'mil.', 'mil.bed.', 'mil.ger.', 'min.',
'min.', 'aanbev.', 'min.', 'circ.', 'min.', 'fin.',
'min.j.omz.', 'min.just.circ.', 'mitt.', 'mnd.', 'mod.',
'mon.', 'mouv.comm.', 'mr.', 'ms.', 'muz.', 'mv.', 'n.',
'chr.', 'n.a.', 'n.a.g.', 'n.a.v.', 'n.b.', 'n.c.',
'n.chr.', 'n.d.', 'n.d.r.', 'n.e.a.', 'n.g.', 'n.h.b.c.',
'n.j.', 'n.j.b.', 'n.j.w.', 'n.l.', 'n.m.', 'n.m.m.',
'n.n.', 'n.n.b.', 'n.n.g.', 'n.n.k.', 'n.o.m.', 'n.o.t.k.',
'n.rapp.', 'n.tijd.pol.', 'n.v.', 'n.v.d.r.', 'n.v.d.v.',
'n.v.o.b.', 'n.v.t.', 'nat.besch.w.', 'nat.omb.',
'nat.pers.', 'ned.cult.r.', 'neg.verkl.', 'nhd.', 'wisk.',
'njcm-bull.', 'nl.', 'nnd.', 'no.', 'not.fisc.m.',
'not.w.', 'not.wet.', 'nr.', 'nrs.', 'nste.', 'nt.',
'numism.', 'o.', 'o.a.', 'o.b.', 'o.c.', 'o.g.', 'o.g.v.',
'o.i.', 'o.i.d.', 'o.m.', 'o.o.', 'o.o.d.', 'o.o.v.',
'o.p.', 'o.r.', 'o.regl.', 'o.s.', 'o.t.s.', 'o.t.t.',
'o.t.t.t.', 'o.t.t.z.', 'o.tk.t.', 'o.v.t.', 'o.v.t.t.',
'o.v.tk.t.', 'o.v.v.', 'ob.', 'obsv.', 'octr.',
'octr.gem.regl.', 'octr.regl.', 'oe.', 'off.pol.', 'ofra.',
'ohd.', 'omb.', 'omnil.', 'omz.', 'on.ww.', 'onderr.',
'onfrank.', 'onteig.w.', 'ontw.', 'b.w.', 'onuitg.',
'onz.', 'oorl.w.', 'op.cit.', 'opin.pa.', 'opm.', 'or.',
'ord.br.', 'ord.gem.', 'ors.', 'orth.', 'os.', 'osm.',
'ov.', 'ov.w.i.', 'ov.w.ii.', 'ov.ww.', 'overg.w.',
'overw.', 'ovkst.', 'oz.', 'p.', 'p.a.', 'p.a.o.',
'p.b.o.', 'p.e.', 'p.g.', 'p.j.', 'p.m.', 'p.m.a.', 'p.o.',
'p.o.j.t.', 'p.p.', 'p.v.', 'p.v.s.', 'pachtw.', 'pag.',
'pan.', 'pand.b.', 'pand.pér.', 'parl.gesch.',
'parl.gesch.', 'inv.', 'parl.st.', 'part.arb.', 'pas.',
'pasin.', 'pat.', 'pb.c.', 'pb.l.', 'pens.',
'pensioenverz.', 'per.ber.i.b.r.', 'per.ber.ibr.', 'pers.',
'st.', 'pft.', 'pk.', 'pktg.', 'plv.', 'po.', 'pol.',
'pol.off.', 'pol.r.', 'pol.w.', 'postbankw.', 'postw.',
'pp.', 'pr.', 'preadv.', 'pres.', 'prf.', 'prft.', 'prg.',
'prijz.w.', 'proc.', 'procesregl.', 'prof.', 'prot.',
'prov.', 'prov.b.', 'prov.instr.h.m.g.', 'prov.regl.',
'prov.verord.', 'prov.w.', 'publ.', 'pun.', 'pw.',
'q.b.d.', 'q.e.d.', 'q.q.', 'q.r.', 'r.', 'r.a.b.g.',
'r.a.c.e.', 'r.a.j.b.', 'r.b.d.c.', 'r.b.d.i.', 'r.b.s.s.',
'r.c.', 'r.c.b.', 'r.c.d.c.', 'r.c.j.b.', 'r.c.s.j.',
'r.cass.', 'r.d.c.', 'r.d.i.', 'r.d.i.d.c.', 'r.d.j.b.',
'r.d.j.p.', 'r.d.p.c.', 'r.d.s.', 'r.d.t.i.', 'r.e.',
'r.f.s.v.p.', 'r.g.a.r.', 'r.g.c.f.', 'r.g.d.c.', 'r.g.f.',
'r.g.z.', 'r.h.a.', 'r.i.c.', 'r.i.d.a.', 'r.i.e.j.',
'r.i.n.', 'r.i.s.a.', 'r.j.d.a.', 'r.j.i.', 'r.k.', 'r.l.',
'r.l.g.b.', 'r.med.', 'r.med.rechtspr.', 'r.n.b.', 'r.o.',
'r.ov.', 'r.p.', 'r.p.d.b.', 'r.p.o.t.', 'r.p.r.j.',
'r.p.s.', 'r.r.d.', 'r.r.s.', 'r.s.', 'r.s.v.p.',
'r.stvb.', 'r.t.d.f.', 'r.t.d.h.', 'r.t.l.',
'r.trim.dr.eur.', 'r.v.a.', 'r.verkb.', 'r.w.', 'r.w.d.',
'rap.ann.c.a.', 'rap.ann.c.c.', 'rap.ann.c.e.',
'rap.ann.c.s.j.', 'rap.ann.ca.', 'rap.ann.cass.',
'rap.ann.cc.', 'rap.ann.ce.', 'rap.ann.csj.', 'rapp.',
'rb.', 'rb.kh.', 'rdn.', 'rdnr.', 're.pers.', 'rec.',
'rec.c.i.j.', 'rec.c.j.c.e.', 'rec.cij.', 'rec.cjce.',
'rec.gén.enr.not.', 'rechtsk.t.', 'rechtspl.zeem.',
'rechtspr.arb.br.', 'rechtspr.b.f.e.', 'rechtspr.bfe.',
'rechtspr.soc.r.b.l.n.', 'recl.reg.', 'rect.', 'red.',
'reg.', 'reg.huiz.bew.', 'reg.w.', 'registr.w.', 'regl.',
'regl.', 'r.v.k.', 'regl.besl.', 'regl.onderr.',
'regl.r.t.', 'rep.', 'rép.fisc.', 'rép.not.', 'rep.r.j.',
'rep.rj.', 'req.', 'res.', 'resp.', 'rev.', 'rev.',
'comp.', 'rev.', 'trim.', 'civ.', 'rev.', 'trim.', 'comm.',
'rev.acc.trav.', 'rev.adm.', 'rev.b.compt.',
'rev.b.dr.const.', 'rev.b.dr.intern.', 'rev.b.séc.soc.',
'rev.banc.fin.', 'rev.comm.', 'rev.cons.prud.',
'rev.dr.b.', 'rev.dr.commun.', 'rev.dr.étr.',
'rev.dr.fam.', 'rev.dr.intern.comp.', 'rev.dr.mil.',
'rev.dr.min.', 'rev.dr.pén.', 'rev.dr.pén.mil.',
'rev.dr.rur.', 'rev.dr.u.l.b.', 'rev.dr.ulb.', 'rev.exp.',
'rev.faill.', 'rev.fisc.', 'rev.gd.', 'rev.hist.dr.',
'rev.i.p.c.', 'rev.ipc.', 'rev.not.b.',
'rev.prat.dr.comm.', 'rev.prat.not.b.', 'rev.prat.soc.',
'rev.rec.', 'rev.rw.', 'rev.trav.', 'rev.trim.d.h.',
'rev.trim.dr.fam.', 'rev.urb.', 'richtl.', 'riv.dir.int.',
'riv.dir.int.priv.proc.', 'rk.', 'rln.', 'roln.', 'rom.',
'rondz.', 'rov.', 'rtl.', 'rubr.', 'ruilv.wet.',
'rv.verdr.', 'rvkb.', 's.', 's.', 's.a.', 's.b.n.',
's.ct.', 's.d.', 's.e.c.', 's.e.et.o.', 's.e.w.',
's.exec.rept.', 's.hrg.', 's.j.b.', 's.l.', 's.l.e.a.',
's.l.n.d.', 's.p.a.', 's.s.', 's.t.', 's.t.b.', 's.v.',
's.v.p.', 'samenw.', 'sc.', 'sch.', 'scheidsr.uitspr.',
'schepel.besl.', 'secr.comm.', 'secr.gen.', 'sect.soc.',
'sess.', 'cas.', 'sir.', 'soc.', 'best.', 'soc.', 'handv.',
'soc.', 'verz.', 'soc.act.', 'soc.best.', 'soc.kron.',
'soc.r.', 'soc.sw.', 'soc.weg.', 'sofi-nr.', 'somm.',
'somm.ann.', 'sp.c.c.', 'sr.', 'ss.', 'st.doc.b.c.n.a.r.',
'st.doc.bcnar.', 'st.vw.', 'stagever.', 'stas.', 'stat.',
'stb.', 'stbl.', 'stcrt.', 'stud.dipl.', 'su.', 'subs.',
'subst.', 'succ.w.', 'suppl.', 'sv.', 'sw.', 't.', 't.a.',
't.a.a.', 't.a.n.', 't.a.p.', 't.a.s.n.', 't.a.v.',
't.a.v.w.', 't.aann.', 't.acc.', 't.agr.r.', 't.app.',
't.b.b.r.', 't.b.h.', 't.b.m.', 't.b.o.', 't.b.p.',
't.b.r.', 't.b.s.', 't.b.v.', 't.bankw.', 't.belg.not.',
't.desk.', 't.e.m.', 't.e.p.', 't.f.r.', 't.fam.',
't.fin.r.', 't.g.r.', 't.g.t.', 't.g.v.', 't.gem.',
't.gez.', 't.huur.', 't.i.n.', 't.j.k.', 't.l.l.',
't.l.v.', 't.m.', 't.m.r.', 't.m.w.', 't.mil.r.',
't.mil.strafr.', 't.not.', 't.o.', 't.o.r.b.', 't.o.v.',
't.ontv.', 't.p.r.', 't.pol.', 't.r.', 't.r.g.',
't.r.o.s.', 't.r.v.', 't.s.r.', 't.strafr.', 't.t.',
't.u.', 't.v.c.', 't.v.g.', 't.v.m.r.', 't.v.o.', 't.v.v.',
't.v.v.d.b.', 't.v.w.', 't.verz.', 't.vred.', 't.vreemd.',
't.w.', 't.w.k.', 't.w.v.', 't.w.v.r.', 't.wrr.', 't.z.',
't.z.t.', 't.z.v.', 'taalk.', 'tar.burg.z.', 'td.',
'techn.', 'telecomm.', 'toel.', 'toel.st.v.w.', 'toep.',
'toep.regl.', 'tom.', 'top.', 'trans.b.', 'transp.r.',
'trb.', 'trib.', 'trib.civ.', 'trib.gr.inst.', 'ts.',
'ts.', 'best.', 'ts.', 'verv.', 'turnh.rechtsl.', 'tvpol.',
'tvpr.', 'tvrechtsgesch.', 'tw.', 'u.', 'u.a.', 'u.a.r.',
'u.a.v.', 'u.c.', 'u.c.c.', 'u.g.', 'u.p.', 'u.s.',
'u.s.d.c.', 'uitdr.', 'uitl.w.', 'uitv.besch.div.b.',
'uitv.besl.', 'uitv.besl.', 'succ.w.', 'uitv.besl.bel.rv.',
'uitv.besl.l.b.', 'uitv.reg.', 'inv.w.', 'uitv.reg.bel.d.',
'uitv.reg.afd.verm.', 'uitv.reg.lb.', 'uitv.reg.succ.w.',
'univ.', 'univ.verkl.', 'v.', 'v.', 'chr.', 'v.a.',
'v.a.v.', 'v.c.', 'v.chr.', 'v.h.', 'v.huw.verm.', 'v.i.',
'v.i.o.', 'v.k.a.', 'v.m.', 'v.o.f.', 'v.o.n.',
'v.onderh.verpl.', 'v.p.', 'v.r.', 'v.s.o.', 'v.t.t.',
'v.t.t.t.', 'v.tk.t.', 'v.toep.r.vert.', 'v.v.b.',
'v.v.g.', 'v.v.t.', 'v.v.t.t.', 'v.v.tk.t.', 'v.w.b.',
'v.z.m.', 'vb.', 'vb.bo.', 'vbb.', 'vc.', 'vd.', 'veldw.',
'ver.k.', 'ver.verg.gem.', 'gem.comm.', 'verbr.', 'verd.',
'verdr.', 'verdr.v.', 'tek.mod.', 'verenw.', 'verg.',
'verg.fr.gem.', 'comm.', 'verkl.', 'verkl.herz.gw.',
'verl.', 'deelw.', 'vern.', 'verord.', 'vers.r.',
'versch.', 'versl.c.s.w.', 'versl.csw.', 'vert.', 'verw.',
'verz.', 'verz.w.', 'verz.wett.besl.',
'verz.wett.decr.besl.', 'vgl.', 'vid.', 'viss.w.',
'vl.parl.', 'vl.r.', 'vl.t.gez.', 'vl.w.reg.',
'vl.w.succ.', 'vlg.', 'vn.', 'vnl.', 'vnw.', 'vo.',
'vo.bl.', 'voegw.', 'vol.', 'volg.', 'volt.', 'deelw.',
'voorl.', 'voorz.', 'vord.w.', 'vorst.d.', 'vr.', 'vred.',
'vrg.', 'vnw.', 'vrijgrs.', 'vs.', 'vt.', 'vw.', 'vz.',
'vzngr.', 'vzr.', 'w.', 'w.a.', 'w.b.r.', 'w.c.h.',
'w.conf.huw.', 'w.conf.huwelijksb.', 'w.consum.kr.',
'w.f.r.', 'w.g.', 'w.gew.r.', 'w.ident.pl.', 'w.just.doc.',
'w.kh.', 'w.l.r.', 'w.l.v.', 'w.mil.straf.spr.', 'w.n.',
'w.not.ambt.', 'w.o.', 'w.o.d.huurcomm.', 'w.o.d.k.',
'w.openb.manif.', 'w.parl.', 'w.r.', 'w.reg.', 'w.succ.',
'w.u.b.', 'w.uitv.pl.verord.', 'w.v.', 'w.v.k.',
'w.v.m.s.', 'w.v.r.', 'w.v.w.', 'w.venn.', 'wac.', 'wd.',
'wetb.', 'n.v.h.', 'wgb.', 'winkelt.w.', 'wisk.',
'wka-verkl.', 'wnd.', 'won.w.', 'woningw.', 'woonr.w.',
'wrr.', 'wrr.ber.', 'wrsch.', 'ws.', 'wsch.', 'wsr.',
'wtvb.', 'ww.', 'x.d.', 'z.a.', 'z.g.', 'z.i.', 'z.j.',
'z.o.z.', 'z.p.', 'z.s.m.', 'zg.', 'zgn.', 'zn.', 'znw.',
'zr.', 'zr.', 'ms.', 'zr.ms.']
_exc = {}
for orth in abbrevs:
_exc[orth] = [{ORTH: orth}]
uppered = orth.upper()
capsed = orth.capitalize()
for i in [uppered, capsed]:
_exc[i] = [{ORTH: i}]
TOKENIZER_EXCEPTIONS = _exc

View File

@ -134,6 +134,11 @@ def nl_tokenizer():
return get_lang_class("nl").Defaults.create_tokenizer()
@pytest.fixture
def nl_lemmatizer(scope="session"):
return get_lang_class("nl").Defaults.create_lemmatizer()
@pytest.fixture(scope="session")
def pl_tokenizer():
return get_lang_class("pl").Defaults.create_tokenizer()

View File

@ -0,0 +1,143 @@
# coding: utf-8
from __future__ import unicode_literals
import pytest
# Calling the Lemmatizer directly
# Imitates behavior of:
# Tagger.set_annotations()
# -> vocab.morphology.assign_tag_id()
# -> vocab.morphology.assign_tag_id()
# -> Token.tag.__set__
# -> vocab.morphology.assign_tag(...)
# -> ... -> Morphology.assign_tag(...)
# -> self.lemmatize(analysis.tag.pos, token.lex.orth,
noun_irreg_lemmatization_cases = [
("volkeren", "volk"),
("vaatje", "vat"),
("verboden", "verbod"),
("ijsje", "ijsje"),
("slagen", "slag"),
("verdragen", "verdrag"),
("verloven", "verlof"),
("gebeden", "gebed"),
("gaten", "gat"),
("staven", "staf"),
("aquariums", "aquarium"),
("podia", "podium"),
("holen", "hol"),
("lammeren", "lam"),
("bevelen", "bevel"),
("wegen", "weg"),
("moeilijkheden", "moeilijkheid"),
("aanwezigheden", "aanwezigheid"),
("goden", "god"),
("loten", "lot"),
("kaarsen", "kaars"),
("leden", "lid"),
("glaasje", "glas"),
("eieren", "ei"),
("vatten", "vat"),
("kalveren", "kalf"),
("padden", "pad"),
("smeden", "smid"),
("genen", "gen"),
("beenderen", "been"),
]
verb_irreg_lemmatization_cases = [
("liep", "lopen"),
("hief", "heffen"),
("begon", "beginnen"),
("sla", "slaan"),
("aangekomen", "aankomen"),
("sproot", "spruiten"),
("waart", "zijn"),
("snoof", "snuiven"),
("spoot", "spuiten"),
("ontbeet", "ontbijten"),
("gehouwen", "houwen"),
("afgewassen", "afwassen"),
("deed", "doen"),
("schoven", "schuiven"),
("gelogen", "liegen"),
("woog", "wegen"),
("gebraden", "braden"),
("smolten", "smelten"),
("riep", "roepen"),
("aangedaan", "aandoen"),
("vermeden", "vermijden"),
("stootten", "stoten"),
("ging", "gaan"),
("geschoren", "scheren"),
("gesponnen", "spinnen"),
("reden", "rijden"),
("zochten", "zoeken"),
("leed", "lijden"),
("verzonnen", "verzinnen"),
]
@pytest.mark.parametrize("text,lemma", noun_irreg_lemmatization_cases)
def test_nl_lemmatizer_noun_lemmas_irreg(nl_lemmatizer, text, lemma):
pos = "noun"
lemmas_pred = nl_lemmatizer(text, pos)
assert lemma == sorted(lemmas_pred)[0]
@pytest.mark.parametrize("text,lemma", verb_irreg_lemmatization_cases)
def test_nl_lemmatizer_verb_lemmas_irreg(nl_lemmatizer, text, lemma):
pos = "verb"
lemmas_pred = nl_lemmatizer(text, pos)
assert lemma == sorted(lemmas_pred)[0]
@pytest.mark.skip
@pytest.mark.parametrize("text,lemma", [])
def test_nl_lemmatizer_verb_lemmas_reg(nl_lemmatizer, text, lemma):
# TODO: add test
pass
@pytest.mark.skip
@pytest.mark.parametrize("text,lemma", [])
def test_nl_lemmatizer_adjective_lemmas(nl_lemmatizer, text, lemma):
# TODO: add test
pass
@pytest.mark.skip
@pytest.mark.parametrize("text,lemma", [])
def test_nl_lemmatizer_determiner_lemmas(nl_lemmatizer, text, lemma):
# TODO: add test
pass
@pytest.mark.skip
@pytest.mark.parametrize("text,lemma", [])
def test_nl_lemmatizer_adverb_lemmas(nl_lemmatizer, text, lemma):
# TODO: add test
pass
@pytest.mark.parametrize("text,lemma", [])
def test_nl_lemmatizer_pronoun_lemmas(nl_lemmatizer, text, lemma):
# TODO: add test
pass
# Using the lemma lookup table only
@pytest.mark.parametrize("text,lemma", noun_irreg_lemmatization_cases)
def test_nl_lemmatizer_lookup_noun(nl_lemmatizer, text, lemma):
lemma_pred = nl_lemmatizer.lookup(text)
assert lemma_pred in (lemma, text)
@pytest.mark.parametrize("text,lemma", verb_irreg_lemmatization_cases)
def test_nl_lemmatizer_lookup_verb(nl_lemmatizer, text, lemma):
lemma_pred = nl_lemmatizer.lookup(text)
assert lemma_pred in (lemma, text)

View File

@ -9,3 +9,19 @@ from spacy.lang.nl.lex_attrs import like_num
def test_nl_lex_attrs_capitals(word):
assert like_num(word)
assert like_num(word.upper())
@pytest.mark.parametrize(
"text,num_tokens",
[
(
"De aftredende minister-president benadrukte al dat zijn partij inhoudelijk weinig gemeen heeft met de groenen.",
16,
),
("Hij is sociaal-cultureel werker.", 5),
("Er staan een aantal dure auto's in de garage.", 10),
],
)
def test_tokenizer_doesnt_split_hyphens(nl_tokenizer, text, num_tokens):
tokens = nl_tokenizer(text)
assert len(tokens) == num_tokens