~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/contrib/analyzers/common/src/java/org/apache/lucene/analysis/el/GreekStemmer.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.apache.lucene.analysis.el;
2
 
 
3
 
import org.apache.lucene.analysis.CharArraySet;
4
 
import org.apache.lucene.util.Version;
5
 
 
6
 
import java.util.Arrays;
7
 
 
8
 
/**
9
 
 * Licensed to the Apache Software Foundation (ASF) under one or more
10
 
 * contributor license agreements.  See the NOTICE file distributed with
11
 
 * this work for additional information regarding copyright ownership.
12
 
 * The ASF licenses this file to You under the Apache License, Version 2.0
13
 
 * (the "License"); you may not use this file except in compliance with
14
 
 * the License.  You may obtain a copy of the License at
15
 
 *
16
 
 *     http://www.apache.org/licenses/LICENSE-2.0
17
 
 *
18
 
 * Unless required by applicable law or agreed to in writing, software
19
 
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 
 * See the License for the specific language governing permissions and
22
 
 * limitations under the License.
23
 
 */
24
 
 
25
 
/**
26
 
 * A stemmer for Greek words, according to: <i>Development of a Stemmer for the
27
 
 * Greek Language.</i> Georgios Ntais
28
 
 * <p>
29
 
 * NOTE: Input is expected to be casefolded for Greek (including folding of final
30
 
 * sigma to sigma), and with diacritics removed. This can be achieved with 
31
 
 * either {@link GreekLowerCaseFilter} or ICUFoldingFilter.
32
 
 * @lucene.experimental
33
 
 */
34
 
public class GreekStemmer {
35
 
  public int stem(char s[], int len) {
36
 
    if (len < 4) // too short
37
 
      return len;
38
 
    
39
 
    final int origLen = len;
40
 
    // "short rules": if it hits one of these, it skips the "long list"
41
 
    len = rule0(s, len);
42
 
    len = rule1(s, len);
43
 
    len = rule2(s, len);
44
 
    len = rule3(s, len);
45
 
    len = rule4(s, len);
46
 
    len = rule5(s, len);
47
 
    len = rule6(s, len);
48
 
    len = rule7(s, len);
49
 
    len = rule8(s, len);
50
 
    len = rule9(s, len);
51
 
    len = rule10(s, len);
52
 
    len = rule11(s, len);
53
 
    len = rule12(s, len);
54
 
    len = rule13(s, len);
55
 
    len = rule14(s, len);
56
 
    len = rule15(s, len);
57
 
    len = rule16(s, len);
58
 
    len = rule17(s, len);
59
 
    len = rule18(s, len);
60
 
    len = rule19(s, len);
61
 
    len = rule20(s, len);
62
 
    // "long list"
63
 
    if (len == origLen)
64
 
      len = rule21(s, len);
65
 
    
66
 
    return rule22(s, len);
67
 
  }
68
 
 
69
 
  private int rule0(char s[], int len) {
70
 
    if (len > 9 && (endsWith(s, len, "καθεστωτοσ")
71
 
        || endsWith(s, len, "καθεστωτων")))
72
 
      return len - 4;
73
 
    
74
 
    if (len > 8 && (endsWith(s, len, "γεγονοτοσ")
75
 
        || endsWith(s, len, "γεγονοτων")))
76
 
      return len - 4;
77
 
    
78
 
    if (len > 8 && endsWith(s, len, "καθεστωτα"))
79
 
      return len - 3;
80
 
    
81
 
    if (len > 7 && (endsWith(s, len, "τατογιου")
82
 
        || endsWith(s, len, "τατογιων")))
83
 
      return len - 4;
84
 
    
85
 
    if (len > 7 && endsWith(s, len, "γεγονοτα"))
86
 
      return len - 3;
87
 
    
88
 
    if (len > 7 && endsWith(s, len, "καθεστωσ"))
89
 
      return len - 2;
90
 
    
91
 
    if (len > 6 && (endsWith(s, len, "σκαγιου"))
92
 
        || endsWith(s, len, "σκαγιων")
93
 
        || endsWith(s, len, "ολογιου")
94
 
        || endsWith(s, len, "ολογιων")
95
 
        || endsWith(s, len, "κρεατοσ")
96
 
        || endsWith(s, len, "κρεατων")
97
 
        || endsWith(s, len, "περατοσ")
98
 
        || endsWith(s, len, "περατων")
99
 
        || endsWith(s, len, "τερατοσ")
100
 
        || endsWith(s, len, "τερατων"))
101
 
      return len - 4;
102
 
    
103
 
    if (len > 6 && endsWith(s, len, "τατογια"))
104
 
      return len - 3;
105
 
    
106
 
    if (len > 6 && endsWith(s, len, "γεγονοσ"))
107
 
      return len - 2;
108
 
    
109
 
    if (len > 5 && (endsWith(s, len, "φαγιου")
110
 
        || endsWith(s, len, "φαγιων")
111
 
        || endsWith(s, len, "σογιου")
112
 
        || endsWith(s, len, "σογιων")))
113
 
      return len - 4;
114
 
    
115
 
    if (len > 5 && (endsWith(s, len, "σκαγια")
116
 
        || endsWith(s, len, "ολογια")
117
 
        || endsWith(s, len, "κρεατα")
118
 
        || endsWith(s, len, "περατα")
119
 
        || endsWith(s, len, "τερατα")))
120
 
      return len - 3;
121
 
    
122
 
    if (len > 4 && (endsWith(s, len, "φαγια")
123
 
        || endsWith(s, len, "σογια")
124
 
        || endsWith(s, len, "φωτοσ")
125
 
        || endsWith(s, len, "φωτων")))
126
 
      return len - 3;
127
 
    
128
 
    if (len > 4 && (endsWith(s, len, "κρεασ")
129
 
        || endsWith(s, len, "περασ")
130
 
        || endsWith(s, len, "τερασ")))
131
 
      return len - 2;
132
 
    
133
 
    if (len > 3 && endsWith(s, len, "φωτα"))
134
 
      return len - 2;
135
 
    
136
 
    if (len > 2 && endsWith(s, len, "φωσ"))
137
 
      return len - 1;
138
 
    
139
 
    return len;
140
 
  }
141
 
 
142
 
