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 $ 35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class Metaphone implements StringEncoder { 37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Five values in the English language 40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private String vowels = "AEIOU" ; 42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Variable used in Metaphone algorithm 45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private String frontv = "EIY" ; 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 varson = "CSPTG" ; 52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * The max code length for metaphone is 4 55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private int maxCodeLen = 4 ; 57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Creates an instance of the Metaphone encoder 60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public Metaphone() { 62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project super(); 63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Find the metaphone value of a String. This is similar to the 67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * soundex algorithm, but better at finding similar sounding words. 68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * All input is converted to upper case. 69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Limitations: Input format is expected to be a single ASCII word 70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with only characters in the A - Z range, no punctuation or numbers. 71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param txt String to find the metaphone code for 73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return A metaphone code corresponding to the String supplied 74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public String metaphone(String txt) { 76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project boolean hard = false ; 77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((txt == null) || (txt.length() == 0)) { 78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return "" ; 79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // single character is itself 81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (txt.length() == 1) { 82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return txt.toUpperCase() ; 83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project char[] inwd = txt.toUpperCase().toCharArray() ; 86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project StringBuffer local = new StringBuffer(40); // manipulate 88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project StringBuffer code = new StringBuffer(10) ; // output 89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // handle initial 2 characters exceptions 90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project switch(inwd[0]) { 91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'K' : 92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'G' : 93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'P' : /* looking for KN, etc*/ 94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (inwd[1] == 'N') { 95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd, 1, inwd.length - 1); 96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd); 98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'A': /* looking for AE */ 101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (inwd[1] == 'E') { 102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd, 1, inwd.length - 1); 103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd); 105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'W' : /* looking for WR or WH */ 108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (inwd[1] == 'R') { // WR -> R 109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd, 1, inwd.length - 1); 110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (inwd[1] == 'H') { 113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd, 1, inwd.length - 1); 114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.setCharAt(0, 'W'); // WH -> W 115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd); 117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'X' : /* initial X becomes S */ 120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project inwd[0] = 'S'; 121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd); 122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project default : 124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project local.append(inwd); 125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } // now local has working string with initials fixed 126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int wdsz = local.length(); 128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project int n = 0 ; 129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project while ((code.length() < this.getMaxCodeLen()) && 131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (n < wdsz) ) { // max code size of 4 works well 132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project char symb = local.charAt(n) ; 133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // remove duplicate letters except C 134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((symb != 'C') && (isPreviousChar( local, n, symb )) ) { 135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project n++ ; 136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { // not dup 137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project switch(symb) { 138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'A' : case 'E' : case 'I' : case 'O' : case 'U' : 139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (n == 0) { 140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; // only use vowel if leading char 143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'B' : 144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ( isPreviousChar(local, n, 'M') && 145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isLastChar(wdsz, n) ) { // B is silent if word ends in MB 146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'C' : // lots of C special cases 151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /* discard if SCI, SCE or SCY */ 152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ( isPreviousChar(local, n, 'S') && 153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project !isLastChar(wdsz, n) && 154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (this.frontv.indexOf(local.charAt(n + 1)) >= 0) ) { 155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (regionMatch(local, n, "CIA")) { // "CIA" -> X 158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('X'); 159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isLastChar(wdsz, n) && 162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (this.frontv.indexOf(local.charAt(n + 1)) >= 0)) { 163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('S'); 164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; // CI,CE,CY -> S 165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isPreviousChar(local, n, 'S') && 167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isNextChar(local, n, 'H') ) { // SCH->sk 168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K') ; 169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isNextChar(local, n, 'H')) { // detect CH 172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((n == 0) && 173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (wdsz >= 3) && 174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isVowel(local,2) ) { // CH consonant -> K consonant 175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K'); 176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('X'); // CHvowel -> X 178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K'); 181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'D' : 184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isLastChar(wdsz, n + 1) && 185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isNextChar(local, n, 'G') && 186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (this.frontv.indexOf(local.charAt(n + 2)) >= 0)) { // DGE DGI DGY -> J 187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('J'); n += 2 ; 188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('T'); 190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'G' : // GH silent at end or before consonant 193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isLastChar(wdsz, n + 1) && 194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isNextChar(local, n, 'H')) { 195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isLastChar(wdsz, n + 1) && 198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isNextChar(local,n,'H') && 199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project !isVowel(local,n+2)) { 200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((n > 0) && 203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project ( regionMatch(local, n, "GN") || 204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project regionMatch(local, n, "GNED") ) ) { 205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; // silent G 206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isPreviousChar(local, n, 'G')) { 208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project hard = true ; 209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project hard = false ; 211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isLastChar(wdsz, n) && 213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (this.frontv.indexOf(local.charAt(n + 1)) >= 0) && 214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (!hard)) { 215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('J'); 216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K'); 218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'H': 221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isLastChar(wdsz, n)) { 222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; // terminal H 223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if ((n > 0) && 225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (this.varson.indexOf(local.charAt(n - 1)) >= 0)) { 226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isVowel(local,n+1)) { 229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('H'); // Hvowel 230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'F': 233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'J' : 234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'L' : 235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'M': 236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'N' : 237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'R' : 238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'K' : 241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (n > 0) { // not initial 242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isPreviousChar(local, n, 'C')) { 243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); // initial K 247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'P' : 250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (isNextChar(local,n,'H')) { 251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // PH -> F 252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('F'); 253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'Q' : 258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K'); 259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'S' : 261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (regionMatch(local,n,"SH") || 262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project regionMatch(local,n,"SIO") || 263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project regionMatch(local,n,"SIA")) { 264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('X'); 265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('S'); 267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'T' : 270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (regionMatch(local,n,"TIA") || 271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project regionMatch(local,n,"TIO")) { 272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('X'); 273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (regionMatch(local,n,"TCH")) { 276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // Silent if in "TCH" 277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break; 278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project // substitute numeral 0 for TH (resembles theta after all) 280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (regionMatch(local,n,"TH")) { 281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('0'); 282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } else { 283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('T'); 284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'V' : 287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('F'); break ; 288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'W' : case 'Y' : // silent if not followed by vowel 289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!isLastChar(wdsz,n) && 290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project isVowel(local,n+1)) { 291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append(symb); 292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'X' : 295069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('K'); code.append('S'); 296069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project break ; 297069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project case 'Z' : 298069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.append('S'); break ; 299069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } // end switch 300069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project n++ ; 301069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } // end else from symb != 'C' 302069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (code.length() > this.getMaxCodeLen()) { 303069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project code.setLength(this.getMaxCodeLen()); 304069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 305069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 306069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return code.toString(); 307069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 308069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 309069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean isVowel(StringBuffer string, int index) { 310069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return (this.vowels.indexOf(string.charAt(index)) >= 0); 311069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 312069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 313069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean isPreviousChar(StringBuffer string, int index, char c) { 314069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project boolean matches = false; 315069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if( index > 0 && 316069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project index < string.length() ) { 317069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project matches = string.charAt(index - 1) == c; 318069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 319069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return matches; 320069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 321069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 322069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean isNextChar(StringBuffer string, int index, char c) { 323069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project boolean matches = false; 324069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if( index >= 0 && 325069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project index < string.length() - 1 ) { 326069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project matches = string.charAt(index + 1) == c; 327069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 328069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return matches; 329069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 330069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 331069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean regionMatch(StringBuffer string, int index, String test) { 332069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project boolean matches = false; 333069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if( index >= 0 && 334069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project (index + test.length() - 1) < string.length() ) { 335069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project String substring = string.substring( index, index + test.length()); 336069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project matches = substring.equals( test ); 337069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 338069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return matches; 339069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 340069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 341069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project private boolean isLastChar(int wdsz, int n) { 342069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return n + 1 == wdsz; 343069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 344069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 345069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 346069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 347069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Encodes an Object using the metaphone algorithm. This method 348069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * is provided in order to satisfy the requirements of the 349069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Encoder interface, and will throw an EncoderException if the 350069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * supplied object is not of type java.lang.String. 351069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 352069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param pObject Object to encode 353069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return An object (or type java.lang.String) containing the 354069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * metaphone code which corresponds to the String supplied. 355069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @throws EncoderException if the parameter supplied is not 356069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * of type java.lang.String 357069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 358069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public Object encode(Object pObject) throws EncoderException { 359069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project if (!(pObject instanceof java.lang.String)) { 360069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String"); 361069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 362069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return metaphone((String) pObject); 363069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 364069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 365069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 366069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Encodes a String using the Metaphone algorithm. 367069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 368069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param pString String object to encode 369069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return The metaphone code corresponding to the String supplied 370069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 371069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public String encode(String pString) { 372069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return metaphone(pString); 373069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 374069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 375069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 376069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Tests is the metaphones of two strings are identical. 377069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 378069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param str1 First of two strings to compare 379069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param str2 Second of two strings to compare 380069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return true if the metaphones of these strings are identical, 381069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * false otherwise. 382069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 383069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public boolean isMetaphoneEqual(String str1, String str2) { 384069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project return metaphone(str1).equals(metaphone(str2)); 385069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project } 386069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 387069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 388069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Returns the maxCodeLen. 389069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @return int 390069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 391069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public int getMaxCodeLen() { return this.maxCodeLen; } 392069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 393069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project /** 394069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Sets the maxCodeLen. 395069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @param maxCodeLen The maxCodeLen to set 396069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 397069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project public void setMaxCodeLen(int maxCodeLen) { this.maxCodeLen = maxCodeLen; } 398069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 399069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} 400