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,259 @@
|
|
|
1
|
+
import parse from './parse/index.js'
|
|
2
|
+
import format from './format/index.js'
|
|
3
|
+
|
|
4
|
+
// return the nth elem of a doc
|
|
5
|
+
export const getNth = (doc, n) => (typeof n === 'number' ? doc.eq(n) : doc)
|
|
6
|
+
|
|
7
|
+
const api = function (View) {
|
|
8
|
+
/** */
|
|
9
|
+
class Numbers extends View {
|
|
10
|
+
constructor(document, pointer, groups) {
|
|
11
|
+
super(document, pointer, groups)
|
|
12
|
+
this.viewType = 'Numbers'
|
|
13
|
+
}
|
|
14
|
+
parse(n) {
|
|
15
|
+
return getNth(this, n).map(parse)
|
|
16
|
+
}
|
|
17
|
+
get(n) {
|
|
18
|
+
return getNth(this, n).map(parse).map(o => o.num)
|
|
19
|
+
}
|
|
20
|
+
json(n) {
|
|
21
|
+
let doc = getNth(this, n)
|
|
22
|
+
return doc.map(p => {
|
|
23
|
+
let json = p.toView().json(n)[0]
|
|
24
|
+
let parsed = parse(p)
|
|
25
|
+
json.number = {
|
|
26
|
+
prefix: parsed.prefix,
|
|
27
|
+
num: parsed.num,
|
|
28
|
+
suffix: parsed.suffix,
|
|
29
|
+
hasComma: parsed.hasComma,
|
|
30
|
+
}
|
|
31
|
+
return json
|
|
32
|
+
}, [])
|
|
33
|
+
}
|
|
34
|
+
/** any known measurement unit, for the number */
|
|
35
|
+
units() {
|
|
36
|
+
return this.growRight('#Unit').match('#Unit$')
|
|
37
|
+
}
|
|
38
|
+
/** return only ordinal numbers */
|
|
39
|
+
isOrdinal() {
|
|
40
|
+
return this.if('#Ordinal')
|
|
41
|
+
}
|
|
42
|
+
/** return only cardinal numbers*/
|
|
43
|
+
isCardinal() {
|
|
44
|
+
return this.if('#Cardinal')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** convert to numeric form like '8' or '8th' */
|
|
48
|
+
toNumber() {
|
|
49
|
+
let m = this.if('#TextValue')
|
|
50
|
+
let res = m.map(val => {
|
|
51
|
+
let obj = parse(val)
|
|
52
|
+
if (obj.num === null) {
|
|
53
|
+
return val
|
|
54
|
+
}
|
|
55
|
+
let fmt = val.has('#Ordinal') ? 'Ordinal' : 'Cardinal'
|
|
56
|
+
let str = format(obj, fmt)
|
|
57
|
+
if (str) {
|
|
58
|
+
val.replaceWith(str, { tags: true })
|
|
59
|
+
val.tag('NumericValue')
|
|
60
|
+
}
|
|
61
|
+
return val
|
|
62
|
+
})
|
|
63
|
+
return new Numbers(res.document, res.pointer)
|
|
64
|
+
}
|
|
65
|
+
/** convert to numeric form like 'eight' or 'eighth' */
|
|
66
|
+
toText() {
|
|
67
|
+
let m = this
|
|
68
|
+
let res = m.map(val => {
|
|
69
|
+
if (val.has('#TextValue')) {
|
|
70
|
+
return val
|
|
71
|
+
}
|
|
72
|
+
let obj = parse(val)
|
|
73
|
+
if (obj.num === null) {
|
|
74
|
+
return val
|
|
75
|
+
}
|
|
76
|
+
let fmt = val.has('#Ordinal') ? 'TextOrdinal' : 'TextCardinal'
|
|
77
|
+
let str = format(obj, fmt)
|
|
78
|
+
if (str) {
|
|
79
|
+
val.replaceWith(str, { tags: true })
|
|
80
|
+
val.tag('TextValue')
|
|
81
|
+
}
|
|
82
|
+
return val
|
|
83
|
+
})
|
|
84
|
+
return new Numbers(res.document, res.pointer)
|
|
85
|
+
}
|
|
86
|
+
/** convert ordinal to cardinal form, like 'eight', or '8' */
|
|
87
|
+
toCardinal() {
|
|
88
|
+
let m = this
|
|
89
|
+
let res = m.map(val => {
|
|
90
|
+
if (!val.has('#Ordinal')) {
|
|
91
|
+
return val
|
|
92
|
+
}
|
|
93
|
+
let obj = parse(val)
|
|
94
|
+
if (obj.num === null) {
|
|
95
|
+
return val
|
|
96
|
+
}
|
|
97
|
+
let fmt = val.has('#TextValue') ? 'TextCardinal' : 'Cardinal'
|
|
98
|
+
let str = format(obj, fmt)
|
|
99
|
+
if (str) {
|
|
100
|
+
val.replaceWith(str, { tags: true })
|
|
101
|
+
val.tag('Cardinal')
|
|
102
|
+
}
|
|
103
|
+
return val
|
|
104
|
+
})
|
|
105
|
+
return new Numbers(res.document, res.pointer)
|
|
106
|
+
}
|
|
107
|
+
/** convert cardinal to ordinal form, like 'eighth', or '8th' */
|
|
108
|
+
toOrdinal() {
|
|
109
|
+
let m = this
|
|
110
|
+
let res = m.map(val => {
|
|
111
|
+
if (val.has('#Ordinal')) {
|
|
112
|
+
return val
|
|
113
|
+
}
|
|
114
|
+
let obj = parse(val)
|
|
115
|
+
if (obj.num === null) {
|
|
116
|
+
return val
|
|
117
|
+
}
|
|
118
|
+
let fmt = val.has('#TextValue') ? 'TextOrdinal' : 'Ordinal'
|
|
119
|
+
let str = format(obj, fmt)
|
|
120
|
+
if (str) {
|
|
121
|
+
val.replaceWith(str, { tags: true })
|
|
122
|
+
val.tag('Ordinal')
|
|
123
|
+
}
|
|
124
|
+
return val
|
|
125
|
+
})
|
|
126
|
+
return new Numbers(res.document, res.pointer)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** return only numbers that are == n */
|
|
130
|
+
isEqual(n) {
|
|
131
|
+
return this.filter((val) => {
|
|
132
|
+
let num = parse(val).num
|
|
133
|
+
return num === n
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
/** return only numbers that are > n*/
|
|
137
|
+
greaterThan(n) {
|
|
138
|
+
return this.filter((val) => {
|
|
139
|
+
let num = parse(val).num
|
|
140
|
+
return num > n
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
/** return only numbers that are < n*/
|
|
144
|
+
lessThan(n) {
|
|
145
|
+
return this.filter((val) => {
|
|
146
|
+
let num = parse(val).num
|
|
147
|
+
return num < n
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
/** return only numbers > min and < max */
|
|
151
|
+
between(min, max) {
|
|
152
|
+
return this.filter((val) => {
|
|
153
|
+
let num = parse(val).num
|
|
154
|
+
return num > min && num < max
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
/** set these number to n */
|
|
158
|
+
set(n) {
|
|
159
|
+
if (n === undefined) {
|
|
160
|
+
return this // don't bother
|
|
161
|
+
}
|
|
162
|
+
if (typeof n === 'string') {
|
|
163
|
+
n = parse(n).num
|
|
164
|
+
}
|
|
165
|
+
let m = this
|
|
166
|
+
let res = m.map((val) => {
|
|
167
|
+
let obj = parse(val)
|
|
168
|
+
obj.num = n
|
|
169
|
+
if (obj.num === null) {
|
|
170
|
+
return val
|
|
171
|
+
}
|
|
172
|
+
let fmt = val.has('#Ordinal') ? 'Ordinal' : 'Cardinal'
|
|
173
|
+
if (val.has('#TextValue')) {
|
|
174
|
+
fmt = val.has('#Ordinal') ? 'TextOrdinal' : 'TextCardinal'
|
|
175
|
+
}
|
|
176
|
+
let str = format(obj, fmt)
|
|
177
|
+
// re-group thousands - '1.234.567'
|
|
178
|
+
if (obj.hasComma && fmt === 'Cardinal') {
|
|
179
|
+
str = obj.num.toLocaleString('de-DE')
|
|
180
|
+
}
|
|
181
|
+
if (str) {
|
|
182
|
+
val = val.not('#Currency')
|
|
183
|
+
val.replaceWith(str, { tags: true })
|
|
184
|
+
// handle plural/singular unit
|
|
185
|
+
// agreeUnits(agree, val, obj)
|
|
186
|
+
}
|
|
187
|
+
return val
|
|
188
|
+
})
|
|
189
|
+
return new Numbers(res.document, res.pointer)
|
|
190
|
+
}
|
|
191
|
+
add(n) {
|
|
192
|
+
if (!n) {
|
|
193
|
+
return this // don't bother
|
|
194
|
+
}
|
|
195
|
+
if (typeof n === 'string') {
|
|
196
|
+
n = parse(n).num
|
|
197
|
+
}
|
|
198
|
+
let m = this
|
|
199
|
+
let res = m.map((val) => {
|
|
200
|
+
let obj = parse(val)
|
|
201
|
+
if (obj.num === null) {
|
|
202
|
+
return val
|
|
203
|
+
}
|
|
204
|
+
obj.num += n
|
|
205
|
+
let fmt = val.has('#Ordinal') ? 'Ordinal' : 'Cardinal'
|
|
206
|
+
if (obj.isText) {
|
|
207
|
+
fmt = val.has('#Ordinal') ? 'TextOrdinal' : 'TextCardinal'
|
|
208
|
+
}
|
|
209
|
+
let str = format(obj, fmt)
|
|
210
|
+
if (str) {
|
|
211
|
+
val.replaceWith(str, { tags: true })
|
|
212
|
+
// handle plural/singular unit
|
|
213
|
+
// agreeUnits(agree, val, obj)
|
|
214
|
+
}
|
|
215
|
+
return val
|
|
216
|
+
})
|
|
217
|
+
return new Numbers(res.document, res.pointer)
|
|
218
|
+
}
|
|
219
|
+
/** decrease each number by n*/
|
|
220
|
+
subtract(n, agree) {
|
|
221
|
+
return this.add(n * -1, agree)
|
|
222
|
+
}
|
|
223
|
+
/** increase each number by 1 */
|
|
224
|
+
increment(agree) {
|
|
225
|
+
return this.add(1, agree)
|
|
226
|
+
}
|
|
227
|
+
/** decrease each number by 1 */
|
|
228
|
+
decrement(agree) {
|
|
229
|
+
return this.add(-1, agree)
|
|
230
|
+
}
|
|
231
|
+
// overloaded - keep Numbers class
|
|
232
|
+
update(pointer) {
|
|
233
|
+
let m = new Numbers(this.document, pointer)
|
|
234
|
+
m._cache = this._cache // share this full thing
|
|
235
|
+
return m
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// aliases
|
|
239
|
+
Numbers.prototype.isBetween = Numbers.prototype.between
|
|
240
|
+
Numbers.prototype.minus = Numbers.prototype.subtract
|
|
241
|
+
Numbers.prototype.plus = Numbers.prototype.add
|
|
242
|
+
Numbers.prototype.equals = Numbers.prototype.isEqual
|
|
243
|
+
|
|
244
|
+
View.prototype.numbers = function (n) {
|
|
245
|
+
let m = this.match('#Value+')
|
|
246
|
+
// most numbers are 1-term
|
|
247
|
+
// but very-large numbers get broken up 'zwei Millionen eins'
|
|
248
|
+
if (!m.has('(million|millionen|milliarde)')) {
|
|
249
|
+
m = m.terms()
|
|
250
|
+
}
|
|
251
|
+
// make sure splitter has run
|
|
252
|
+
m.compute('splitter')
|
|
253
|
+
m = getNth(m, n)
|
|
254
|
+
return new Numbers(this.document, m.pointer)
|
|
255
|
+
}
|
|
256
|
+
// alias
|
|
257
|
+
View.prototype.values = View.prototype.numbers
|
|
258
|
+
}
|
|
259
|
+
export default api
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
let data = {
|
|
2
|
+
ones: [
|
|
3
|
+
[1, 'eins', 'erste'],
|
|
4
|
+
[2, 'zwei', 'zweite'],
|
|
5
|
+
[3, 'drei', 'dritte'],
|
|
6
|
+
[4, 'vier', 'vierte'],
|
|
7
|
+
[5, 'fünf', 'fünfte'],
|
|
8
|
+
[6, 'sechs', 'sechste'],
|
|
9
|
+
[7, 'sieben', 'siebente'], //siebte
|
|
10
|
+
[8, 'acht', 'achte'],
|
|
11
|
+
[9, 'neun', 'neunte'],
|
|
12
|
+
],
|
|
13
|
+
teens: [
|
|
14
|
+
[10, 'zehn', 'zehnte'],
|
|
15
|
+
[11, 'elf', 'elfte'],
|
|
16
|
+
[12, 'zwölf', 'zwölfte'],
|
|
17
|
+
[13, 'dreizehn', 'dreizehnte'],
|
|
18
|
+
[14, 'vierzehn', 'vierzehnte'],
|
|
19
|
+
[15, 'fünfzehn', 'fünfzehnte'],
|
|
20
|
+
[16, 'sechzehn', 'sechzehnte'],
|
|
21
|
+
[17, 'siebzehn', 'siebzehnte'],
|
|
22
|
+
[18, 'achtzehn', 'achtzehnte'],
|
|
23
|
+
[19, 'neunzehn', 'neunzehnte'],
|
|
24
|
+
],
|
|
25
|
+
tens: [
|
|
26
|
+
[20, 'zwanzig', 'zwanzigste'],
|
|
27
|
+
[30, 'dreißig', 'dreißigste'],
|
|
28
|
+
[40, 'vierzig', 'vierzigste'],
|
|
29
|
+
[50, 'fünfzig', 'fünfzigste'],
|
|
30
|
+
[60, 'sechzig', 'sechzigste'],
|
|
31
|
+
[70, 'siebzig', 'siebzigste'],
|
|
32
|
+
[80, 'achtzig', 'achtzigste'],
|
|
33
|
+
[90, 'neunzig', 'neunzigste'],
|
|
34
|
+
],
|
|
35
|
+
hundreds: [
|
|
36
|
+
[100, 'einhundert', 'hundertste'],
|
|
37
|
+
// [101, 'einhunderteins', 'hunderterste'],
|
|
38
|
+
[200, 'zweihundert', 'zweihundertste'],
|
|
39
|
+
[300, 'dreihundert', 'dreihundertste'],
|
|
40
|
+
[400, 'vierhundert', 'vierhundertste'],
|
|
41
|
+
[500, 'fünfhundert', 'fünfhundertste'],
|
|
42
|
+
[600, 'sechshundert', 'sechshundertste'],
|
|
43
|
+
[700, 'siebenhundert', 'siebenhundertste'],
|
|
44
|
+
[800, 'achthundert', 'achthundertste'],
|
|
45
|
+
[900, 'neunhundert', 'neunhundertste'],
|
|
46
|
+
],
|
|
47
|
+
multiples: [
|
|
48
|
+
[100, 'hundert', 'hundertste'],
|
|
49
|
+
[1000, 'tausend', 'tausendste'],
|
|
50
|
+
[100000, 'hunderttausend', 'hunderttausendste'],
|
|
51
|
+
[1000000, 'million', 'millionste'],
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
const toCardinal = {}
|
|
55
|
+
const toOrdinal = {}
|
|
56
|
+
const toNumber = {}
|
|
57
|
+
|
|
58
|
+
Object.keys(data).forEach(k => {
|
|
59
|
+
data[k].forEach(a => {
|
|
60
|
+
let [num, w, ord] = a
|
|
61
|
+
toCardinal[ord] = w
|
|
62
|
+
toOrdinal[w] = ord
|
|
63
|
+
toNumber[w] = num
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const isMultiple = new Set(data.multiples.map(a => a[1]))
|
|
68
|
+
|
|
69
|
+
// misc
|
|
70
|
+
toNumber.ein = 1 // eins - ein
|
|
71
|
+
toNumber.hunderteins = 101
|
|
72
|
+
toCardinal.siebte = 'sieben'
|
|
73
|
+
toCardinal.hunderterste = 'hunderteins'
|
|
74
|
+
toOrdinal.hunderteins = 'hunderterste'
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
export { data, toCardinal, toOrdinal, toNumber, isMultiple }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import toText from './toText.js'
|
|
2
|
+
import { toOrdinal } from '../data.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const formatNumber = function (parsed, fmt) {
|
|
6
|
+
if (fmt === 'TextOrdinal') {
|
|
7
|
+
let words = toText(parsed.num)
|
|
8
|
+
let last = words[words.length - 1]
|
|
9
|
+
words[words.length - 1] = toOrdinal[last]
|
|
10
|
+
return words.join('')
|
|
11
|
+
}
|
|
12
|
+
if (fmt === 'TextCardinal') {
|
|
13
|
+
return toText(parsed.num).join('')
|
|
14
|
+
}
|
|
15
|
+
// numeric formats
|
|
16
|
+
// '55e'
|
|
17
|
+
if (fmt === 'Ordinal') {
|
|
18
|
+
let str = String(parsed.num)
|
|
19
|
+
return str += '.'
|
|
20
|
+
}
|
|
21
|
+
if (fmt === 'Cardinal') {
|
|
22
|
+
// german decimals use a comma - '12,5'
|
|
23
|
+
return String(parsed.num).replace('.', ',')
|
|
24
|
+
}
|
|
25
|
+
return String(parsed.num || '').replace('.', ',')
|
|
26
|
+
}
|
|
27
|
+
export default formatNumber
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { data } from '../data.js'
|
|
2
|
+
let tens = data.tens.reverse()
|
|
3
|
+
let teens = data.teens.reverse()
|
|
4
|
+
let ones = data.ones.reverse()
|
|
5
|
+
let hundreds = data.hundreds.reverse()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const doThousands = function (num) {
|
|
9
|
+
let words = []
|
|
10
|
+
// hunderttausend
|
|
11
|
+
if (num >= 100000) {
|
|
12
|
+
for (let i = 0; i < ones.length; i += 1) {
|
|
13
|
+
if (num >= ones[i][0] * 100000) {
|
|
14
|
+
let found = ones[i][0] === 1 ? 'ein' : ones[i][1]
|
|
15
|
+
words.push(found)
|
|
16
|
+
words.push('hunderttausend')
|
|
17
|
+
num -= teens[i][0] * 100000
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// eleven-thousand...
|
|
22
|
+
if (num >= 10000) {
|
|
23
|
+
for (let i = 0; i < teens.length; i += 1) {
|
|
24
|
+
if (num >= teens[i][0] * 1000) {
|
|
25
|
+
words.push(teens[i][1])
|
|
26
|
+
words.push('tausend')
|
|
27
|
+
num -= teens[i][0] * 1000
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// dreitausend, viertausend...
|
|
32
|
+
for (let i = 0; i < ones.length; i += 1) {
|
|
33
|
+
if (num >= ones[i][0] * 1000) {
|
|
34
|
+
let found = ones[i][0] === 1 ? 'ein' : ones[i][1]
|
|
35
|
+
return [found, 'tausend']
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return words
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const doHundreds = function (num) {
|
|
42
|
+
let words = []
|
|
43
|
+
for (let i = 0; i < hundreds.length; i += 1) {
|
|
44
|
+
if (num >= hundreds[i][0]) {
|
|
45
|
+
words.push(hundreds[i][1])
|
|
46
|
+
num -= hundreds[i][0]
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return words
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 23 -> '[drei][und][zwanzig]'
|
|
54
|
+
const twoDigit = function (num) {
|
|
55
|
+
let words = []
|
|
56
|
+
// ninety, eighty ...
|
|
57
|
+
for (let i = 0; i < tens.length; i += 1) {
|
|
58
|
+
if (num >= tens[i][0]) {
|
|
59
|
+
words.push(tens[i][1])
|
|
60
|
+
num -= tens[i][0]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// found nothing? look for teens
|
|
64
|
+
if (words.length === 0) {
|
|
65
|
+
for (let i = 0; i < teens.length; i += 1) {
|
|
66
|
+
if (num === teens[i][0]) {
|
|
67
|
+
return [teens[i][1]] //these don't combine
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// look for ones to add on
|
|
72
|
+
for (let i = 0; i < ones.length; i += 1) {
|
|
73
|
+
if (num === ones[i][0]) {
|
|
74
|
+
// drei und zwanzig
|
|
75
|
+
if (words.length === 1) {
|
|
76
|
+
// use '[ein][und][zwanzig]', not 'eins..'
|
|
77
|
+
let found = ones[i][0] === 1 ? 'ein' : ones[i][1]
|
|
78
|
+
return [found, 'und', words[0]]
|
|
79
|
+
}
|
|
80
|
+
// just 'drei'
|
|
81
|
+
if (words.length === 0) {
|
|
82
|
+
return [ones[i][1]]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return words
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
// turn 130 into '[ein][hundert][dreißig]'
|
|
91
|
+
const toText = function (num) {
|
|
92
|
+
let words = []
|
|
93
|
+
if (num === 0) {
|
|
94
|
+
return ['null']
|
|
95
|
+
}
|
|
96
|
+
if (num < 0) {
|
|
97
|
+
words.push('moins')
|
|
98
|
+
num = Math.abs(num)
|
|
99
|
+
}
|
|
100
|
+
// do '[sieben][tausend]'
|
|
101
|
+
if (num >= 1000) {
|
|
102
|
+
let res = doThousands(num)
|
|
103
|
+
words = words.concat(res)
|
|
104
|
+
num %= 1000
|
|
105
|
+
}
|
|
106
|
+
// do '[zwei][hundert]'
|
|
107
|
+
if (num >= 100) {
|
|
108
|
+
let res = doHundreds(num)
|
|
109
|
+
words = words.concat(res)
|
|
110
|
+
num %= 100
|
|
111
|
+
}
|
|
112
|
+
// do '[drei][und][zwanzig]'
|
|
113
|
+
if (num > 0) {
|
|
114
|
+
words = words.concat(twoDigit(num))
|
|
115
|
+
}
|
|
116
|
+
return words
|
|
117
|
+
}
|
|
118
|
+
export default toText
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { toCardinal, toNumber, isMultiple } from '../data.js'
|
|
2
|
+
|
|
3
|
+
const parseNumbers = function (terms = []) {
|
|
4
|
+
let sum = 0
|
|
5
|
+
let carry = 0
|
|
6
|
+
let minus = false
|
|
7
|
+
|
|
8
|
+
let words = terms[0].splits || []
|
|
9
|
+
// console.log(words)
|
|
10
|
+
let tags = terms[0].tags
|
|
11
|
+
for (let i = 0; i < words.length; i += 1) {
|
|
12
|
+
let w = words[i]
|
|
13
|
+
|
|
14
|
+
if (w === 'minus') {
|
|
15
|
+
minus = true
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
// ... [ein][und][zwanzig]
|
|
19
|
+
if (w === 'und') {
|
|
20
|
+
continue
|
|
21
|
+
}
|
|
22
|
+
// 'huitieme'
|
|
23
|
+
if (tags.has('Ordinal')) {
|
|
24
|
+
w = toCardinal[w] || w
|
|
25
|
+
}
|
|
26
|
+
// 'hundert'
|
|
27
|
+
if (isMultiple.has(w)) {
|
|
28
|
+
let mult = toNumber[w] || 1
|
|
29
|
+
if (carry === 0) {
|
|
30
|
+
carry = 1
|
|
31
|
+
}
|
|
32
|
+
sum += mult * carry
|
|
33
|
+
carry = 0
|
|
34
|
+
continue
|
|
35
|
+
}
|
|
36
|
+
// 'fünf'
|
|
37
|
+
if (toNumber.hasOwnProperty(w)) {
|
|
38
|
+
carry += toNumber[w]
|
|
39
|
+
// console.log(w, carry)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// include any remaining
|
|
43
|
+
if (carry !== 0) {
|
|
44
|
+
sum += carry
|
|
45
|
+
}
|
|
46
|
+
// make it all negative
|
|
47
|
+
if (minus === true) {
|
|
48
|
+
sum *= -1
|
|
49
|
+
}
|
|
50
|
+
return sum
|
|
51
|
+
}
|
|
52
|
+
export default parseNumbers
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fromText from './fromText.js'
|
|
2
|
+
|
|
3
|
+
const fromNumber = function (m) {
|
|
4
|
+
// use the raw text - normalization strips the german decimal-comma
|
|
5
|
+
let str = (m.text() || m.text('normal')).toLowerCase().trim()
|
|
6
|
+
str = str.replace(/(e|er)$/, '')
|
|
7
|
+
// get prefix/suffix
|
|
8
|
+
let arr = str.split(/([0-9.,]*)/)
|
|
9
|
+
let [prefix, num] = arr
|
|
10
|
+
let suffix = arr.slice(2).join('')
|
|
11
|
+
// german format - '.' groups thousands, ',' marks the decimal
|
|
12
|
+
num = num.replace(/[.,]$/, '')
|
|
13
|
+
let hasComma = /\d\.\d/.test(num)
|
|
14
|
+
num = num.replace(/\./g, '').replace(/,/, '.')
|
|
15
|
+
if (num !== '' && m.length < 2) {
|
|
16
|
+
num = Number(num)
|
|
17
|
+
//ensure that num is an actual number
|
|
18
|
+
if (typeof num !== 'number' || isNaN(num)) {
|
|
19
|
+
num = null
|
|
20
|
+
} else if (/-$/.test(prefix)) {
|
|
21
|
+
num = num * -1
|
|
22
|
+
}
|
|
23
|
+
// strip an ordinal off the suffix
|
|
24
|
+
if (suffix === 'e' || suffix === 'er') {
|
|
25
|
+
suffix = ''
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
hasComma,
|
|
30
|
+
prefix,
|
|
31
|
+
num,
|
|
32
|
+
suffix,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const parseNumber = function (m) {
|
|
37
|
+
let terms = m.docs[0]
|
|
38
|
+
let num = null
|
|
39
|
+
let prefix = ''
|
|
40
|
+
let suffix = ''
|
|
41
|
+
let hasComma = false
|
|
42
|
+
let isText = m.has('#TextValue')
|
|
43
|
+
if (isText) {
|
|
44
|
+
num = fromText(terms)
|
|
45
|
+
} else {
|
|
46
|
+
let res = fromNumber(m)
|
|
47
|
+
prefix = res.prefix
|
|
48
|
+
suffix = res.suffix
|
|
49
|
+
num = res.num
|
|
50
|
+
hasComma = res.hasComma
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
hasComma,
|
|
54
|
+
prefix,
|
|
55
|
+
num,
|
|
56
|
+
suffix,
|
|
57
|
+
isText,
|
|
58
|
+
isOrdinal: m.has('#Ordinal'),
|
|
59
|
+
isFraction: m.has('#Fraction'),
|
|
60
|
+
isMoney: m.has('#Money'),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export default parseNumber
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
let r = m.not('(#Adverb|#Auxiliary|#Modal)')
|
|
6
|
+
r = r.eq(0).compute('root')
|
|
7
|
+
return r.text('root')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const api = function (View) {
|
|
11
|
+
class Verbs extends View {
|
|
12
|
+
constructor(document, pointer, groups) {
|
|
13
|
+
super(document, pointer, groups)
|
|
14
|
+
this.viewType = 'Verbs'
|
|
15
|
+
}
|
|
16
|
+
conjugate(n) {
|
|
17
|
+
const methods = this.methods.two.transform.verb
|
|
18
|
+
const { toPresent, toPast, toSubjunctive1, toSubjunctive2, toImperative, toPastParticiple, toPresentParticiple } = methods
|
|
19
|
+
return getNth(this, n).map(m => {
|
|
20
|
+
let str = getRoot(m, methods)
|
|
21
|
+
return {
|
|
22
|
+
infinitive: str,
|
|
23
|
+
presentTense: toPresent(str),
|
|
24
|
+
pastTense: toPast(str),
|
|
25
|
+
subjunctive1: toSubjunctive1(str),
|
|
26
|
+
subjunctive2: toSubjunctive2(str),
|
|
27
|
+
imperative: toImperative(str),
|
|
28
|
+
pastParticiple: toPastParticiple(str),
|
|
29
|
+
presentParticiple: toPresentParticiple(str)
|
|
30
|
+
}
|
|
31
|
+
}, [])
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
View.prototype.verbs = function (n) {
|
|
36
|
+
let m = this.match('#Verb+')
|
|
37
|
+
m = getNth(m, n)
|
|
38
|
+
return new Verbs(this.document, m.pointer)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export default api
|
package/src/_lib.js
ADDED
package/src/_version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default '0.1.0'
|