  private int rule1(char s[], int len) {
143
 
    if (len > 4 && (endsWith(s, len, "αδεσ") || endsWith(s, len, "αδων"))) {
144
 
      len -= 4;
145
 
      if (!(endsWith(s, len, "οκ") ||
146
 
          endsWith(s, len, "μαμ") ||
147
 
          endsWith(s, len, "μαν") ||
148
 
          endsWith(s, len, "μπαμπ") ||
149
 
          endsWith(s, len, "πατερ") ||
150
 
          endsWith(s, len, "γιαγι") ||
151
 
          endsWith(s, len, "νταντ") ||
152
 
          endsWith(s, len, "κυρ") ||
153
 
          endsWith(s, len, "θει") ||
154
 
          endsWith(s, len, "πεθερ")))
155
 
        len += 2; // add back -αδ
156
 
    }
157
 
    return len;
158
 
  }
159
 
  
160
 
  private int rule2(char s[], int len) {
161
 
    if (len > 4 && (endsWith(s, len, "εδεσ") || endsWith(s, len, "εδων"))) {
162
 
      len -= 4;
163
 
      if (endsWith(s, len, "οπ") ||
164
 
          endsWith(s, len, "ιπ") ||
165
 
          endsWith(s, len, "εμπ") ||
166
 
          endsWith(s, len, "υπ") ||
167
 
          endsWith(s, len, "γηπ") ||
168
 
          endsWith(s, len, "δαπ") ||
169
 
          endsWith(s, len, "κρασπ") ||
170
 
          endsWith(s, len, "μιλ"))
171
 
        len += 2; // add back -εδ
172
 
    }
173
 
    return len;
174
 
  }
175
 
  
176
 
  private int rule3(char s[], int len) {
177
 
    if (len > 5 && (endsWith(s, len, "ουδεσ") || endsWith(s, len, "ουδων"))) {
178
 
      len -= 5;
179
 
      if (endsWith(s, len, "αρκ") ||
180
 
          endsWith(s, len, "καλιακ") ||
181
 
          endsWith(s, len, "πεταλ") ||
182
 
          endsWith(s, len, "λιχ") ||
183
 
          endsWith(s, len, "πλεξ") ||
184
 
          endsWith(s, len, "σκ") ||
185
 
          endsWith(s, len, "σ") ||
186
 
          endsWith(s, len, "φλ") ||
187
 
          endsWith(s, len, "φρ") ||
188
 
          endsWith(s, len, "βελ") ||
189
 
          endsWith(s, len, "λουλ") ||
190
 
          endsWith(s, len, "χν") ||
191
 
          endsWith(s, len, "σπ") ||
192
 
          endsWith(s, len, "τραγ") ||
193
 
          endsWith(s, len, "φε"))
194
 
        len += 3; // add back -ουδ
195
 
    }
196
 
    return len;
197
 
  }
198
 
  
199
 
  private static final CharArraySet exc4 = new CharArraySet(Version.LUCENE_31,
200
 
      Arrays.asList("θ", "δ", "ελ", "γαλ", "ν", "π", "ιδ", "παρ"),
201
 
      false);
202
 
  
203
 
  private int rule4(char s[], int len) {   
204
 
    if (len > 3 && (endsWith(s, len, "εωσ") || endsWith(s, len, "εων"))) {
205
 
      len -= 3;
206
 
      if (exc4.contains(s, 0, len))
207
 
        len++; // add back -ε
208
 
    }
209
 
    return len;
210
 
  }
211
 
  
212
 
  private int rule5(char s[], int len) {
213
 
    if (len > 2 && endsWith(s, len, "ια")) {
214
 
      len -= 2;
215
 
      if (endsWithVowel(s, len))
216
 
        len++; // add back -ι
217
 
    } else if (len > 3 && (endsWith(s, len, "ιου") || endsWith(s, len, "ιων"))) {
218
 
      len -= 3;
219
 
      if (endsWithVowel(s, len))
220
 
        len++; // add back -ι
221
 
    }
222
 
    return len;
223
 
  }
224
 
 
225
 
