pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / analyzers / common / src / java / org / apache / lucene / analysis / hu / HungarianLightStemmer.java
1 package org.apache.lucene.analysis.hu;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 /* 
21  * This algorithm is updated based on code located at:
22  * http://members.unine.ch/jacques.savoy/clef/
23  * 
24  * Full copyright for that code follows:
25  */
26
27 /*
28  * Copyright (c) 2005, Jacques Savoy
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without 
32  * modification, are permitted provided that the following conditions are met:
33  *
34  * Redistributions of source code must retain the above copyright notice, this 
35  * list of conditions and the following disclaimer. Redistributions in binary 
36  * form must reproduce the above copyright notice, this list of conditions and
37  * the following disclaimer in the documentation and/or other materials 
38  * provided with the distribution. Neither the name of the author nor the names 
39  * of its contributors may be used to endorse or promote products derived from 
40  * this software without specific prior written permission.
41  * 
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
43  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
44  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
45  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
46  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
47  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
48  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
49  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
50  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
51  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52  * POSSIBILITY OF SUCH DAMAGE.
53  */
54
55 import static org.apache.lucene.analysis.util.StemmerUtil.*;
56
57 /**
58  * Light Stemmer for Hungarian.
59  * <p>
60  * This stemmer implements the "UniNE" algorithm in:
61  * <i>Light Stemming Approaches for the French, Portuguese, German and Hungarian Languages</i>
62  * Jacques Savoy
63  */
64 public class HungarianLightStemmer {
65   public int stem(char s[], int len) {
66     for (int i = 0; i < len; i++)
67       switch(s[i]) {
68         case 'á': s[i] = 'a'; break;
69         case 'ë':
70         case 'é': s[i] = 'e'; break;
71         case 'í': s[i] = 'i'; break;
72         case 'ó':
73         case 'ő':
74         case 'õ':
75         case 'ö': s[i] = 'o'; break;
76         case 'ú':
77         case 'ű':
78         case 'ũ':
79         case 'û':
80         case 'ü': s[i] = 'u'; break;
81       }
82     
83     len = removeCase(s, len);
84     len = removePossessive(s, len);
85     len = removePlural(s, len);
86     return normalize(s, len);
87   }
88   
89   private int removeCase(char s[], int len) {
90     if (len > 6 && endsWith(s, len, "kent"))
91       return len - 4;
92     
93     if (len > 5) {
94       if (endsWith(s, len, "nak") ||
95           endsWith(s, len, "nek") ||
96           endsWith(s, len, "val") ||
97           endsWith(s, len, "vel") ||
98           endsWith(s, len, "ert") ||
99           endsWith(s, len, "rol") ||
100           endsWith(s, len, "ban") ||
101           endsWith(s, len, "ben") ||
102           endsWith(s, len, "bol") ||
103           endsWith(s, len, "nal") ||
104           endsWith(s, len, "nel") ||
105           endsWith(s, len, "hoz") ||
106           endsWith(s, len, "hez") ||
107           endsWith(s, len, "tol"))
108         return len - 3;
109       
110       if (endsWith(s, len, "al") || endsWith(s, len, "el")) {
111         if (!isVowel(s[len-3]) && s[len-3] == s[len-4])
112           return len - 3;
113       }
114     }
115     
116     if (len > 4) {
117       if (endsWith(s, len, "at") ||
118           endsWith(s, len, "et") ||
119           endsWith(s, len, "ot") ||
120           endsWith(s, len, "va") ||
121           endsWith(s, len, "ve") ||
122           endsWith(s, len, "ra") ||
123           endsWith(s, len, "re") ||
124           endsWith(s, len, "ba") ||
125           endsWith(s, len, "be") ||
126           endsWith(s, len, "ul") ||
127           endsWith(s, len, "ig"))
128         return len - 2;
129       
130       if ((endsWith(s, len, "on") || endsWith(s, len, "en")) && !isVowel(s[len-3]))
131           return len - 2;
132       
133       switch(s[len-1]) {
134         case 't':
135         case 'n': return len - 1;
136         case 'a':
137         case 'e': if (s[len-2] == s[len-3] && !isVowel(s[len-2])) return len - 2;
138       }
139     }
140     
141     return len;
142   }
143
144   private int removePossessive(char s[], int len) {
145     if (len > 6) {
146       if (!isVowel(s[len-5]) && 
147          (endsWith(s, len, "atok") || 
148           endsWith(s, len, "otok") || 
149           endsWith(s, len, "etek")))
150         return len - 4;
151       
152       if (endsWith(s, len, "itek") || endsWith(s, len, "itok"))
153         return len - 4;
154     }
155     
156     if (len > 5) {
157       if (!isVowel(s[len-4]) &&
158         (endsWith(s, len, "unk") ||
159          endsWith(s, len, "tok") ||
160          endsWith(s, len, "tek")))
161         return len - 3;
162       
163       if (isVowel(s[len-4]) && endsWith(s, len, "juk"))
164         return len - 3;
165       
166       if (endsWith(s, len, "ink"))
167         return len - 3;
168     }
169     
170     if (len > 4) {
171       if (!isVowel(s[len-3]) &&
172          (endsWith(s, len, "am") ||
173           endsWith(s, len, "em") ||
174           endsWith(s, len, "om") ||
175           endsWith(s, len, "ad") ||
176           endsWith(s, len, "ed") ||
177           endsWith(s, len, "od") ||
178           endsWith(s, len, "uk")))
179         return len - 2;
180       
181       if (isVowel(s[len-3]) &&
182          (endsWith(s, len, "nk") ||
183           endsWith(s, len, "ja") ||
184           endsWith(s, len, "je")))
185         return len - 2;
186       
187       if (endsWith(s, len, "im") ||
188           endsWith(s, len, "id") ||
189           endsWith(s, len, "ik"))
190         return len - 2;
191     }
192     
193     if (len > 3)
194       switch(s[len-1]) {
195         case 'a':
196         case 'e': if (!isVowel(s[len-2])) return len - 1; break;
197         case 'm':
198         case 'd': if (isVowel(s[len-2])) return len - 1; break;
199         case 'i': return len - 1;
200       }
201     
202     return len;
203   }
204
205   @SuppressWarnings("fallthrough")
206   private int removePlural(char s[], int len) {
207     if (len > 3 && s[len-1] == 'k')
208       switch(s[len-2]) {
209         case 'a':
210         case 'o':
211         case 'e': if (len > 4) return len - 2; /* intentional fallthru */
212         default: return len - 1;
213       }
214     return len;
215   }
216
217   private int normalize(char s[], int len) {
218     if (len > 3)
219       switch(s[len-1]) {
220         case 'a':
221         case 'e':
222         case 'i':
223         case 'o': return len - 1;
224       }
225     return len;
226   }
227
228   private boolean isVowel(char ch) {
229     switch(ch) {
230       case 'a':
231       case 'e':
232       case 'i':
233       case 'o':
234       case 'u':
235       case 'y': return true;
236       default: return false;
237     }
238   }
239 }