add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / analyzers / common / src / java / org / apache / lucene / analysis / br / BrazilianStemmer.java
1 package org.apache.lucene.analysis.br;
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  * A stemmer for Brazilian Portuguese words.
22  */
23 public class BrazilianStemmer {
24
25         /**
26          * Changed term
27          */
28         private   String TERM ;
29         private   String CT ;
30         private   String R1 ;
31         private   String R2 ;
32         private   String RV ;
33
34
35         public BrazilianStemmer() {
36         }
37
38         /**
39          * Stems the given term to an unique <tt>discriminator</tt>.
40          *
41          * @param term  The term that should be stemmed.
42          * @return      Discriminator for <tt>term</tt>
43          */
44         protected String stem( String term ) {
45     boolean altered = false ; // altered the term
46
47     // creates CT
48     createCT(term) ;
49
50                 if ( !isIndexable( CT ) ) {
51                         return null;
52                 }
53                 if ( !isStemmable( CT ) ) {
54                         return CT ;
55                 }
56
57     R1 = getR1(CT) ;
58     R2 = getR1(R1) ;
59     RV = getRV(CT) ;
60     TERM = term + ";" +CT ;
61
62     altered = step1() ;
63     if (!altered) {
64       altered = step2() ;
65     }
66
67     if (altered) {
68       step3();
69     } else {
70       step4();
71     }
72
73     step5() ;
74
75     return CT ;
76         }
77
78         /**
79          * Checks a term if it can be processed correctly.
80          *
81          * @return  true if, and only if, the given term consists in letters.
82          */
83         private boolean isStemmable( String term ) {
84                 for ( int c = 0; c < term.length(); c++ ) {
85                         // Discard terms that contain non-letter characters.
86                         if ( !Character.isLetter(term.charAt(c))) {
87                                 return false;
88                         }
89                 }
90                 return true;
91         }
92
93         /**
94          * Checks a term if it can be processed indexed.
95          *
96          * @return  true if it can be indexed
97          */
98         private boolean isIndexable( String term ) {
99                 return (term.length() < 30) && (term.length() > 2) ;
100         }
101
102         /**
103          * See if string is 'a','e','i','o','u'
104    *
105    * @return true if is vowel
106          */
107         private boolean isVowel( char value ) {
108     return (value == 'a') ||
109            (value == 'e') ||
110            (value == 'i') ||
111            (value == 'o') ||
112            (value == 'u') ;
113   }
114
115         /**
116          * Gets R1
117    *
118    * R1 - is the region after the first non-vowel following a vowel,
119    *      or is the null region at the end of the word if there is
120    *      no such non-vowel.
121    *
122    * @return null or a string representing R1
123          */
124         private String getR1( String value ) {
125     int     i;
126     int     j;
127
128     // be-safe !!!
129     if (value == null) {
130       return null ;
131     }
132
133     // find 1st vowel
134     i = value.length()-1 ;
135     for (j=0 ; j < i ; j++) {
136       if (isVowel(value.charAt(j))) {
137         break ;
138       }
139     }
140
141     if (!(j < i)) {
142       return null ;
143     }
144
145     // find 1st non-vowel
146     for ( ; j < i ; j++) {
147       if (!(isVowel(value.charAt(j)))) {
148         break ;
149       }
150     }
151
152     if (!(j < i)) {
153       return null ;
154     }
155
156     return value.substring(j+1) ;
157   }
158
159         /**
160          * Gets RV
161    *
162    * RV - IF the second letter is a consonant, RV is the region after
163    *      the next following vowel,
164    *
165    *      OR if the first two letters are vowels, RV is the region
166    *      after the next consonant,
167    *
168    *      AND otherwise (consonant-vowel case) RV is the region after
169    *      the third letter.
170    *
171    *      BUT RV is the end of the word if this positions cannot be
172    *      found.
173    *
174    * @return null or a string representing RV
175          */
176         private String getRV( String value ) {
177     int     i;
178     int     j;
179
180     // be-safe !!!
181     if (value == null) {
182       return null ;
183     }
184
185     i = value.length()-1 ;
186
187     // RV - IF the second letter is a consonant, RV is the region after
188     //      the next following vowel,
189     if ((i > 0) && !isVowel(value.charAt(1))) {
190       // find 1st vowel
191       for (j=2 ; j < i ; j++) {
192         if (isVowel(value.charAt(j))) {
193           break ;
194         }
195       }
196
197       if (j < i) {
198         return value.substring(j+1) ;
199       }
200     }
201
202
203     // RV - OR if the first two letters are vowels, RV is the region
204     //      after the next consonant,
205     if ((i > 1) &&
206         isVowel(value.charAt(0)) &&
207         isVowel(value.charAt(1))) {
208       // find 1st consoant
209       for (j=2 ; j < i ; j++) {
210         if (!isVowel(value.charAt(j))) {
211           break ;
212         }
213       }
214
215       if (j < i) {
216         return value.substring(j+1) ;
217       }
218     }
219
220     // RV - AND otherwise (consonant-vowel case) RV is the region after
221     //      the third letter.
222     if (i > 2) {
223       return value.substring(3) ;
224     }
225
226     return null ;
227   }
228
229         /**
230    * 1) Turn to lowercase
231    * 2) Remove accents
232    * 3) ã -> a ; õ -> o
233    * 4) ç -> c
234    *
235    * @return null or a string transformed
236          */
237         private String changeTerm( String value ) {
238     int     j;
239     String  r = "" ;
240
241     // be-safe !!!
242     if (value == null) {
243       return null ;
244     }
245
246     value = value.toLowerCase() ;
247     for (j=0 ; j < value.length() ; j++) {
248       if ((value.charAt(j) == 'á') ||
249           (value.charAt(j) == 'â') ||
250           (value.charAt(j) == 'ã')) {
251         r= r + "a" ; continue ;
252       }
253       if ((value.charAt(j) == 'é') ||
254           (value.charAt(j) == 'ê')) {
255         r= r + "e" ; continue ;
256       }
257       if (value.charAt(j) == 'í') {
258         r= r + "i" ; continue ;
259       }
260       if ((value.charAt(j) == 'ó') ||
261           (value.charAt(j) == 'ô') ||
262           (value.charAt(j) == 'õ')) {
263         r= r + "o" ; continue ;
264       }
265       if ((value.charAt(j) == 'ú') ||
266           (value.charAt(j) == 'ü')) {
267         r= r + "u" ; continue ;
268       }
269       if (value.charAt(j) == 'ç') {
270         r= r + "c" ; continue ;
271       }
272       if (value.charAt(j) == 'ñ') {
273         r= r + "n" ; continue ;
274       }
275
276       r= r+ value.charAt(j) ;
277     }
278
279     return r ;
280   }
281
282         /**
283    * Check if a string ends with a suffix
284    *
285    * @return true if the string ends with the specified suffix
286          */
287         private boolean suffix( String value, String suffix ) {
288
289     // be-safe !!!
290     if ((value == null) || (suffix == null)) {
291       return false ;
292     }
293
294     if (suffix.length() > value.length()) {
295       return false ;
296     }
297
298     return value.substring(value.length()-suffix.length()).equals(suffix);
299   }
300
301         /**
302    * Replace a string suffix by another
303    *
304    * @return the replaced String
305          */
306         private String replaceSuffix( String value, String toReplace, String changeTo ) {
307     String vvalue ;
308
309     // be-safe !!!
310     if ((value == null) ||
311         (toReplace == null) ||
312         (changeTo == null) ) {
313       return value ;
314     }
315
316     vvalue = removeSuffix(value,toReplace) ;
317
318     if (value.equals(vvalue)) {
319       return value ;
320     } else {
321       return vvalue + changeTo ;
322     }
323   }
324
325         /**
326    * Remove a string suffix
327    *
328    * @return the String without the suffix
329          */
330         private String removeSuffix( String value, String toRemove ) {
331     // be-safe !!!
332     if ((value == null) ||
333         (toRemove == null) ||
334         !suffix(value,toRemove) ) {
335       return value ;
336     }
337
338     return value.substring(0,value.length()-toRemove.length()) ;
339   }
340
341         /**
342    * See if a suffix is preceded by a String
343    *
344    * @return true if the suffix is preceded
345          */
346         private boolean suffixPreceded( String value, String suffix, String preceded ) {
347     // be-safe !!!
348     if ((value == null) ||
349         (suffix == null) ||
350         (preceded == null) ||
351         !suffix(value,suffix) ) {
352       return false ;
353     }
354
355     return suffix(removeSuffix(value,suffix),preceded) ;
356   }
357
358         /**
359          * Creates CT (changed term) , substituting * 'ã' and 'õ' for 'a~' and 'o~'.
360          */
361         private void createCT( String term ) {
362     CT = changeTerm(term) ;
363
364     if (CT.length() < 2) return ;
365
366     // if the first character is ... , remove it
367     if ((CT.charAt(0) == '"')  ||
368         (CT.charAt(0) == '\'') ||
369         (CT.charAt(0) == '-')  ||
370         (CT.charAt(0) == ',')  ||
371         (CT.charAt(0) == ';')  ||
372         (CT.charAt(0) == '.')  ||
373         (CT.charAt(0) == '?')  ||
374         (CT.charAt(0) == '!')
375         ) {
376         CT = CT.substring(1);
377     }
378
379     if (CT.length() < 2) return ;
380
381     // if the last character is ... , remove it
382     if ((CT.charAt(CT.length()-1) == '-') ||
383         (CT.charAt(CT.length()-1) == ',') ||
384         (CT.charAt(CT.length()-1) == ';') ||
385         (CT.charAt(CT.length()-1) == '.') ||
386         (CT.charAt(CT.length()-1) == '?') ||
387         (CT.charAt(CT.length()-1) == '!') ||
388         (CT.charAt(CT.length()-1) == '\'') ||
389         (CT.charAt(CT.length()-1) == '"')
390         ) {
391         CT = CT.substring(0,CT.length()-1);
392     }
393   }
394
395
396         /**
397          * Standard suffix removal.
398    * Search for the longest among the following suffixes, and perform
399    * the following actions:
400    *
401    * @return false if no ending was removed
402          */
403         private boolean step1() {
404     if (CT == null) return false ;
405
406     // suffix length = 7
407     if (suffix(CT,"uciones") && suffix(R2,"uciones")) {
408         CT = replaceSuffix(CT,"uciones","u") ; return true;
409     }
410
411     // suffix length = 6
412     if (CT.length() >= 6) {
413       if (suffix(CT,"imentos") && suffix(R2,"imentos")) {
414           CT = removeSuffix(CT,"imentos") ; return true;
415       }
416       if (suffix(CT,"amentos") && suffix(R2,"amentos")) {
417           CT = removeSuffix(CT,"amentos") ; return true;
418       }
419       if (suffix(CT,"adores") && suffix(R2,"adores")) {
420           CT = removeSuffix(CT,"adores") ; return true;
421       }
422       if (suffix(CT,"adoras") && suffix(R2,"adoras")) {
423           CT = removeSuffix(CT,"adoras") ; return true;
424       }
425       if (suffix(CT,"logias") && suffix(R2,"logias")) {
426           replaceSuffix(CT,"logias","log") ; return true;
427       }
428       if (suffix(CT,"encias") && suffix(R2,"encias")) {
429           CT = replaceSuffix(CT,"encias","ente") ; return true;
430       }
431       if (suffix(CT,"amente") && suffix(R1,"amente")) {
432           CT = removeSuffix(CT,"amente") ; return true;
433       }
434       if (suffix(CT,"idades") && suffix(R2,"idades")) {
435           CT = removeSuffix(CT,"idades") ; return true;
436       }
437     }
438
439     // suffix length = 5
440     if (CT.length() >= 5) {
441       if (suffix(CT,"acoes") && suffix(R2,"acoes")) {
442           CT = removeSuffix(CT,"acoes") ; return true;
443       }
444       if (suffix(CT,"imento") && suffix(R2,"imento")) {
445           CT = removeSuffix(CT,"imento") ; return true;
446       }
447       if (suffix(CT,"amento") && suffix(R2,"amento")) {
448           CT = removeSuffix(CT,"amento") ; return true;
449       }
450       if (suffix(CT,"adora") && suffix(R2,"adora")) {
451           CT = removeSuffix(CT,"adora") ; return true;
452       }
453       if (suffix(CT,"ismos") && suffix(R2,"ismos")) {
454           CT = removeSuffix(CT,"ismos") ; return true;
455       }
456       if (suffix(CT,"istas") && suffix(R2,"istas")) {
457           CT = removeSuffix(CT,"istas") ; return true;
458       }
459       if (suffix(CT,"logia") && suffix(R2,"logia")) {
460           CT = replaceSuffix(CT,"logia","log") ; return true;
461       }
462       if (suffix(CT,"ucion") && suffix(R2,"ucion")) {
463           CT = replaceSuffix(CT,"ucion","u") ; return true;
464       }
465       if (suffix(CT,"encia") && suffix(R2,"encia")) {
466           CT = replaceSuffix(CT,"encia","ente") ; return true;
467       }
468       if (suffix(CT,"mente") && suffix(R2,"mente")) {
469           CT = removeSuffix(CT,"mente") ; return true;
470       }
471       if (suffix(CT,"idade") && suffix(R2,"idade")) {
472           CT = removeSuffix(CT,"idade") ; return true;
473       }
474     }
475
476     // suffix length = 4
477     if (CT.length() >= 4) {
478       if (suffix(CT,"acao") && suffix(R2,"acao")) {
479           CT = removeSuffix(CT,"acao") ; return true;
480       }
481       if (suffix(CT,"ezas") && suffix(R2,"ezas")) {
482           CT = removeSuffix(CT,"ezas") ; return true;
483       }
484       if (suffix(CT,"icos") && suffix(R2,"icos")) {
485           CT = removeSuffix(CT,"icos") ; return true ;
486       }
487       if (suffix(CT,"icas") && suffix(R2,"icas")) {
488           CT = removeSuffix(CT,"icas") ; return true ;
489       }
490       if (suffix(CT,"ismo") && suffix(R2,"ismo")) {
491           CT = removeSuffix(CT,"ismo") ; return true ;
492       }
493       if (suffix(CT,"avel") && suffix(R2,"avel")) {
494           CT = removeSuffix(CT,"avel") ; return true ;
495       }
496       if (suffix(CT,"ivel") && suffix(R2,"ivel")) {
497           CT = removeSuffix(CT,"ivel") ; return true ;
498       }
499       if (suffix(CT,"ista") && suffix(R2,"ista")) {
500           CT = removeSuffix(CT,"ista") ; return true ;
501       }
502       if (suffix(CT,"osos") && suffix(R2,"osos")) {
503           CT = removeSuffix(CT,"osos") ; return true ;
504       }
505       if (suffix(CT,"osas") && suffix(R2,"osas")) {
506           CT = removeSuffix(CT,"osas") ; return true ;
507       }
508       if (suffix(CT,"ador") && suffix(R2,"ador")) {
509           CT = removeSuffix(CT,"ador") ; return true ;
510       }
511       if (suffix(CT,"ivas") && suffix(R2,"ivas")) {
512           CT = removeSuffix(CT,"ivas") ; return true ;
513       }
514       if (suffix(CT,"ivos") && suffix(R2,"ivos")) {
515           CT = removeSuffix(CT,"ivos") ; return true ;
516       }
517       if (suffix(CT,"iras") &&
518           suffix(RV,"iras") &&
519           suffixPreceded(CT,"iras","e")) {
520           CT = replaceSuffix(CT,"iras","ir") ; return true ;
521       }
522     }
523
524     // suffix length = 3
525     if (CT.length() >= 3) {
526       if (suffix(CT,"eza") && suffix(R2,"eza")) {
527           CT = removeSuffix(CT,"eza") ; return true ;
528       }
529       if (suffix(CT,"ico") && suffix(R2,"ico")) {
530           CT = removeSuffix(CT,"ico") ; return true ;
531       }
532       if (suffix(CT,"ica") && suffix(R2,"ica")) {
533           CT = removeSuffix(CT,"ica") ; return true ;
534       }
535       if (suffix(CT,"oso") && suffix(R2,"oso")) {
536           CT = removeSuffix(CT,"oso") ; return true ;
537       }
538       if (suffix(CT,"osa") && suffix(R2,"osa")) {
539           CT = removeSuffix(CT,"osa") ; return true ;
540       }
541       if (suffix(CT,"iva") && suffix(R2,"iva")) {
542           CT = removeSuffix(CT,"iva") ; return true ;
543       }
544       if (suffix(CT,"ivo") && suffix(R2,"ivo")) {
545           CT = removeSuffix(CT,"ivo") ; return true ;
546       }
547       if (suffix(CT,"ira") &&
548           suffix(RV,"ira") &&
549           suffixPreceded(CT,"ira","e")) {
550           CT = replaceSuffix(CT,"ira","ir") ; return true ;
551       }
552     }
553
554     // no ending was removed by step1
555     return false ;
556   }
557
558
559         /**
560          * Verb suffixes.
561    *
562    * Search for the longest among the following suffixes in RV,
563    * and if found, delete.
564    *
565    * @return false if no ending was removed
566         */
567         private boolean step2() {
568     if (RV == null) return false ;
569
570     // suffix lenght = 7
571     if (RV.length() >= 7) {
572       if (suffix(RV,"issemos")) {
573         CT = removeSuffix(CT,"issemos") ; return true;
574       }
575       if (suffix(RV,"essemos")) {
576         CT = removeSuffix(CT,"essemos") ; return true;
577       }
578       if (suffix(RV,"assemos")) {
579         CT = removeSuffix(CT,"assemos") ; return true;
580       }
581       if (suffix(RV,"ariamos")) {
582         CT = removeSuffix(CT,"ariamos") ; return true;
583       }
584       if (suffix(RV,"eriamos")) {
585         CT = removeSuffix(CT,"eriamos") ; return true;
586       }
587       if (suffix(RV,"iriamos")) {
588         CT = removeSuffix(CT,"iriamos") ; return true;
589       }
590     }
591
592     // suffix length = 6
593     if (RV.length() >= 6) {
594       if (suffix(RV,"iremos")) {
595         CT = removeSuffix(CT,"iremos") ; return true;
596       }
597       if (suffix(RV,"eremos")) {
598         CT = removeSuffix(CT,"eremos") ; return true;
599       }
600       if (suffix(RV,"aremos")) {
601         CT = removeSuffix(CT,"aremos") ; return true;
602       }
603       if (suffix(RV,"avamos")) {
604         CT = removeSuffix(CT,"avamos") ; return true;
605       }
606       if (suffix(RV,"iramos")) {
607         CT = removeSuffix(CT,"iramos") ; return true;
608       }
609       if (suffix(RV,"eramos")) {
610         CT = removeSuffix(CT,"eramos") ; return true;
611       }
612       if (suffix(RV,"aramos")) {
613         CT = removeSuffix(CT,"aramos") ; return true;
614       }
615       if (suffix(RV,"asseis")) {
616         CT = removeSuffix(CT,"asseis") ; return true;
617       }
618       if (suffix(RV,"esseis")) {
619         CT = removeSuffix(CT,"esseis") ; return true;
620       }
621       if (suffix(RV,"isseis")) {
622         CT = removeSuffix(CT,"isseis") ; return true;
623       }
624       if (suffix(RV,"arieis")) {
625         CT = removeSuffix(CT,"arieis") ; return true;
626       }
627       if (suffix(RV,"erieis")) {
628         CT = removeSuffix(CT,"erieis") ; return true;
629       }
630       if (suffix(RV,"irieis")) {
631         CT = removeSuffix(CT,"irieis") ; return true;
632       }
633     }
634
635
636     // suffix length = 5
637     if (RV.length() >= 5) {
638       if (suffix(RV,"irmos")) {
639         CT = removeSuffix(CT,"irmos") ; return true;
640       }
641       if (suffix(RV,"iamos")) {
642         CT = removeSuffix(CT,"iamos") ; return true;
643       }
644       if (suffix(RV,"armos")) {
645         CT = removeSuffix(CT,"armos") ; return true;
646       }
647       if (suffix(RV,"ermos")) {
648         CT = removeSuffix(CT,"ermos") ; return true;
649       }
650       if (suffix(RV,"areis")) {
651         CT = removeSuffix(CT,"areis") ; return true;
652       }
653       if (suffix(RV,"ereis")) {
654         CT = removeSuffix(CT,"ereis") ; return true;
655       }
656       if (suffix(RV,"ireis")) {
657         CT = removeSuffix(CT,"ireis") ; return true;
658       }
659       if (suffix(RV,"asses")) {
660         CT = removeSuffix(CT,"asses") ; return true;
661       }
662       if (suffix(RV,"esses")) {
663         CT = removeSuffix(CT,"esses") ; return true;
664       }
665       if (suffix(RV,"isses")) {
666         CT = removeSuffix(CT,"isses") ; return true;
667       }
668       if (suffix(RV,"astes")) {
669         CT = removeSuffix(CT,"astes") ; return true;
670       }
671       if (suffix(RV,"assem")) {
672         CT = removeSuffix(CT,"assem") ; return true;
673       }
674       if (suffix(RV,"essem")) {
675         CT = removeSuffix(CT,"essem") ; return true;
676       }
677       if (suffix(RV,"issem")) {
678         CT = removeSuffix(CT,"issem") ; return true;
679       }
680       if (suffix(RV,"ardes")) {
681         CT = removeSuffix(CT,"ardes") ; return true;
682       }
683       if (suffix(RV,"erdes")) {
684         CT = removeSuffix(CT,"erdes") ; return true;
685       }
686       if (suffix(RV,"irdes")) {
687         CT = removeSuffix(CT,"irdes") ; return true;
688       }
689       if (suffix(RV,"ariam")) {
690         CT = removeSuffix(CT,"ariam") ; return true;
691       }
692       if (suffix(RV,"eriam")) {
693         CT = removeSuffix(CT,"eriam") ; return true;
694       }
695       if (suffix(RV,"iriam")) {
696         CT = removeSuffix(CT,"iriam") ; return true;
697       }
698       if (suffix(RV,"arias")) {
699         CT = removeSuffix(CT,"arias") ; return true;
700       }
701       if (suffix(RV,"erias")) {
702         CT = removeSuffix(CT,"erias") ; return true;
703       }
704       if (suffix(RV,"irias")) {
705         CT = removeSuffix(CT,"irias") ; return true;
706       }
707       if (suffix(RV,"estes")) {
708         CT = removeSuffix(CT,"estes") ; return true;
709       }
710       if (suffix(RV,"istes")) {
711         CT = removeSuffix(CT,"istes") ; return true;
712       }
713       if (suffix(RV,"areis")) {
714         CT = removeSuffix(CT,"areis") ; return true;
715       }
716       if (suffix(RV,"aveis")) {
717         CT = removeSuffix(CT,"aveis") ; return true;
718       }
719     }
720
721     // suffix length = 4
722     if (RV.length() >= 4) {
723       if (suffix(RV,"aria")) {
724         CT = removeSuffix(CT,"aria") ; return true;
725       }
726       if (suffix(RV,"eria")) {
727         CT = removeSuffix(CT,"eria") ; return true;
728       }
729       if (suffix(RV,"iria")) {
730         CT = removeSuffix(CT,"iria") ; return true;
731       }
732       if (suffix(RV,"asse")) {
733         CT = removeSuffix(CT,"asse") ; return true;
734       }
735       if (suffix(RV,"esse")) {
736         CT = removeSuffix(CT,"esse") ; return true;
737       }
738       if (suffix(RV,"isse")) {
739         CT = removeSuffix(CT,"isse") ; return true;
740       }
741       if (suffix(RV,"aste")) {
742         CT = removeSuffix(CT,"aste") ; return true;
743       }
744       if (suffix(RV,"este")) {
745         CT = removeSuffix(CT,"este") ; return true;
746       }
747       if (suffix(RV,"iste")) {
748         CT = removeSuffix(CT,"iste") ; return true;
749       }
750       if (suffix(RV,"arei")) {
751         CT = removeSuffix(CT,"arei") ; return true;
752       }
753       if (suffix(RV,"erei")) {
754         CT = removeSuffix(CT,"erei") ; return true;
755       }
756       if (suffix(RV,"irei")) {
757         CT = removeSuffix(CT,"irei") ; return true;
758       }
759       if (suffix(RV,"aram")) {
760         CT = removeSuffix(CT,"aram") ; return true;
761       }
762       if (suffix(RV,"eram")) {
763         CT = removeSuffix(CT,"eram") ; return true;
764       }
765       if (suffix(RV,"iram")) {
766         CT = removeSuffix(CT,"iram") ; return true;
767       }
768       if (suffix(RV,"avam")) {
769         CT = removeSuffix(CT,"avam") ; return true;
770       }
771       if (suffix(RV,"arem")) {
772         CT = removeSuffix(CT,"arem") ; return true;
773       }
774       if (suffix(RV,"erem")) {
775         CT = removeSuffix(CT,"erem") ; return true;
776       }
777       if (suffix(RV,"irem")) {
778         CT = removeSuffix(CT,"irem") ; return true;
779       }
780       if (suffix(RV,"ando")) {
781         CT = removeSuffix(CT,"ando") ; return true;
782       }
783       if (suffix(RV,"endo")) {
784         CT = removeSuffix(CT,"endo") ; return true;
785       }
786       if (suffix(RV,"indo")) {
787         CT = removeSuffix(CT,"indo") ; return true;
788       }
789       if (suffix(RV,"arao")) {
790         CT = removeSuffix(CT,"arao") ; return true;
791       }
792       if (suffix(RV,"erao")) {
793         CT = removeSuffix(CT,"erao") ; return true;
794       }
795       if (suffix(RV,"irao")) {
796         CT = removeSuffix(CT,"irao") ; return true;
797       }
798       if (suffix(RV,"adas")) {
799         CT = removeSuffix(CT,"adas") ; return true;
800       }
801       if (suffix(RV,"idas")) {
802         CT = removeSuffix(CT,"idas") ; return true;
803       }
804       if (suffix(RV,"aras")) {
805         CT = removeSuffix(CT,"aras") ; return true;
806       }
807       if (suffix(RV,"eras")) {
808         CT = removeSuffix(CT,"eras") ; return true;
809       }
810       if (suffix(RV,"iras")) {
811         CT = removeSuffix(CT,"iras") ; return true;
812       }
813       if (suffix(RV,"avas")) {
814         CT = removeSuffix(CT,"avas") ; return true;
815       }
816       if (suffix(RV,"ares")) {
817         CT = removeSuffix(CT,"ares") ; return true;
818       }
819       if (suffix(RV,"eres")) {
820         CT = removeSuffix(CT,"eres") ; return true;
821       }
822       if (suffix(RV,"ires")) {
823         CT = removeSuffix(CT,"ires") ; return true;
824       }
825       if (suffix(RV,"ados")) {
826         CT = removeSuffix(CT,"ados") ; return true;
827       }
828       if (suffix(RV,"idos")) {
829         CT = removeSuffix(CT,"idos") ; return true;
830       }
831       if (suffix(RV,"amos")) {
832         CT = removeSuffix(CT,"amos") ; return true;
833       }
834       if (suffix(RV,"emos")) {
835         CT = removeSuffix(CT,"emos") ; return true;
836       }
837       if (suffix(RV,"imos")) {
838         CT = removeSuffix(CT,"imos") ; return true;
839       }
840       if (suffix(RV,"iras")) {
841         CT = removeSuffix(CT,"iras") ; return true;
842       }
843       if (suffix(RV,"ieis")) {
844         CT = removeSuffix(CT,"ieis") ; return true;
845       }
846     }
847
848     // suffix length = 3
849     if (RV.length() >= 3) {
850       if (suffix(RV,"ada")) {
851         CT = removeSuffix(CT,"ada") ; return true;
852       }
853       if (suffix(RV,"ida")) {
854         CT = removeSuffix(CT,"ida") ; return true;
855       }
856       if (suffix(RV,"ara")) {
857         CT = removeSuffix(CT,"ara") ; return true;
858       }
859       if (suffix(RV,"era")) {
860         CT = removeSuffix(CT,"era") ; return true;
861       }
862       if (suffix(RV,"ira")) {
863         CT = removeSuffix(CT,"ava") ; return true;
864       }
865       if (suffix(RV,"iam")) {
866         CT = removeSuffix(CT,"iam") ; return true;
867       }
868       if (suffix(RV,"ado")) {
869         CT = removeSuffix(CT,"ado") ; return true;
870       }
871       if (suffix(RV,"ido")) {
872         CT = removeSuffix(CT,"ido") ; return true;
873       }
874       if (suffix(RV,"ias")) {
875         CT = removeSuffix(CT,"ias") ; return true;
876       }
877       if (suffix(RV,"ais")) {
878         CT = removeSuffix(CT,"ais") ; return true;
879       }
880       if (suffix(RV,"eis")) {
881         CT = removeSuffix(CT,"eis") ; return true;
882       }
883       if (suffix(RV,"ira")) {
884         CT = removeSuffix(CT,"ira") ; return true;
885       }
886       if (suffix(RV,"ear")) {
887         CT = removeSuffix(CT,"ear") ; return true;
888       }
889     }
890
891     // suffix length = 2
892     if (RV.length() >= 2) {
893       if (suffix(RV,"ia")) {
894         CT = removeSuffix(CT,"ia") ; return true;
895       }
896       if (suffix(RV,"ei")) {
897         CT = removeSuffix(CT,"ei") ; return true;
898       }
899       if (suffix(RV,"am")) {
900         CT = removeSuffix(CT,"am") ; return true;
901       }
902       if (suffix(RV,"em")) {
903         CT = removeSuffix(CT,"em") ; return true;
904       }
905       if (suffix(RV,"ar")) {
906         CT = removeSuffix(CT,"ar") ; return true;
907       }
908       if (suffix(RV,"er")) {
909         CT = removeSuffix(CT,"er") ; return true;
910       }
911       if (suffix(RV,"ir")) {
912         CT = removeSuffix(CT,"ir") ; return true;
913       }
914       if (suffix(RV,"as")) {
915         CT = removeSuffix(CT,"as") ; return true;
916       }
917       if (suffix(RV,"es")) {
918         CT = removeSuffix(CT,"es") ; return true;
919       }
920       if (suffix(RV,"is")) {
921         CT = removeSuffix(CT,"is") ; return true;
922       }
923       if (suffix(RV,"eu")) {
924         CT = removeSuffix(CT,"eu") ; return true;
925       }
926       if (suffix(RV,"iu")) {
927         CT = removeSuffix(CT,"iu") ; return true;
928       }
929       if (suffix(RV,"iu")) {
930         CT = removeSuffix(CT,"iu") ; return true;
931       }
932       if (suffix(RV,"ou")) {
933         CT = removeSuffix(CT,"ou") ; return true;
934       }
935     }
936
937     // no ending was removed by step2
938     return false ;
939   }
940
941         /**
942          * Delete suffix 'i' if in RV and preceded by 'c'
943    *
944         */
945         private void step3() {
946     if (RV == null) return ;
947
948     if (suffix(RV,"i") && suffixPreceded(RV,"i","c")) {
949       CT = removeSuffix(CT,"i") ;
950     }
951
952   }
953
954         /**
955          * Residual suffix
956    *
957    * If the word ends with one of the suffixes (os a i o á í ó)
958    * in RV, delete it
959    *
960         */
961         private void step4() {
962     if (RV == null) return  ;
963
964     if (suffix(RV,"os")) {
965       CT = removeSuffix(CT,"os") ; return ;
966     }
967     if (suffix(RV,"a")) {
968       CT = removeSuffix(CT,"a") ; return ;
969     }
970     if (suffix(RV,"i")) {
971       CT = removeSuffix(CT,"i") ; return ;
972     }
973     if (suffix(RV,"o")) {
974       CT = removeSuffix(CT,"o") ; return ;
975     }
976
977   }
978
979         /**
980          * If the word ends with one of ( e é ê) in RV,delete it,
981    * and if preceded by 'gu' (or 'ci') with the 'u' (or 'i') in RV,
982    * delete the 'u' (or 'i')
983    *
984    * Or if the word ends ç remove the cedilha
985    *
986         */
987         private void step5() {
988     if (RV == null) return  ;
989
990     if (suffix(RV,"e")) {
991       if (suffixPreceded(RV,"e","gu")) {
992         CT = removeSuffix(CT,"e") ;
993         CT = removeSuffix(CT,"u") ;
994         return ;
995       }
996
997       if (suffixPreceded(RV,"e","ci")) {
998         CT = removeSuffix(CT,"e") ;
999         CT = removeSuffix(CT,"i") ;
1000         return ;
1001       }
1002
1003       CT = removeSuffix(CT,"e") ; return ;
1004     }
1005   }
1006
1007         /**
1008          * For log and debug purpose
1009          *
1010          * @return  TERM, CT, RV, R1 and R2
1011          */
1012         public String log() {
1013     return " (TERM = " + TERM + ")" +
1014            " (CT = " + CT +")" +
1015            " (RV = " + RV +")" +
1016            " (R1 = " + R1 +")" +
1017            " (R2 = " + R2 +")" ;
1018         }
1019
1020 }
1021