  private static final CharArraySet exc6 = new CharArraySet(Version.LUCENE_31,
226
 
      Arrays.asList("αλ", "αδ", "ενδ", "αμαν", "αμμοχαλ", "ηθ", "ανηθ",
227
 
          "αντιδ", "φυσ", "βρωμ", "γερ", "εξωδ", "καλπ", "καλλιν", "καταδ",
228
 
          "μουλ", "μπαν", "μπαγιατ", "μπολ", "μποσ", "νιτ", "ξικ", "συνομηλ",
229
 
          "πετσ", "πιτσ", "πικαντ", "πλιατσ", "ποστελν", "πρωτοδ", "σερτ",
230
 
          "συναδ", "τσαμ", "υποδ", "φιλον", "φυλοδ", "χασ"), 
231
 
       false);
232
 
 
233
 
  private int rule6(char s[], int len) {
234
 
    boolean removed = false;
235
 
    if (len > 3 && (endsWith(s, len, "ικα") || endsWith(s, len, "ικο"))) {
236
 
      len -= 3;
237
 
      removed = true;
238
 
    } else if (len > 4 && (endsWith(s, len, "ικου") || endsWith(s, len, "ικων"))) {
239
 
      len -= 4;
240
 
      removed = true;
241
 
    }
242
 
    
243
 
    if (removed) {
244
 
      if (endsWithVowel(s, len) || exc6.contains(s, 0, len))
245
 
        len += 2; // add back -ικ
246
 
    }
247
 
    return len;
248
 
  }
249
 
  
250
 
  private static final CharArraySet exc7 = new CharArraySet(Version.LUCENE_31,
251
 
      Arrays.asList("αναπ", "αποθ", "αποκ", "αποστ", "βουβ", "ξεθ", "ουλ",
252
 
          "πεθ", "πικρ", "ποτ", "σιχ", "χ"), 
253
 
      false);
254
 
  
255
 
  private int rule7(char s[], int len) {
256
 
    if (len == 5 && endsWith(s, len, "αγαμε"))
257
 
      return len - 1;
258
 
    
259
 
    if (len > 7 && endsWith(s, len, "ηθηκαμε"))
260
 
      len -= 7;
261
 
    else if (len > 6 && endsWith(s, len, "ουσαμε"))
262
 
      len -= 6;
263
 
    else if (len > 5 && (endsWith(s, len, "αγαμε") ||
264
 
             endsWith(s, len, "ησαμε") ||
265
 
             endsWith(s, len, "ηκαμε")))
266
 
      len -= 5;
267
 
    
268
 
    if (len > 3 && endsWith(s, len, "αμε")) {
269
 
      len -= 3;
270
 
      if (exc7.contains(s, 0, len))
271
 
        len += 2; // add back -αμ
272
 
    }
273
 
 
274
 
    return len;
275
 
  }
276
 
 
277
 
  private static final CharArraySet exc8a = new CharArraySet(Version.LUCENE_31,
278
 
      Arrays.asList("τρ", "τσ"),
279
 
      false);
280
 
 
281
 
  private static final CharArraySet exc8b = new CharArraySet(Version.LUCENE_31,
282
 
      Arrays.asList("βετερ", "βουλκ", "βραχμ", "γ", "δραδουμ", "θ", "καλπουζ",
283
 
          "καστελ", "κορμορ", "λαοπλ", "μωαμεθ", "μ", "μουσουλμ", "ν", "ουλ",
284
 
          "π", "πελεκ", "πλ", "πολισ", "πορτολ", "σαρακατσ", "σουλτ",
285
 
          "τσαρλατ", "ορφ", "τσιγγ", "τσοπ", "φωτοστεφ", "χ", "ψυχοπλ", "αγ",
286
 
          "ορφ", "γαλ", "γερ", "δεκ", "διπλ", "αμερικαν", "ουρ", "πιθ",
287
 
          "πουριτ", "σ", "ζωντ", "ικ", "καστ", "κοπ", "λιχ", "λουθηρ", "μαιντ",
288
 
          "μελ", "σιγ", "σπ", "στεγ", "τραγ", "τσαγ", "φ", "ερ", "αδαπ",
289
 
          "αθιγγ", "αμηχ", "ανικ", "ανοργ", "απηγ", "απιθ", "ατσιγγ", "βασ",
290
 
          "βασκ", "βαθυγαλ", "βιομηχ", "βραχυκ", "διατ", "διαφ", "ενοργ",
291
 
          "θυσ", "καπνοβιομηχ", "καταγαλ", "κλιβ", "κοιλαρφ", "λιβ",
292
 
          "μεγλοβιομηχ", "μικροβιομηχ", "νταβ", "ξηροκλιβ", "ολιγοδαμ",
293
 
          "ολογαλ", "πενταρφ", "περηφ", "περιτρ", "πλατ", "πολυδαπ", "πολυμηχ",
294
 
          "στεφ", "ταβ", "τετ", "υπερηφ", "υποκοπ", "χαμηλοδαπ", "ψηλοταβ"),
295
 
      false);
296
 
  
297
 
