de-compromise 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/builds/de-compromise.cjs +2357 -1687
- package/builds/de-compromise.min.js +1 -1
- package/builds/de-compromise.mjs +1 -1
- package/package.json +21 -14
- package/src/01-one/lexicon/_data.js +32 -0
- package/src/01-one/lexicon/compute/root.js +55 -0
- package/src/01-one/lexicon/lexicon.js +95 -0
- package/src/01-one/lexicon/methods/_data.js +193 -0
- package/src/01-one/lexicon/methods/adjectives/_test-back.js +29 -0
- package/src/01-one/lexicon/methods/adjectives/_test.js +49 -0
- package/src/01-one/lexicon/methods/adjectives/inflect.js +27 -0
- package/src/01-one/lexicon/methods/adjectives/model.js +126 -0
- package/src/01-one/lexicon/methods/adjectives/new/adjective.js +8 -0
- package/src/01-one/lexicon/methods/adjectives/new/comparative.js +7 -0
- package/src/01-one/lexicon/methods/adjectives/new/superlative.js +159 -0
- package/src/01-one/lexicon/methods/adjectives/toRoot.js +47 -0
- package/src/01-one/lexicon/methods/index.js +56 -0
- package/src/01-one/lexicon/methods/models.js +10 -0
- package/src/01-one/lexicon/methods/nouns/_test-back.js +45 -0
- package/src/01-one/lexicon/methods/nouns/new.js +56 -0
- package/src/01-one/lexicon/methods/nouns/toPlural.js +49 -0
- package/src/01-one/lexicon/methods/nouns/toSingular.js +46 -0
- package/src/01-one/lexicon/methods/verbs/conjugate.js +87 -0
- package/src/01-one/lexicon/methods/verbs/custom/_test-from.js +53 -0
- package/src/01-one/lexicon/methods/verbs/custom/_test-to.js +50 -0
- package/src/01-one/lexicon/methods/verbs/custom/fromPastParticiple.js +37 -0
- package/src/01-one/lexicon/methods/verbs/custom/rules.js +182 -0
- package/src/01-one/lexicon/methods/verbs/custom/toPastParticiple.js +54 -0
- package/src/01-one/lexicon/methods/verbs/irregulars.js +202 -0
- package/src/01-one/lexicon/methods/verbs/toRoot.js +55 -0
- package/src/01-one/lexicon/misc.js +78 -0
- package/src/01-one/lexicon/plugin.js +14 -0
- package/src/01-one/splitter/build.js +20 -0
- package/src/01-one/splitter/compute/splitter.js +54 -0
- package/src/01-one/splitter/model/index.js +20 -0
- package/src/01-one/splitter/plugin.js +10 -0
- package/src/01-one/splitter/trie.js +40 -0
- package/src/01-one/tagset/plugin.js +11 -0
- package/src/01-one/tagset/tags/dates.js +45 -0
- package/src/01-one/tagset/tags/misc.js +70 -0
- package/src/01-one/tagset/tags/nouns.js +116 -0
- package/src/01-one/tagset/tags/values.js +47 -0
- package/src/01-one/tagset/tags/verbs.js +64 -0
- package/src/01-one/tokenizer/contractions.js +40 -0
- package/src/01-one/tokenizer/is-sentence.js +37 -0
- package/src/01-one/tokenizer/plugin.js +11 -0
- package/src/01-one/tokenizer/unicode.js +55 -0
- package/src/02-two/postTagger/matches.js +47 -0
- package/src/02-two/postTagger/plugin.js +8 -0
- package/src/02-two/preTagger/compute/1st-pass/regex.js +43 -0
- package/src/02-two/preTagger/compute/1st-pass/titlecase.js +21 -0
- package/src/02-two/preTagger/compute/1st-pass/year.js +54 -0
- package/src/02-two/preTagger/compute/2nd-pass/acronym.js +82 -0
- package/src/02-two/preTagger/compute/2nd-pass/fallback.js +27 -0
- package/src/02-two/preTagger/compute/2nd-pass/prefix-lookup.js +33 -0
- package/src/02-two/preTagger/compute/2nd-pass/suffix-lookup.js +44 -0
- package/src/02-two/preTagger/compute/index.js +42 -0
- package/src/02-two/preTagger/model/index.js +14 -0
- package/src/02-two/preTagger/model/prefixes.js +46 -0
- package/src/02-two/preTagger/model/regex/regex-normal.js +25 -0
- package/src/02-two/preTagger/model/regex/regex-numbers.js +62 -0
- package/src/02-two/preTagger/model/regex/regex-text.js +17 -0
- package/src/02-two/preTagger/model/suffixes.js +171 -0
- package/src/02-two/preTagger/plugin.js +12 -0
- package/src/03-three/adjectives/api.js +34 -0
- package/src/03-three/adjectives/plugin.js +5 -0
- package/src/03-three/nouns/api.js +74 -0
- package/src/03-three/nouns/plugin.js +5 -0
- package/src/03-three/numbers/api.js +259 -0
- package/src/03-three/numbers/data.js +77 -0
- package/src/03-three/numbers/format/index.js +27 -0
- package/src/03-three/numbers/format/toText.js +118 -0
- package/src/03-three/numbers/parse/fromText.js +52 -0
- package/src/03-three/numbers/parse/index.js +63 -0
- package/src/03-three/numbers/plugin.js +5 -0
- package/src/03-three/verbs/api.js +41 -0
- package/src/03-three/verbs/plugin.js +5 -0
- package/src/_lib.js +4 -0
- package/src/_version.js +1 -0
- package/src/index.js +53 -0
- package/types/index.d.ts +46 -0
- package/types/misc.ts +92 -0
- package/types/view/de.ts +61 -0
- package/types/view/one.ts +235 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
//sweep-through all prefixes
|
|
3
|
+
const prefixLoop = function (str = '', prefixes = []) {
|
|
4
|
+
const len = str.length
|
|
5
|
+
let max = 10
|
|
6
|
+
if (max > len - 3) {
|
|
7
|
+
max = len - 3
|
|
8
|
+
}
|
|
9
|
+
for (let i = max; i > 2; i -= 1) {
|
|
10
|
+
let prefix = str.substring(0, i)
|
|
11
|
+
if (prefixes[prefix.length].hasOwnProperty(prefix) === true) {
|
|
12
|
+
let tag = prefixes[prefix.length][prefix]
|
|
13
|
+
return tag
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// give 'overwork' the same tag as 'work'
|
|
20
|
+
const checkPrefix = function (terms, i, world) {
|
|
21
|
+
let setTag = world.methods.one.setTag
|
|
22
|
+
let term = terms[i]
|
|
23
|
+
if (term.tags.size === 0) {
|
|
24
|
+
let tag = prefixLoop(term.normal, world.model.two.prefixPatterns)
|
|
25
|
+
if (tag !== null) {
|
|
26
|
+
setTag([term], tag, world, false, '2-prefix')
|
|
27
|
+
term.confidence = 0.5
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
export default checkPrefix
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
//sweep-through all suffixes
|
|
3
|
+
const suffixLoop = function (str = '', suffixes = []) {
|
|
4
|
+
const len = str.length
|
|
5
|
+
let max = 10
|
|
6
|
+
if (len <= max) {
|
|
7
|
+
max = len - 1
|
|
8
|
+
}
|
|
9
|
+
for (let i = max; i > 1; i -= 1) {
|
|
10
|
+
let suffix = str.substr(len - i, len)
|
|
11
|
+
if (suffixes[suffix.length].hasOwnProperty(suffix) === true) {
|
|
12
|
+
// console.log(suffix)
|
|
13
|
+
let tag = suffixes[suffix.length][suffix]
|
|
14
|
+
return tag
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// decide tag from the ending of the word
|
|
21
|
+
const suffixCheck = function (terms, i, world) {
|
|
22
|
+
let setTag = world.methods.one.setTag
|
|
23
|
+
let suffixes = world.model.two.suffixPatterns
|
|
24
|
+
let term = terms[i]
|
|
25
|
+
if (term.tags.size === 0) {
|
|
26
|
+
let tag = suffixLoop(term.normal, suffixes)
|
|
27
|
+
if (tag !== null) {
|
|
28
|
+
setTag([term], tag, world, false, '2-suffix')
|
|
29
|
+
term.confidence = 0.7
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
// try implicit form of word, too
|
|
33
|
+
if (term.implicit) {
|
|
34
|
+
tag = suffixLoop(term.implicit, suffixes)
|
|
35
|
+
if (tag !== null) {
|
|
36
|
+
setTag([term], tag, world, false, '2-implicit-suffix')
|
|
37
|
+
term.confidence = 0.7
|
|
38
|
+
return true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
export default suffixCheck
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// 1st pass
|
|
2
|
+
import checkRegex from './1st-pass/regex.js'
|
|
3
|
+
import titleCase from './1st-pass/titlecase.js'
|
|
4
|
+
import checkYear from './1st-pass/year.js'
|
|
5
|
+
// 2nd pass
|
|
6
|
+
import acronym from './2nd-pass/acronym.js'
|
|
7
|
+
// import neighbours from './2nd-pass/neighbours.js'
|
|
8
|
+
import fallback from './2nd-pass/fallback.js'
|
|
9
|
+
import suffixCheck from './2nd-pass/suffix-lookup.js'
|
|
10
|
+
import prefixCheck from './2nd-pass/prefix-lookup.js'
|
|
11
|
+
|
|
12
|
+
// these methods don't care about word-neighbours
|
|
13
|
+
const firstPass = function (terms, world) {
|
|
14
|
+
for (let i = 0; i < terms.length; i += 1) {
|
|
15
|
+
// is it titlecased?
|
|
16
|
+
let found = titleCase(terms, i, world)
|
|
17
|
+
// try look-like rules
|
|
18
|
+
found = found || checkRegex(terms, i, world)
|
|
19
|
+
// turn '1993' into a year
|
|
20
|
+
checkYear(terms, i, world)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const secondPass = function (terms, world) {
|
|
24
|
+
for (let i = 0; i < terms.length; i += 1) {
|
|
25
|
+
let found = acronym(terms, i, world)
|
|
26
|
+
found = found || suffixCheck(terms, i, world)
|
|
27
|
+
found = found || prefixCheck(terms, i, world)
|
|
28
|
+
// found = found || neighbours(terms, i, world)
|
|
29
|
+
found = found || fallback(terms, i, world)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const tagger = function (view) {
|
|
35
|
+
let world = view.world
|
|
36
|
+
view.docs.forEach(terms => {
|
|
37
|
+
firstPass(terms, world)
|
|
38
|
+
secondPass(terms, world)
|
|
39
|
+
})
|
|
40
|
+
return view
|
|
41
|
+
}
|
|
42
|
+
export default tagger
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import regexNormal from './regex/regex-normal.js'
|
|
2
|
+
import regexNumbers from './regex/regex-numbers.js'
|
|
3
|
+
import regexText from './regex/regex-text.js'
|
|
4
|
+
import suffixPatterns from './suffixes.js'
|
|
5
|
+
import prefixPatterns from './prefixes.js'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
regexNormal,
|
|
10
|
+
regexNumbers,
|
|
11
|
+
regexText,
|
|
12
|
+
suffixPatterns,
|
|
13
|
+
prefixPatterns
|
|
14
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const val = 'TextValue'
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
null,
|
|
5
|
+
{
|
|
6
|
+
// one-letter prefixes
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
// two-letter prefixes
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
// three-letter prefixes
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
// four-letter prefixes
|
|
16
|
+
"eins": val,
|
|
17
|
+
"zwei": val,
|
|
18
|
+
"drei": val,
|
|
19
|
+
"vier": val,
|
|
20
|
+
"fünf": val,
|
|
21
|
+
"acht": val,
|
|
22
|
+
"neun": val,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
// five-letter prefixes
|
|
26
|
+
"sechs": val,
|
|
27
|
+
"sieben": val,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
// six-letter prefixes
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
// seven-letter prefixes
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
// eight-letter prefixes
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
// nine-letter prefixes
|
|
40
|
+
einhunder: val
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
// ten-letter prefixes
|
|
44
|
+
zweihunder: val
|
|
45
|
+
},
|
|
46
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
//web tags
|
|
3
|
+
[/^[\w.]+@[\w.]+\.[a-z]{2,3}$/, 'Email'],
|
|
4
|
+
[/^(https?:\/\/|www\.)+\w+\.[a-z]{2,3}/, 'Url', 'http..'],
|
|
5
|
+
[/^[a-z0-9./].+\.(com|net|gov|org|ly|edu|info|biz|dev|ru|jp|de|in|uk|br|io|ai)/, 'Url', '.com'],
|
|
6
|
+
|
|
7
|
+
// timezones
|
|
8
|
+
[/^[PMCE]ST$/, 'Timezone', 'EST'],
|
|
9
|
+
|
|
10
|
+
//names
|
|
11
|
+
[/^ma?c'.*/, 'LastName', "mc'neil"],
|
|
12
|
+
[/^o'[drlkn].*/, 'LastName', "o'connor"],
|
|
13
|
+
[/^ma?cd[aeiou]/, 'LastName', 'mcdonald'],
|
|
14
|
+
|
|
15
|
+
//slang things
|
|
16
|
+
[/^(lol)+[sz]$/, 'Expression', 'lol'],
|
|
17
|
+
[/^wo{2,}a*h?$/, 'Expression', 'wooah'],
|
|
18
|
+
[/^(hee?){2,}h?$/, 'Expression', 'hehe'],
|
|
19
|
+
[/^(un|de|re)\\-[a-z\u00C0-\u00FF]{2}/, 'Verb', 'un-vite'],
|
|
20
|
+
|
|
21
|
+
// m/h
|
|
22
|
+
[/^(m|k|cm|km)\/(s|h|hr)$/, 'Unit', '5 k/m'],
|
|
23
|
+
// μg/g
|
|
24
|
+
[/^(ug|ng|mg)\/(l|m3|ft3)$/, 'Unit', 'ug/L'],
|
|
25
|
+
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
|
|
3
|
+
[/^@1?[0-9](am|pm)$/i, 'Time', '3pm'],
|
|
4
|
+
[/^[0-9]{2}[:.][0-9]{2}(am|pm)?$/i, 'Time', '13.30pm'],
|
|
5
|
+
[/^'[0-9]{2}$/, 'Year'],
|
|
6
|
+
// times
|
|
7
|
+
[/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])$/, 'Time', '3:12:31'],
|
|
8
|
+
[/^[012]?[0-9](:[0-5][0-9])?(:[0-5][0-9])? ?(am|pm)$/i, 'Time', '1:12pm'],
|
|
9
|
+
[/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])? ?(am|pm)?$/i, 'Time', '1:12:31pm'], //can remove?
|
|
10
|
+
|
|
11
|
+
// iso-dates
|
|
12
|
+
[/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}/i, 'Date', 'iso-date'],
|
|
13
|
+
[/^[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,4}$/, 'Date', 'iso-dash'],
|
|
14
|
+
[/^[0-9]{1,4}\/[0-9]{1,2}\/[0-9]{1,4}$/, 'Date', 'iso-slash'],
|
|
15
|
+
[/^[0-9]{1,4}\.[0-9]{1,2}\.[0-9]{1,4}$/, 'Date', 'iso-dot'],
|
|
16
|
+
[/^[0-9]{1,4}-[a-z]{2,9}-[0-9]{1,4}$/i, 'Date', '12-dec-2019'],
|
|
17
|
+
|
|
18
|
+
// timezones
|
|
19
|
+
[/^utc ?[+-]?[0-9]+$/, 'Timezone', 'utc-9'],
|
|
20
|
+
[/^(gmt|utc)[+-][0-9]{1,2}$/i, 'Timezone', 'gmt-3'],
|
|
21
|
+
|
|
22
|
+
//phone numbers
|
|
23
|
+
[/^[0-9]{3}-[0-9]{4}$/, 'PhoneNumber', '421-0029'],
|
|
24
|
+
[/^(\+?[0-9][ -])?[0-9]{3}[ -]?[0-9]{3}-[0-9]{4}$/, 'PhoneNumber', '1-800-'],
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
//money
|
|
28
|
+
//like $5.30
|
|
29
|
+
[
|
|
30
|
+
/^[-+]?[$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6][-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?([kmb]|bn)?\+?$/,
|
|
31
|
+
['Money', 'Value'],
|
|
32
|
+
'$5.30',
|
|
33
|
+
],
|
|
34
|
+
//like 5.30$
|
|
35
|
+
[
|
|
36
|
+
/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?[$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]\+?$/,
|
|
37
|
+
['Money', 'Value'],
|
|
38
|
+
'5.30£',
|
|
39
|
+
],
|
|
40
|
+
//like
|
|
41
|
+
[/^[-+]?[$£]?[0-9]([0-9,.])+(usd|eur|jpy|gbp|cad|aud|chf|cny|hkd|nzd|kr|rub)$/i, ['Money', 'Value'], '$400usd'],
|
|
42
|
+
|
|
43
|
+
//numbers
|
|
44
|
+
// german-format - '.' groups thousands
|
|
45
|
+
[/^[-+]?[0-9]{1,3}(\.[0-9]{3})+(,[0-9]+)?$/, ['Cardinal', 'NumericValue'], '1.234.567'],
|
|
46
|
+
// 50 | -50 | 3.23 | 5,999.0 | 10+
|
|
47
|
+
[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?\+?$/, ['Cardinal', 'NumericValue'], '5,999'],
|
|
48
|
+
[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?(st|nd|rd|r?th)$/, ['Ordinal', 'NumericValue'], '53rd'],
|
|
49
|
+
// .73th
|
|
50
|
+
[/^\.[0-9]+\+?$/, ['Cardinal', 'NumericValue'], '.73th'],
|
|
51
|
+
//percent
|
|
52
|
+
[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?%\+?$/, ['Percent', 'Cardinal', 'NumericValue'], '-4%'],
|
|
53
|
+
[/^\.[0-9]+%$/, ['Percent', 'Cardinal', 'NumericValue'], '.3%'],
|
|
54
|
+
//fraction
|
|
55
|
+
[/^[0-9]{1,4}\/[0-9]{1,4}(st|nd|rd|th)?s?$/, ['Fraction', 'NumericValue'], '2/3rds'],
|
|
56
|
+
//range
|
|
57
|
+
[/^[0-9.]{1,3}[a-z]{0,2}[-–—][0-9]{1,3}[a-z]{0,2}$/, ['Value', 'NumberRange'], '3-4'],
|
|
58
|
+
//time-range
|
|
59
|
+
[/^[0-9]{1,2}(:[0-9][0-9])?(am|pm)? ?[-–—] ?[0-9]{1,2}(:[0-9][0-9])?(am|pm)$/, ['Time', 'NumberRange'], '3-4pm'],
|
|
60
|
+
//with unit
|
|
61
|
+
[/^[0-9.]+([a-z]{1,4})$/, 'Value', '9km'],
|
|
62
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
// #coolguy
|
|
3
|
+
[/^#[a-z0-9_\u00C0-\u00FF]{2,}$/i, 'HashTag'],
|
|
4
|
+
|
|
5
|
+
// @spencermountain
|
|
6
|
+
[/^@\w{2,}$/, 'AtMention'],
|
|
7
|
+
|
|
8
|
+
// period-ones acronyms - f.b.i.
|
|
9
|
+
[/^([A-ZÄÖÜ]\.){2}[A-ZÄÖÜ]?/i, ['Acronym', 'Noun'], 'F.B.I'], //ascii-only
|
|
10
|
+
|
|
11
|
+
// ending-apostrophes
|
|
12
|
+
[/.{3}[lkmnp]in['‘’‛‵′`´]$/, 'Gerund', "chillin'"],
|
|
13
|
+
[/.{4}s['‘’‛‵′`´]$/, 'Possessive', "flanders'"],
|
|
14
|
+
|
|
15
|
+
// german ordinals '4.'
|
|
16
|
+
// [/^[0-9]+\.$/, 'Ordinal'],
|
|
17
|
+
]
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const rb = 'Adverb'
|
|
2
|
+
const nn = 'Noun'
|
|
3
|
+
const vb = 'Verb'
|
|
4
|
+
const jj = 'Adjective'
|
|
5
|
+
const ord = 'TextOrdinal'
|
|
6
|
+
const card = 'TextCardinal'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
null,
|
|
11
|
+
{
|
|
12
|
+
// one-letter suffixes
|
|
13
|
+
s: nn,
|
|
14
|
+
l: nn,
|
|
15
|
+
a: nn,
|
|
16
|
+
k: nn,
|
|
17
|
+
d: nn,
|
|
18
|
+
z: nn,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
// two-letter suffixes
|
|
22
|
+
ig: jj,
|
|
23
|
+
ls: rb,
|
|
24
|
+
// er: nn,
|
|
25
|
+
el: nn,
|
|
26
|
+
et: vb,
|
|
27
|
+
gt: vb,
|
|
28
|
+
lt: vb,
|
|
29
|
+
// en: vb,
|
|
30
|
+
ns: nn,
|
|
31
|
+
ts: nn,
|
|
32
|
+
// ht: vb,
|
|
33
|
+
'ßt': vb
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
// three-letter suffixes
|
|
37
|
+
che: jj,
|
|
38
|
+
ige: jj,
|
|
39
|
+
// ger: jj,
|
|
40
|
+
tig: jj,
|
|
41
|
+
end: jj,
|
|
42
|
+
// mal: rb,
|
|
43
|
+
hin: rb,
|
|
44
|
+
ung: nn,
|
|
45
|
+
ion: nn,
|
|
46
|
+
ter: nn,
|
|
47
|
+
ert: vb,
|
|
48
|
+
tet: vb,
|
|
49
|
+
ten: vb,
|
|
50
|
+
eln: vb,
|
|
51
|
+
ern: vb,
|
|
52
|
+
gen: vb,
|
|
53
|
+
fen: vb,
|
|
54
|
+
// ben: vb,
|
|
55
|
+
// ren: vb,
|
|
56
|
+
// fen: vb,
|
|
57
|
+
// men: vb,
|
|
58
|
+
igt: vb,
|
|
59
|
+
tzt: vb,
|
|
60
|
+
det: vb,
|
|
61
|
+
elt: vb,
|
|
62
|
+
ete: vb,
|
|
63
|
+
elf: card,//eleven
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
// four-letter suffixes
|
|
67
|
+
chen: jj,
|
|
68
|
+
lich: jj,
|
|
69
|
+
igen: jj,
|
|
70
|
+
cher: jj,
|
|
71
|
+
ende: jj,
|
|
72
|
+
isch: jj,
|
|
73
|
+
enen: jj,
|
|
74
|
+
tige: jj,
|
|
75
|
+
tens: rb,
|
|
76
|
+
mals: rb,
|
|
77
|
+
rung: nn,
|
|
78
|
+
iert: vb,
|
|
79
|
+
eben: vb,
|
|
80
|
+
ehen: vb,
|
|
81
|
+
mmen: vb,
|
|
82
|
+
llen: vb,
|
|
83
|
+
ngen: vb,
|
|
84
|
+
tzen: vb,
|
|
85
|
+
hren: vb,
|
|
86
|
+
cken: vb,
|
|
87
|
+
ssen: vb,
|
|
88
|
+
eßen: vb,
|
|
89
|
+
hnen: vb,
|
|
90
|
+
ufen: vb,
|
|
91
|
+
lten: vb,
|
|
92
|
+
hten: vb,
|
|
93
|
+
zehn: card,//10s
|
|
94
|
+
eins: card,
|
|
95
|
+
zwei: card,
|
|
96
|
+
drei: card,
|
|
97
|
+
vier: card,
|
|
98
|
+
fünf: card,
|
|
99
|
+
acht: card,
|
|
100
|
+
neun: card,
|
|
101
|
+
// zehn: card,
|
|
102
|
+
// lten: vb,
|
|
103
|
+
// ssen: vb
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
// five-letter suffixes
|
|
107
|
+
ische: jj,
|
|
108
|
+
zwölf: card,
|
|
109
|
+
sechs: card,
|
|
110
|
+
liche: jj,
|
|
111
|
+
// enden: jj,
|
|
112
|
+
tlich: jj,
|
|
113
|
+
// tigen: jj,
|
|
114
|
+
stens: rb,
|
|
115
|
+
falls: rb,
|
|
116
|
+
weise: rb,
|
|
117
|
+
seits: rb,
|
|
118
|
+
ungen: nn,
|
|
119
|
+
erung: nn,
|
|
120
|
+
ieren: vb,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
// six-letter suffixes
|
|
124
|
+
igsten: jj,
|
|
125
|
+
ischen: jj,
|
|
126
|
+
sieben: card,
|
|
127
|
+
lichen: jj,
|
|
128
|
+
tische: jj,
|
|
129
|
+
nische: jj,
|
|
130
|
+
zehnte: ord,
|
|
131
|
+
zigste: ord,
|
|
132
|
+
ßigste: ord,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
// seven-letter suffixes
|
|
136
|
+
zigsten: ord,
|
|
137
|
+
tischen: jj,
|
|
138
|
+
tlichen: jj,
|
|
139
|
+
nischen: jj,
|
|
140
|
+
zwanzig: card,//20
|
|
141
|
+
dreißig: card,//30
|
|
142
|
+
vierzig: card,//40
|
|
143
|
+
fünfzig: card,//50
|
|
144
|
+
sechzig: card, //60
|
|
145
|
+
siebzig: card, //70
|
|
146
|
+
achtzig: card, //80
|
|
147
|
+
neunzig: card, //90
|
|
148
|
+
hundert: card,//100
|
|
149
|
+
tausend: card,//1,000
|
|
150
|
+
},
|
|
151
|
+
// eight-letter suffixes
|
|
152
|
+
{
|
|
153
|
+
dreizehn: card,
|
|
154
|
+
vierzehn: card,
|
|
155
|
+
fünfzehn: card,
|
|
156
|
+
sechzehn: card,
|
|
157
|
+
siebzehn: card,
|
|
158
|
+
achtzehn: card,
|
|
159
|
+
neunzehn: card,
|
|
160
|
+
|
|
161
|
+
},
|
|
162
|
+
// nine-letter suffixes
|
|
163
|
+
{
|
|
164
|
+
},
|
|
165
|
+
// ten-letter suffixes
|
|
166
|
+
{
|
|
167
|
+
hundertste: ord,
|
|
168
|
+
tausendste: ord,
|
|
169
|
+
millionste: ord
|
|
170
|
+
},
|
|
171
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const getNth = (doc, n) => (typeof n === 'number' ? doc.eq(n) : doc)
|
|
2
|
+
|
|
3
|
+
// get root form of adjective
|
|
4
|
+
const getRoot = function (m) {
|
|
5
|
+
m = m.eq(0).compute('root')
|
|
6
|
+
return m.text('root')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const api = function (View) {
|
|
10
|
+
class Adjectives extends View {
|
|
11
|
+
constructor(document, pointer, groups) {
|
|
12
|
+
super(document, pointer, groups)
|
|
13
|
+
this.viewType = 'Adjectives'
|
|
14
|
+
}
|
|
15
|
+
conjugate(n) {
|
|
16
|
+
const methods = this.methods.two.transform.adjective
|
|
17
|
+
const { inflect, toRoot } = methods
|
|
18
|
+
return getNth(this, n).map(m => {
|
|
19
|
+
let str = getRoot(m, methods)
|
|
20
|
+
let root = toRoot(str) || str
|
|
21
|
+
let res = inflect(root)
|
|
22
|
+
res.infinitive = root
|
|
23
|
+
return res
|
|
24
|
+
}, [])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
View.prototype.adjectives = function (n) {
|
|
29
|
+
let m = this.match('#Adjective')
|
|
30
|
+
m = getNth(m, n)
|
|
31
|
+
return new Adjectives(this.document, m.pointer)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export default api
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const getNth = (doc, n) => (typeof n === 'number' ? doc.eq(n) : doc)
|
|
2
|
+
|
|
3
|
+
// get (lower-cased) singular form of noun
|
|
4
|
+
const getRoot = function (m) {
|
|
5
|
+
m = m.eq(0).compute('root')
|
|
6
|
+
return m.text('root')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// german nouns are capitalized - keep the casing of the original word
|
|
10
|
+
const matchCase = function (m, str) {
|
|
11
|
+
if (/^[A-ZÄÖÜ]/.test(m.text().trim())) {
|
|
12
|
+
return str.charAt(0).toUpperCase() + str.substring(1)
|
|
13
|
+
}
|
|
14
|
+
return str
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 'hunde' → 'hund' → 'hunde' round-trips, so it is already a plural,
|
|
18
|
+
// even when the tagger could not tell - 'die Hunde' vs 'der Kunde'
|
|
19
|
+
const isPluralForm = function (methods, str) {
|
|
20
|
+
let single = methods.toSingular(str)
|
|
21
|
+
return single !== str && methods.toPlural(single).one === str
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const api = function (View) {
|
|
25
|
+
class Nouns extends View {
|
|
26
|
+
constructor(document, pointer, groups) {
|
|
27
|
+
super(document, pointer, groups)
|
|
28
|
+
this.viewType = 'Nouns'
|
|
29
|
+
}
|
|
30
|
+
conjugate(n) {
|
|
31
|
+
const methods = this.methods.two.transform.noun
|
|
32
|
+
return getNth(this, n).map(m => {
|
|
33
|
+
let root = getRoot(m)
|
|
34
|
+
return {
|
|
35
|
+
singular: root,
|
|
36
|
+
plural: methods.toPlural(root).one,
|
|
37
|
+
}
|
|
38
|
+
}, [])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
isPlural(n) {
|
|
42
|
+
return getNth(this, n).if('#Plural')
|
|
43
|
+
}
|
|
44
|
+
toPlural(n) {
|
|
45
|
+
const methods = this.methods.two.transform.noun
|
|
46
|
+
return getNth(this, n).not('#Plural').map(m => {
|
|
47
|
+
if (isPluralForm(methods, m.text('normal'))) {
|
|
48
|
+
return m
|
|
49
|
+
}
|
|
50
|
+
let str = getRoot(m)
|
|
51
|
+
let plural = methods.toPlural(str).one
|
|
52
|
+
return m.replaceWith(matchCase(m, plural))
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
toSingular(n) {
|
|
56
|
+
const methods = this.methods.two.transform.noun
|
|
57
|
+
return getNth(this, n).not('#Singular').map(m => {
|
|
58
|
+
let str = m.text('normal')
|
|
59
|
+
if (!m.has('#Plural') && !isPluralForm(methods, str)) {
|
|
60
|
+
return m
|
|
61
|
+
}
|
|
62
|
+
let singular = methods.toSingular(str)
|
|
63
|
+
return m.replaceWith(matchCase(m, singular))
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
View.prototype.nouns = function (n) {
|
|
69
|
+
let m = this.match('#Noun+')
|
|
70
|
+
m = getNth(m, n)
|
|
71
|
+
return new Nouns(this.document, m.pointer)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export default api
|