1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/*
2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Copyright 2001-2004 The Apache Software Foundation.
3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * you may not use this file except in compliance with the License.
6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * You may obtain a copy of the License at
7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * See the License for the specific language governing permissions and
14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * limitations under the License.
15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.commons.codec.language;
18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.commons.codec.EncoderException;
20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.commons.codec.StringEncoder;
21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/**
23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Encodes a string into a metaphone value.
24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p>
25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Initial Java implementation by <CITE>William B. Brogden. December, 1997</CITE>.
26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Permission given by <CITE>wbrogden</CITE> for code to be used anywhere.
27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * </p>
28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <p>
29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <CITE>Hanging on the Metaphone</CITE> by <CITE>Lawrence Philips</CITE> in <CITE>Computer Language of Dec. 1990, p
30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 39.</CITE>
31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * </p>
32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Apache Software Foundation
34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @version $Id: Metaphone.java,v 1.20 2004/06/05 18:32:04 ggregory Exp $
35d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *
36d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * @deprecated Please use {@link java.net.URL#openConnection} instead.
37d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
38d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *     for further details.
39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
40d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath@Deprecated
41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class Metaphone implements StringEncoder {
42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Five values in the English language
45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private String vowels = "AEIOU" ;
47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Variable used in Metaphone algorithm
50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private String frontv = "EIY"   ;
52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Variable used in Metaphone algorithm
55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private String varson = "CSPTG" ;
57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The max code length for metaphone is 4
60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private int maxCodeLen = 4 ;
62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates an instance of the Metaphone encoder
65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public Metaphone() {
67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        super();
68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Find the metaphone value of a String. This is similar to the
72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * soundex algorithm, but better at finding similar sounding words.
73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * All input is converted to upper case.
74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Limitations: Input format is expected to be a single ASCII word
75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * with only characters in the A - Z range, no punctuation or numbers.
76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param txt String to find the metaphone code for
78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return A metaphone code corresponding to the String supplied
79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public String metaphone(String txt) {
81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean hard = false ;
82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if ((txt == null) || (txt.length() == 0)) {
83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return "" ;
84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // single character is itself
86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (txt.length() == 1) {
87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return txt.toUpperCase() ;
88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        char[] inwd = txt.toUpperCase().toCharArray() ;
91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        StringBuffer local = new StringBuffer(40); // manipulate
93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        StringBuffer code = new StringBuffer(10) ; //   output
94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // handle initial 2 characters exceptions
95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        switch(inwd[0]) {
96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'K' :
97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'G' :
98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'P' : /* looking for KN, etc*/
99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (inwd[1] == 'N') {
100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd, 1, inwd.length - 1);
101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else {
102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd);
103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            break;
105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'A': /* looking for AE */
106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (inwd[1] == 'E') {
107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd, 1, inwd.length - 1);
108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else {
109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd);
110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            break;
112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'W' : /* looking for WR or WH */
113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (inwd[1] == 'R') {   // WR -> R
114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd, 1, inwd.length - 1);
115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                break ;
116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (inwd[1] == 'H') {
118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd, 1, inwd.length - 1);
119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.setCharAt(0, 'W'); // WH -> W
120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else {
121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                local.append(inwd);
122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            break;
124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        case 'X' : /* initial X becomes S */
125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            inwd[0] = 'S';
126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            local.append(inwd);
127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            break ;
128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        default :
129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            local.append(inwd);
130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } // now local has working string with initials fixed
131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int wdsz = local.length();
133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int n = 0 ;
134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        while ((code.length() < this.getMaxCodeLen()) &&
136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project               (n < wdsz) ) { // max code size of 4 works well
137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            char symb = local.charAt(n) ;
138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // remove duplicate letters except C
139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if ((symb != 'C') && (isPreviousChar( local, n, symb )) ) {
140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                n++ ;
141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else { // not dup
142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                switch(symb) {
143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'A' : case 'E' : case 'I' : case 'O' : case 'U' :
144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (n == 0) {
145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append(symb);
146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ; // only use vowel if leading char
148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'B' :
149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if ( isPreviousChar(local, n, 'M') &&
150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                         isLastChar(wdsz, n) ) { // B is silent if word ends in MB
151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append(symb);
154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break;
155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'C' : // lots of C special cases
156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    /* discard if SCI, SCE or SCY */
157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if ( isPreviousChar(local, n, 'S') &&
158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                         !isLastChar(wdsz, n) &&
159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                         (this.frontv.indexOf(local.charAt(n + 1)) >= 0) ) {
160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (regionMatch(local, n, "CIA")) { // "CIA" -> X
163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('X');
164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (!isLastChar(wdsz, n) &&
167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        (this.frontv.indexOf(local.charAt(n + 1)) >= 0)) {
168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('S');
169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break; // CI,CE,CY -> S
170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isPreviousChar(local, n, 'S') &&
172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        isNextChar(local, n, 'H') ) { // SCH->sk
173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('K') ;
174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break ;
175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isNextChar(local, n, 'H')) { // detect CH
177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        if ((n == 0) &&
178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                            (wdsz >= 3) &&
179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                            isVowel(local,2) ) { // CH consonant -> K consonant
180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                            code.append('K');
181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        } else {
182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                            code.append('X'); // CHvowel -> X
183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        }
184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('K');
186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'D' :
189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (!isLastChar(wdsz, n + 1) &&
190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        isNextChar(local, n, 'G') &&
191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        (this.frontv.indexOf(local.charAt(n + 2)) >= 0)) { // DGE DGI DGY -> J
192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('J'); n += 2 ;
193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('T');
195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'G' : // GH silent at end or before consonant
198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isLastChar(wdsz, n + 1) &&
199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        isNextChar(local, n, 'H')) {
200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (!isLastChar(wdsz, n + 1) &&
203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        isNextChar(local,n,'H') &&
204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        !isVowel(local,n+2)) {
205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if ((n > 0) &&
208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        ( regionMatch(local, n, "GN") ||
209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                          regionMatch(local, n, "GNED") ) ) {
210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break; // silent G
211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isPreviousChar(local, n, 'G')) {
213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        hard = true ;
214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        hard = false ;
216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (!isLastChar(wdsz, n) &&
218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        (this.frontv.indexOf(local.charAt(n + 1)) >= 0) &&
219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        (!hard)) {
220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('J');
221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('K');
223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'H':
226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isLastChar(wdsz, n)) {
227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break ; // terminal H
228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if ((n > 0) &&
230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        (this.varson.indexOf(local.charAt(n - 1)) >= 0)) {
231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isVowel(local,n+1)) {
234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('H'); // Hvowel
235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break;
237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'F':
238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'J' :
239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'L' :
240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'M':
241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'N' :
242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'R' :
243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append(symb);
244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break;
245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'K' :
246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (n > 0) { // not initial
247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        if (!isPreviousChar(local, n, 'C')) {
248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                            code.append(symb);
249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        }
250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append(symb); // initial K
252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'P' :
255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (isNextChar(local,n,'H')) {
256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        // PH -> F
257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('F');
258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append(symb);
260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'Q' :
263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append('K');
264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break;
265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'S' :
266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (regionMatch(local,n,"SH") ||
267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        regionMatch(local,n,"SIO") ||
268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        regionMatch(local,n,"SIA")) {
269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('X');
270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('S');
272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break;
274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'T' :
275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (regionMatch(local,n,"TIA") ||
276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        regionMatch(local,n,"TIO")) {
277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('X');
278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (regionMatch(local,n,"TCH")) {
281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        // Silent if in "TCH"
282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        break;
283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    // substitute numeral 0 for TH (resembles theta after all)
285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (regionMatch(local,n,"TH")) {
286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('0');
287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    } else {
288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append('T');
289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'V' :
292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append('F'); break ;
293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'W' : case 'Y' : // silent if not followed by vowel
294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    if (!isLastChar(wdsz,n) &&
295069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        isVowel(local,n+1)) {
296069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        code.append(symb);
297069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    }
298069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
299069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'X' :
300069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append('K'); code.append('S');
301069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    break ;
302069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                case 'Z' :
303069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    code.append('S'); break ;
304069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                } // end switch
305069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                n++ ;
306069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } // end else from symb != 'C'
307069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (code.length() > this.getMaxCodeLen()) {
308069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                code.setLength(this.getMaxCodeLen());
309069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
310069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
311069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return code.toString();
312069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
313069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
314069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean isVowel(StringBuffer string, int index) {
315069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (this.vowels.indexOf(string.charAt(index)) >= 0);
316069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
317069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
318069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean isPreviousChar(StringBuffer string, int index, char c) {
319069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean matches = false;
320069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if( index > 0 &&
321069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            index < string.length() ) {
322069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            matches = string.charAt(index - 1) == c;
323069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
324069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return matches;
325069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
326069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
327069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean isNextChar(StringBuffer string, int index, char c) {
328069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean matches = false;
329069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if( index >= 0 &&
330069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            index < string.length() - 1 ) {
331069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            matches = string.charAt(index + 1) == c;
332069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
333069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return matches;
334069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
335069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
336069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean regionMatch(StringBuffer string, int index, String test) {
337069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean matches = false;
338069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if( index >= 0 &&
339069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            (index + test.length() - 1) < string.length() ) {
340069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            String substring = string.substring( index, index + test.length());
341069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            matches = substring.equals( test );
342069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
343069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return matches;
344069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
345069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
346069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private boolean isLastChar(int wdsz, int n) {
347069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return n + 1 == wdsz;
348069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
349069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
350069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
351069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
352069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Encodes an Object using the metaphone algorithm.  This method
353069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * is provided in order to satisfy the requirements of the
354069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Encoder interface, and will throw an EncoderException if the
355069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * supplied object is not of type java.lang.String.
356069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
357069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param pObject Object to encode
358069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return An object (or type java.lang.String) containing the
359069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *         metaphone code which corresponds to the String supplied.
360069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws EncoderException if the parameter supplied is not
361069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                          of type java.lang.String
362069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
363069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public Object encode(Object pObject) throws EncoderException {
364069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (!(pObject instanceof java.lang.String)) {
365069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String");
366069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
367069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return metaphone((String) pObject);
368069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
369069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
370069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
371069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Encodes a String using the Metaphone algorithm.
372069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
373069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param pString String object to encode
374069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return The metaphone code corresponding to the String supplied
375069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
376069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public String encode(String pString) {
377069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return metaphone(pString);
378069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
379069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
380069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
381069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Tests is the metaphones of two strings are identical.
382069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
383069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param str1 First of two strings to compare
384069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param str2 Second of two strings to compare
385069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return true if the metaphones of these strings are identical,
386069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *         false otherwise.
387069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
388069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public boolean isMetaphoneEqual(String str1, String str2) {
389069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return metaphone(str1).equals(metaphone(str2));
390069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
391069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
392069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
393069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Returns the maxCodeLen.
394069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return int
395069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
396069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public int getMaxCodeLen() { return this.maxCodeLen; }
397069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
398069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
399069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Sets the maxCodeLen.
400069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param maxCodeLen The maxCodeLen to set
401069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
402069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public void setMaxCodeLen(int maxCodeLen) { this.maxCodeLen = maxCodeLen; }
403069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
404069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project}
405