  private int rule8(char s[], int len) {
298
 
    boolean removed = false;
299
 
    
300
 
    if (len > 8 && endsWith(s, len, "ιουντανε")) {
301
 
      len -= 8;
302
 
      removed = true;
303
 
    } else if (len > 7 && endsWith(s, len, "ιοντανε") ||
304
 
        endsWith(s, len, "ουντανε") ||
305
 
        endsWith(s, len, "ηθηκανε")) {
306
 
      len -= 7;
307
 
      removed = true;
308
 
    } else if (len > 6 && endsWith(s, len, "ιοτανε") ||
309
 
        endsWith(s, len, "οντανε") ||
310
 
        endsWith(s, len, "ουσανε")) {
311
 
      len -= 6;
312
 
      removed = true;
313
 
    } else if (len > 5 && endsWith(s, len, "αγανε") ||
314
 
        endsWith(s, len, "ησανε") ||
315
 
        endsWith(s, len, "οτανε") ||
316
 
        endsWith(s, len, "ηκανε")) {
317
 
      len -= 5;
318
 
      removed = true;
319
 
    }
320
 
    
321
 
    if (removed && exc8a.contains(s, 0, len)) {
322
 
      // add -αγαν (we removed > 4 chars so its safe)
323
 
      len += 4;
324
 
      s[len - 4] = 'α';
325
 
      s[len - 3] = 'γ';
326
 
      s[len - 2] = 'α';
327
 
      s[len - 1] = 'ν';
328
 
    }
329
 
    
330
 
    if (len > 3 && endsWith(s, len, "ανε")) {
331
 
      len -= 3;
332
 
      if (endsWithVowelNoY(s, len) || exc8b.contains(s, 0, len)) {
333
 
        len += 2; // add back -αν
334
 
      }
335
 
    }
336
 
    
337
 
    return len;
338
 
  }
339
 
  
340
 
  private static final CharArraySet exc9 = new CharArraySet(Version.LUCENE_31,
341
 
      Arrays.asList("αβαρ", "βεν", "εναρ", "αβρ", "αδ", "αθ", "αν", "απλ",
342
 
          "βαρον", "ντρ", "σκ", "κοπ", "μπορ", "νιφ", "παγ", "παρακαλ", "σερπ",
343
 
          "σκελ", "συρφ", "τοκ", "υ", "δ", "εμ", "θαρρ", "θ"), 
344
 
      false);
345
 
  
346
 
  private int rule9(char s[], int len) {
347
 
    if (len > 5 && endsWith(s, len, "ησετε"))
348
 
      len -= 5;
349
 
    
350
 
    if (len > 3 && endsWith(s, len, "ετε")) {
351
 
      len -= 3;
352
 
      if (exc9.contains(s, 0, len) ||
353
 
          endsWithVowelNoY(s, len) ||
354
 
          endsWith(s, len, "οδ") ||
355
 
          endsWith(s, len, "αιρ") ||
356
 
          endsWith(s, len, "φορ") ||
357
 
          endsWith(s, len, "ταθ") ||
358
 
          endsWith(s, len, "διαθ") ||
359
 
          endsWith(s, len, "σχ") ||
360
 
          endsWith(s, len, "ενδ") ||
361
 
          endsWith(s, len, "ευρ") ||
362
 
          endsWith(s, len, "τιθ") ||
363
 
          endsWith(s, len, "υπερθ") ||
364
 
          endsWith(s, len, "ραθ") ||
365
 
          endsWith(s, len, "ενθ") ||
366
 
          endsWith(s, len, "ροθ") ||
367
 
          endsWith(s, len, "σθ") ||
368
 
          endsWith(s, len, "πυρ") ||
369
 
          endsWith(s, len, "αιν") ||
370
 
          endsWith(s, len, "συνδ") ||
371
 
          endsWith(s, len, "συν") ||
372
 
          endsWith(s, len, "συνθ") ||
373
 
          endsWith(s, len, "χωρ") ||
374
 
          endsWith(s, len, "πον") ||
375
 
          endsWith(s, len, "βρ") ||
376
 
          endsWith(s, len, "καθ") ||
377
 
          endsWith(s, len, "ευθ") ||
378
 
          endsWith(s, len, "εκθ") ||
379
 
          endsWith(s, len, "νετ") ||
380
 
          endsWith(s, len, "ρον") ||
381
 
          endsWith(s, len, "αρκ") ||
382
 
          endsWith(s, len, "βαρ") ||
383
 
          endsWith(s, len, "βολ") ||
384
 
          endsWith(s, len, "ωφελ")) {
385
 
        len += 2; // add back -ετ
386
 
      }
387
 
    }
388
 
    
389
 
    return len;
390
 
  }
391
 
 
392
 
