aboutsummaryrefslogtreecommitdiffstats
path: root/netinstall/6/tg/content/search/stemmers/de_stemmer.js
blob: 7ff3822a45baa2eb855572a7571fb41e57a2a3f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
 * Author: Joder Illi
 *
 * Copyright (c) 2010, FormBlitz AG
 * All rights reserved.
 * Implementation of the stemming algorithm from http://snowball.tartarus.org/algorithms/german/stemmer.html
 * Copyright of the algorithm is: Copyright (c) 2001, Dr Martin Porter and can be found at http://snowball.tartarus.org/license.php
 *
 * Redistribution and use in source and binary forms, with or without modification, is covered by the standard BSD license.
 *
 */

//var stemmer = function Stemmer() {
    /*
    German includes the following accented forms,
    ä   ö   ü
    and a special letter, ß, equivalent to double s.
    The following letters are vowels:
    a   e   i   o   u   y   ä   ö   ü
    */

    var stemmer = function(word) {
        /*
        Put u and y between vowels into upper case
        */
        word = word.replace(/([aeiouyäöü])u([aeiouyäöü])/g, '$1U$2');
        word = word.replace(/([aeiouyäöü])y([aeiouyäöü])/g, '$1Y$2');

        /*
        and then do the following mappings,
        (a) replace ß with ss,
        (a) replace ae with ä,                          Not doing these, have trouble with diphtongs
        (a) replace oe with ö,                          Not doing these, have trouble with diphtongs
        (a) replace ue with ü unless preceded by q.     Not doing these, have trouble with diphtongs
        So in quelle, ue is not mapped to ü because it follows q, and in feuer it is not mapped because the first part of the rule changes it to feUer, so the u is not found.
        */
        word = word.replace(/ß/g, 'ss');
        //word = word.replace(/ae/g, 'ä');
        //word = word.replace(/oe/g, 'ö');
        //word = word.replace(/([^q])ue/g, '$1ü');

        /*
        R1 and R2 are first set up in the standard way (see the note on R1 and R2), but then R1 is adjusted so that the region before it contains at least 3 letters.
        R1 is the region after the first non-vowel following a vowel, or is the null region at the end of the word if there is no such non-vowel.
        R2 is the region after the first non-vowel following a vowel in R1, or is the null region at the end of the word if there is no such non-vowel.
        */

        var r1Index = word.search(/[aeiouyäöü][^aeiouyäöü]/);
        var r1 = '';
        if (r1Index != -1) {
            r1Index += 2;
            r1 = word.substring(r1Index);
        }

        var r2Index = -1;
        var r2 = '';

        if (r1Index != -1) {
            var r2Index = r1.search(/[aeiouyäöü][^aeiouyäöü]/);
            if (r2Index != -1) {
                r2Index += 2;
                r2 = r1.substring(r2Index);
                r2Index += r1Index;
            } else {
                r2 = '';
            }
        }

        if (r1Index != -1 && r1Index < 3) {
            r1Index = 3;
            r1 = word.substring(r1Index);
        }

        /*
        Define a valid s-ending as one of b, d, f, g, h, k, l, m, n, r or t.
        Define a valid st-ending as the same list, excluding letter r.
        */

        /*
        Do each of steps 1, 2 and 3.
        */

        /*
        Step 1:
        Search for the longest among the following suffixes,
        (a) em   ern   er
        (b) e   en   es
        (c) s (preceded by a valid s-ending)
        */
        var a1Index = word.search(/(em|ern|er)$/g);
        var b1Index = word.search(/(e|en|es)$/g);
        var c1Index = word.search(/([bdfghklmnrt]s)$/g);
        if (c1Index != -1) {
            c1Index++;
        }
        var index1 = 10000;
        var optionUsed1 = '';
        if (a1Index != -1 && a1Index < index1) {
            optionUsed1 = 'a';
            index1 = a1Index;
        }
        if (b1Index != -1 && b1Index < index1) {
            optionUsed1 = 'b';
            index1 = b1Index;
        }
        if (c1Index != -1 && c1Index < index1) {
            optionUsed1 = 'c';
            index1 = c1Index;
        }

        /*
        and delete if in R1. (Of course the letter of the valid s-ending is not necessarily in R1.) If an ending of group (b) is deleted, and the ending is preceded by niss, delete the final s.
        (For example, äckern -> äck, ackers -> acker, armes -> arm, bedürfnissen -> bedürfnis)
        */

        if (index1 != 10000 && r1Index != -1) {
            if (index1 >= r1Index) {
                word = word.substring(0, index1);
                if (optionUsed1 == 'b') {
                    if (word.search(/niss$/) != -1) {
                        word = word.substring(0, word.length -1);
                    }
                }
            }
        }
        /*
        Step 2:
        Search for the longest among the following suffixes,
        (a) en   er   est
        (b) st (preceded by a valid st-ending, itself preceded by at least 3 letters)
        */

        var a2Index = word.search(/(en|er|est)$/g);
        var b2Index = word.search(/(.{3}[bdfghklmnt]st)$/g);
        if (b2Index != -1) {
            b2Index += 4;
        }

        var index2 = 10000;
        var optionUsed2 = '';
        if (a2Index != -1 && a2Index < index2) {
            optionUsed2 = 'a';
            index2 = a2Index;
        }
        if (b2Index != -1 && b2Index < index2) {
            optionUsed2 = 'b';
            index2 = b2Index;
        }

        /*
        and delete if in R1.
        (For example, derbsten -> derbst by step 1, and derbst -> derb by step 2, since b is a valid st-ending, and is preceded by just 3 letters)
        */

        if (index2 != 10000 && r1Index != -1) {
            if (index2 >= r1Index) {
                word = word.substring(0, index2);
            }
        }

        /*
        Step 3: d-suffixes (*)
        Search for the longest among the following suffixes, and perform the action indicated.
        end   ung
            delete if in R2
            if preceded by ig, delete if in R2 and not preceded by e
        ig   ik   isch
            delete if in R2 and not preceded by e
        lich   heit
            delete if in R2
            if preceded by er or en, delete if in R1
        keit
            delete if in R2
            if preceded by lich or ig, delete if in R2
        */

        var a3Index = word.search(/(end|ung)$/g);
        var b3Index = word.search(/[^e](ig|ik|isch)$/g);
        var c3Index = word.search(/(lich|heit)$/g);
        var d3Index = word.search(/(keit)$/g);
        if (b3Index != -1) {
            b3Index ++;
        }

        var index3 = 10000;
        var optionUsed3 = '';
        if (a3Index != -1 && a3Index < index3) {
            optionUsed3 = 'a';
            index3 = a3Index;
        }
        if (b3Index != -1 && b3Index < index3) {
            optionUsed3 = 'b';
            index3 = b3Index;
        }
        if (c3Index != -1 && c3Index < index3) {
            optionUsed3 = 'c';
            index3 = c3Index;
        }
        if (d3Index != -1 && d3Index < index3) {
            optionUsed3 = 'd';
            index3 = d3Index;
        }

        if (index3 != 10000 && r2Index != -1) {
            if (index3 >= r2Index) {
                word = word.substring(0, index3);
                var optionIndex = -1;
                var optionSubsrt = '';
                if (optionUsed3 == 'a') {
                    optionIndex = word.search(/[^e](ig)$/);
                    if (optionIndex != -1) {
                        optionIndex++;
                        if (optionIndex >= r2Index) {
                            word = word.substring(0, optionIndex);
                        }
                    }
                } else if (optionUsed3 == 'c') {
                    optionIndex = word.search(/(er|en)$/);
                    if (optionIndex != -1) {
                        if (optionIndex >= r1Index) {
                            word = word.substring(0, optionIndex);
                        }
                    }
                } else if (optionUsed3 == 'd') {
                    optionIndex = word.search(/(lich|ig)$/);
                    if (optionIndex != -1) {
                        if (optionIndex >= r2Index) {
                            word = word.substring(0, optionIndex);
                        }
                    }
                }
            }
        }

        /*
        Finally,
        turn U and Y back into lower case, and remove the umlaut accent from a, o and u.
        */
        word = word.replace(/U/g, 'u');
        word = word.replace(/Y/g, 'y');
        word = word.replace(/ä/g, 'a');
        word = word.replace(/ö/g, 'o');
        word = word.replace(/ü/g, 'u');

        return word;
    };
//}