  private int rule10(char s[], int len) {
393
 
    if (len > 5 && (endsWith(s, len, "οντασ") || endsWith(s, len, "ωντασ"))) {
394
 
      len -= 5;
395
 
      if (len == 3 && endsWith(s, len, "αρχ")) {
396
 
        len += 3; // add back *ντ
397
 
        s[len - 3] = 'ο';
398
 
      }
399
 
      if (endsWith(s, len, "κρε")) {
400
 
        len += 3; // add back *ντ
401
 
        s[len - 3] = 'ω';
402
 
      }
403
 
    }
404
 
    
405
 
    return len;
406
 
  }
407
 
  
408
 
  private int rule11(char s[], int len) {
409
 
    if (len > 6 && endsWith(s, len, "ομαστε")) {
410
 
      len -= 6;
411
 
      if (len == 2 && endsWith(s, len, "ον")) {
412
 
        len += 5; // add back -ομαστ
413
 
      }
414
 
    } else if (len > 7 && endsWith(s, len, "ιομαστε")) {
415
 
      len -= 7;
416
 
      if (len == 2 && endsWith(s, len, "ον")) {
417
 
        len += 5;
418
 
        s[len - 5] = 'ο';
419
 
        s[len - 4] = 'μ';
420
 
        s[len - 3] = 'α';
421
 
        s[len - 2] = 'σ';
422
 
        s[len - 1] = 'τ';
423
 
      }
424
 
    }
425
 
    return len;
426
 
  }
427
 
 
428
 
  private static final CharArraySet exc12a = new CharArraySet(Version.LUCENE_31,
429
 
      Arrays.asList("π", "απ", "συμπ", "ασυμπ", "ακαταπ", "αμεταμφ"),
430
 
      false);
431
 
 
432
 
  private static final CharArraySet exc12b = new CharArraySet(Version.LUCENE_31,
433
 
      Arrays.asList("αλ", "αρ", "εκτελ", "ζ", "μ", "ξ", "παρακαλ", "αρ", "προ", "νισ"),
434
 
      false);
435
 
  
436
 
  private int rule12(char s[], int len) {
437
 
    if (len > 5 && endsWith(s, len, "ιεστε")) {
438
 
      len -= 5;
439
 
      if (exc12a.contains(s, 0, len))   
440
 
        len += 4; // add back -ιεστ
441
 
    }
442
 
    
443
 
    if (len > 4 && endsWith(s, len, "εστε")) {
444
 
      len -= 4;
445
 
      if (exc12b.contains(s, 0, len))
446
 
        len += 3; // add back -εστ
447
 
    }
448
 
    
449
 
    return len;
450
 
  }
451
 
  
452
 
  private static final CharArraySet exc13 = new CharArraySet(Version.LUCENE_31,
453
 
      Arrays.asList("διαθ", "θ", "παρακαταθ", "προσθ", "συνθ"),
454
 
      false);
455
 
  
456
 
  private int rule13(char s[], int len) {
457
 
    if (len > 6 && endsWith(s, len, "ηθηκεσ")) {
458
 
      len -= 6;
459
 
    } else if (len > 5 && (endsWith(s, len, "ηθηκα") || endsWith(s, len, "ηθηκε"))) {
460
 
      len -= 5;
461
 
    }
462
 
    
463
 
    boolean removed = false;
464
 
    
465
 
    if (len > 4 && endsWith(s, len, "ηκεσ")) {
466
 
      len -= 4;
467
 
      removed = true;
468
 
    } else if (len > 3 && (endsWith(s, len, "ηκα") || endsWith(s, len, "ηκε"))) {
469
 
      len -= 3;
470
 
      removed = true;
471
 
    }
472
 
 
473
 
    if (removed && (exc13.contains(s, 0, len) 
474
 
        || endsWith(s, len, "σκωλ")
475
 
        || endsWith(s, len, "σκουλ")
476
 
        || endsWith(s, len, "ναρθ")
477
 
        || endsWith(s, len, "σφ")
478
 
        || endsWith(s, len, "οθ")
479
 
        || endsWith(s, len, "πιθ"))) { 
480
 
      len += 2; // add back the -ηκ
481
 
    }
482
 
    
483
 
    return len;
484
 
  }
485
 
  
486
 
  private static final CharArraySet exc14 = new CharArraySet(Version.LUCENE_31,
487
 
      Arrays.asList("φαρμακ", "χαδ", "αγκ", "αναρρ", "βρομ", "εκλιπ", "λαμπιδ",
488
 
          "λεχ", "μ", "πατ", "ρ", "λ", "μεδ", "μεσαζ", "υποτειν", "αμ", "αιθ",
489
 
          "ανηκ", "δεσποζ", "ενδιαφερ", "δε", "δευτερευ", "καθαρευ", "πλε",
490
 
          "τσα"), 
491
 
      false);
492
 
 
493
 
  private int rule14(char s[], int len) {
494
 
    boolean removed = false;
495
 
    
496
 
    if (len > 5 && endsWith(s, len, "ουσεσ")) {
497
 
      len -= 5;
498
 
      removed = true;
499
 
    } else if (len > 4 && (endsWith(s, len, "ουσα") || endsWith(s, len, "ουσε"))) {
500
 
      len -= 4;
501
 
      removed = true;
502
 
    }
503
 
    
504
 
    if (removed && (exc14.contains(s, 0, len) 
505
 
        || endsWithVowel(s, len)
506
 
        || endsWith(s, len, "ποδαρ")
507
 
        || endsWith(s, len, "βλεπ")
508
 
        || endsWith(s, len, "πανταχ")
509
 
        || endsWith(s, len, "φρυδ") 
510
 
        || endsWith(s, len, "μαντιλ")
511
 
        || endsWith(s, len, "μαλλ")
512
 
        || endsWith(s, len, "κυματ")
513
 
        || endsWith(s, len, "λαχ")
514
 
        || endsWith(s, len, "ληγ")
515
 
        || endsWith(s, len, "φαγ")
516
 
        || endsWith(s, len, "ομ")
517
 
        || endsWith(s, len, "πρωτ"))) {
518
 
      len += 3; // add back -ουσ
519
 
    }
520
 
 
521
 
   return len;
522
 
  }
523
 
  
524
 
  private static final CharArraySet exc15a = new CharArraySet(Version.LUCENE_31,
525
 
      Arrays.asList("αβαστ", "πολυφ", "αδηφ", "παμφ", "ρ", "ασπ", "αφ", "αμαλ",
526
 
          "αμαλλι", "ανυστ", "απερ", "ασπαρ", "αχαρ", "δερβεν", "δροσοπ",
527
 
          "ξεφ", "νεοπ", "νομοτ", "ολοπ", "ομοτ", "προστ", "προσωποπ", "συμπ",
528
 
          "συντ", "τ", "υποτ", "χαρ", "αειπ", "αιμοστ", "ανυπ", "αποτ",
529
 
          "αρτιπ", "διατ", "εν", "επιτ", "κροκαλοπ", "σιδηροπ", "λ", "ναυ",
530
 
          "ουλαμ", "ουρ", "π", "τρ", "μ"), 
531
 
      false);
532
 
  
533
 
  private static final CharArraySet exc15b = new CharArraySet(Version.LUCENE_31,
534
 
      Arrays.asList("ψοφ", "ναυλοχ"),
535
 
      false);
536
 
  
537
 
  private int rule15(char s[], int len) {
538
 
    boolean removed = false;
539
 
    if (len > 4 && endsWith(s, len, "αγεσ")) {
540
 
      len -= 4;
541
 
      removed = true;
542
 
    } else if (len > 3 && (endsWith(s, len, "αγα") || endsWith(s, len, "αγε"))) {
543
 
      len -= 3;
544
 
      removed = true;
545
 
    }
546
 
    
547
 
    if (removed) {
548
 
      final boolean cond1 = exc15a.contains(s, 0, len) 
549
 
        || endsWith(s, len, "οφ")
550
 
        || endsWith(s, len, "πελ")
551
 
        || endsWith(s, len, "χορτ")
552
 
        || endsWith(s, len, "λλ")
553
 
        || endsWith(s, len, "σφ")
554
 
        || endsWith(s, len, "ρπ")
555
 
        || endsWith(s, len, "φρ")
556
 
        || endsWith(s, len, "πρ")
557
 
        || endsWith(s, len, "λοχ")
558
 
        || endsWith(s, len, "σμην");
559
 
      
560
 
      final boolean cond2 = exc15b.contains(s, 0, len)
561
 
        || endsWith(s, len, "κολλ");
562
 
      
563
 
      if (cond1 && !cond2)
564
 
        len += 2; // add back -αγ  
565
 
    }
566
 
    
567
 
    return len;
568
 
  }
569
 
  
570
 
  private static final CharArraySet exc16 = new CharArraySet(Version.LUCENE_31,
571
 
      Arrays.asList("ν", "χερσον", "δωδεκαν", "ερημον", "μεγαλον", "επταν"),
572
 
      false);
573
 
  
574
 
  private int rule16(char s[], int len) {
575
 
    boolean removed = false;
576
 
    if (len > 4 && endsWith(s, len, "ησου")) {
577
 
      len -= 4;
578
 
      removed = true;
579
 
    } else if (len > 3 && (endsWith(s, len, "ησε") || endsWith(s, len, "ησα"))) {
580
 
      len -= 3;
581
 
      removed = true;
582
 
    }
583
 
    
584
 
    if (removed && exc16.contains(s, 0, len))
585
 
      len += 2; // add back -ησ
586
 
    
587
 
    return len;
588
 
  }
589
 
  
590
 
  private static final CharArraySet exc17 = new CharArraySet(Version.LUCENE_31,
591
 
      Arrays.asList("ασβ", "σβ", "αχρ", "χρ", "απλ", "αειμν", "δυσχρ", "ευχρ", "κοινοχρ", "παλιμψ"),
592
 
      false);
593
 
  
594
 
  private int rule17(char s[], int len) {
595
 
    if (len > 4 && endsWith(s, len, "ηστε")) {
596
 
      len -= 4;
597
 
      if (exc17.contains(s, 0, len))
598
 
        len += 3; // add back the -ηστ
599
 
    }
600
 
    
601
 
    return len;
602
 
  }
603
 
  
604
 
  private static final CharArraySet exc18 = new CharArraySet(Version.LUCENE_31,
605
 
      Arrays.asList("ν", "ρ", "σπι", "στραβομουτσ", "κακομουτσ", "εξων"),
606
 
      false);
607
 
  
608
 
  private int rule18(char s[], int len) {
609
 
    boolean removed = false;
610
 
    
611
 
    if (len > 6 && (endsWith(s, len, "ησουνε") || endsWith(s, len, "ηθουνε"))) {
612
 
      len -= 6;
613
 
      removed = true;
614
 
    } else if (len > 4 && endsWith(s, len, "ουνε")) {
615
 
      len -= 4;
616
 
      removed = true;
617
 
    }
618
 
    
619
 
    if (removed && exc18.contains(s, 0, len)) {
620
 
      len += 3;
621
 
      s[len - 3] = 'ο';
622
 
      s[len - 2] = 'υ';
623
 
      s[len - 1] = 'ν';
624
 
    }
625
 
    return len;
626
 
  }
627
 
  
628
 
  private static final CharArraySet exc19 = new CharArraySet(Version.LUCENE_31,
629
 
      Arrays.asList("παρασουσ", "φ", "χ", "ωριοπλ", "αζ", "αλλοσουσ", "ασουσ"),
630
 
      false);
631
 
  
632
 
  private int rule19(char s[], int len) {
633
 
    boolean removed = false;
634
 
    
635
 
    if (len > 6 && (endsWith(s, len, "ησουμε") || endsWith(s, len, "ηθουμε"))) {
636
 
      len -= 6;
637
 
      removed = true;
638
 
    } else if (len > 4 && endsWith(s, len, "ουμε")) {
639
 
      len -= 4;
640
 
      removed = true;
641
 
    }
642
 
    
643
 
    if (removed && exc19.contains(s, 0, len)) {
644
 
      len += 3;
645
 
      s[len - 3] = 'ο';
646
 
      s[len - 2] = 'υ';
647
 
      s[len - 1] = 'μ';
648
 
    }
649
 
    return len;
650
 
  }
651
 
  
652
 
  private int rule20(char s[], int len) {
653
 
    if (len > 5 && (endsWith(s, len, "ματων") || endsWith(s, len, "ματοσ")))
654
 
      len -= 3;
655
 
    else if (len > 4 && endsWith(s, len, "ματα"))
656
 
      len -= 2;
657
 
    return len;
658
 
  }
659
 
 
660
 
  private int rule21(char s[], int len) {
661
 
    if (len > 9 && endsWith(s, len, "ιοντουσαν"))
662
 
      return len - 9;
663
 
    
664
 
    if (len > 8 && (endsWith(s, len, "ιομασταν") ||
665
 
        endsWith(s, len, "ιοσασταν") ||
666
 
        endsWith(s, len, "ιουμαστε") ||
667
 
        endsWith(s, len, "οντουσαν")))
668
 
      return len - 8;
669
 
    
670
 
    if (len > 7 && (endsWith(s, len, "ιεμαστε") ||
671
 
        endsWith(s, len, "ιεσαστε") ||
672
 
        endsWith(s, len, "ιομουνα") ||
673
 
        endsWith(s, len, "ιοσαστε") ||
674
 
        endsWith(s, len, "ιοσουνα") ||
675
 
        endsWith(s, len, "ιουνται") ||
676
 
        endsWith(s, len, "ιουνταν") ||
677
 
        endsWith(s, len, "ηθηκατε") ||
678
 
        endsWith(s, len, "ομασταν") ||
679
 
        endsWith(s, len, "οσασταν") ||
680
 
        endsWith(s, len, "ουμαστε")))
681
 
      return len - 7;
682
 
    
683
 
    if (len > 6 && (endsWith(s, len, "ιομουν") ||
684
 
        endsWith(s, len, "ιονταν") ||
685
 
        endsWith(s, len, "ιοσουν") ||
686
 
        endsWith(s, len, "ηθειτε") ||
687
 
        endsWith(s, len, "ηθηκαν") ||
688
 
        endsWith(s, len, "ομουνα") ||
689
 
        endsWith(s, len, "οσαστε") ||
690
 
        endsWith(s, len, "οσουνα") ||
691
 
        endsWith(s, len, "ουνται") ||
692
 
        endsWith(s, len, "ουνταν") ||
693
 
        endsWith(s, len, "ουσατε")))
694
 
      return len - 6;
695
 
    
696
 
    if (len > 5 && (endsWith(s, len, "αγατε") ||
697
 
        endsWith(s, len, "ιεμαι") ||
698
 
        endsWith(s, len, "ιεται") ||
699
 
        endsWith(s, len, "ιεσαι") ||
700
 
        endsWith(s, len, "ιοταν") ||
701
 
        endsWith(s, len, "ιουμα") ||
702
 
        endsWith(s, len, "ηθεισ") ||
703
 
        endsWith(s, len, "ηθουν") ||
704
 
        endsWith(s, len, "ηκατε") ||
705
 
        endsWith(s, len, "ησατε") ||
706
 
        endsWith(s, len, "ησουν") ||
707
 
        endsWith(s, len, "ομουν") ||
708
 
        endsWith(s, len, "ονται") ||
709
 
        endsWith(s, len, "ονταν") ||
710
 
        endsWith(s, len, "οσουν") ||
711
 
        endsWith(s, len, "ουμαι") ||
712
 
        endsWith(s, len, "ουσαν")))
713
 
      return len - 5;
714
 
    
715
 
    if (len > 4 && (endsWith(s, len, "αγαν") ||
716
 
        endsWith(s, len, "αμαι") ||
717
 
        endsWith(s, len, "ασαι") ||
718
 
        endsWith(s, len, "αται") ||
719
 
        endsWith(s, len, "ειτε") ||
720
 
        endsWith(s, len, "εσαι") ||
721
 
        endsWith(s, len, "εται") ||
722
 
        endsWith(s, len, "ηδεσ") ||
723
 
        endsWith(s, len, "ηδων") ||
724
 
        endsWith(s, len, "ηθει") ||
725
 
        endsWith(s, len, "ηκαν") ||
726
 
        endsWith(s, len, "ησαν") ||
727
 
        endsWith(s, len, "ησει") ||
728
 
        endsWith(s, len, "ησεσ") ||
729
 
        endsWith(s, len, "ομαι") ||
730
 
        endsWith(s, len, "οταν")))
731
 
      return len - 4;
732
 
    
733
 
    if (len > 3 && (endsWith(s, len, "αει") ||
734
 
        endsWith(s, len, "εισ") ||
735
 
        endsWith(s, len, "ηθω") ||
736
 
        endsWith(s, len, "ησω") ||
737
 
        endsWith(s, len, "ουν") ||
738
 
        endsWith(s, len, "ουσ")))
739
 
      return len - 3;
740
 
    
741
 
    if (len > 2 && (endsWith(s, len, "αν") ||
742
 
        endsWith(s, len, "ασ") ||
743
 
        endsWith(s, len, "αω") ||
744
 
        endsWith(s, len, "ει") ||
745
 
        endsWith(s, len, "εσ") ||
746
 
        endsWith(s, len, "ησ") ||
747
 
        endsWith(s, len, "οι") ||
748
 
        endsWith(s, len, "οσ") ||
749
 
        endsWith(s, len, "ου") ||
750
 
        endsWith(s, len, "υσ") ||
751
 
        endsWith(s, len, "ων")))
752
 
      return len - 2;
753
 
    
754
 
    if (len > 1 && endsWithVowel(s, len))
755
 
      return len - 1;
756
 
 
757
 
    return len;
758
 
  }
759
 
  
760
 
  private int rule22(char s[], int len) {
761
 
    if (endsWith(s, len, "εστερ") ||
762
 
        endsWith(s, len, "εστατ"))
763
 
      return len - 5;
764
 
    
765
 
    if (endsWith(s, len, "οτερ") ||
766
 
        endsWith(s, len, "οτατ") ||
767
 
        endsWith(s, len, "υτερ") ||
768
 
        endsWith(s, len, "υτατ") ||
769
 
        endsWith(s, len, "ωτερ") ||
770
 
        endsWith(s, len, "ωτατ"))
771
 
      return len - 4;
772
 
 
773
 
    return len;
774
 
  }
775
 
 
776
 
  private boolean endsWith(char s[], int len, String suffix) {
777
 
    final int suffixLen = suffix.length();
778
 
    if (suffixLen > len)
779
 
      return false;
780
 
    for (int i = suffixLen - 1; i >= 0; i--)
781
 
      if (s[len -(suffixLen - i)] != suffix.charAt(i))
782
 
        return false;
783
 
    
784
 
    return true;
785
 
  }
786
 
  
787
 
  private boolean endsWithVowel(char s[], int len) {
788
 
    if (len == 0)
789
 
      return false;
790
 
    switch(s[len - 1]) {
791
 
      case 'α':
792
 
      case 'ε':
793
 
      case 'η':
794
 
      case 'ι':
795
 
      case 'ο':
796
 
      case 'υ':
797
 
      case 'ω':
798
 
        return true;
799
 
      default:
800
 
        return false;
801
 
    }
802
 
  }
803
 
  
804
 
  private boolean endsWithVowelNoY(char s[], int len) {
805
 
    if (len == 0)
806
 
      return false;
807
 
    switch(s[len - 1]) {
808
 
      case 'α':
809
 
      case 'ε':
810
 
      case 'η':
811
 
      case 'ι':
812
 
      case 'ο':
813
 
      case 'ω':
814
 
        return true;
815
 
      default:
816
 
        return false;
817
 
    }
818
 
  }
819
 
}