OSDN Git Service

343c169f6ee407c3b6ab55af7738cdb8143fd7a8
[neighbornote/NeighborNote.git] / src / com / swabunga / spell / engine / DoubleMeta.java
1 /*\r
2 Jazzy - a Java library for Spell Checking\r
3 Copyright (C) 2001 Mindaugas Idzelis\r
4 Full text of license can be found in LICENSE.txt\r
5 \r
6 This library is free software; you can redistribute it and/or\r
7 modify it under the terms of the GNU Lesser General Public\r
8 License as published by the Free Software Foundation; either\r
9 version 2.1 of the License, or (at your option) any later version.\r
10 \r
11 This library is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
14 Lesser General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU Lesser General Public\r
17 License along with this library; if not, write to the Free Software\r
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
19 */\r
20 package com.swabunga.spell.engine;\r
21 \r
22 \r
23 /**\r
24  * A phonetic encoding algorithm that takes an English word and computes a phonetic version of it. This\r
25  * allows for phonetic matches in a spell checker. This class is a port of the C++ DoubleMetaphone() class,\r
26  * which was intended to return two possible phonetic translations for certain words, although the Java version\r
27  * only seems to be concerned with one, making the "double" part erroneous.\r
28  * <br>\r
29  * source code for the original C++ can be found\r
30  * here: <a href="http://aspell.sourceforge.net/metaphone/"/>http://aspell.sourceforge.net/metaphone/</a>\r
31  * DoubleMetaphone does some processing, such as uppercasing, on the input string first to normalize it. Then, to\r
32  * create the key, the function traverses the input string in a while loop, sending successive characters into a giant\r
33  * switch statement. Before determining the appropriate pronunciation, the algorithm considers the context\r
34  * surrounding each character within the input string.\r
35  * <p>\r
36  * Things that were changed:\r
37  *   <br/>The alternate flag could be set to true but was never checked so why bother with it. REMOVED\r
38  *   <br/>Why was this class serializable?\r
39  *   <br/>The primary, in, length and last variables could be initialized and local to the\r
40  *   process method and references passed around the appropriate methods. As such there are\r
41  *   no class variables and this class becomes firstly threadsafe and secondly could be static final.\r
42  *   <br/>The function call SlavoGermaic was called repeatedly in the process function, it is now only called once.\r
43  *\r
44  */\r
45 public class DoubleMeta implements Transformator {\r
46 \r
47   /**\r
48    * The replace list is used in the getSuggestions method.\r
49    * All of the letters in the misspelled word are replaced with the characters from\r
50    * this list to try and generate more suggestions, which implies l*n tries,\r
51    * if l is the size of the string, and n is the size of this list.\r
52    *\r
53    * In addition to that, each of these letters is added to the misspelled word.\r
54    */\r
55   private static char[] replaceList = {'A', 'B', 'X', 'S', 'K', 'J', 'T', 'F', 'H', 'L', 'M', 'N', 'P', 'R', '0'};\r
56 \r
57 \r
58   private static final String[] myList = {"GN", "KN", "PN", "WR", "PS", ""};\r
59   private static final String[] list1 = {"ACH", ""};\r
60   private static final String[] list2 = {"BACHER", "MACHER", ""};\r
61   private static final String[] list3 = {"CAESAR", ""};\r
62   private static final String[] list4 = {"CHIA", ""};\r
63   private static final String[] list5 = {"CH", ""};\r
64   private static final String[] list6 = {"CHAE", ""};\r
65   private static final String[] list7 = {"HARAC", "HARIS", ""};\r
66   private static final String[] list8 = {"HOR", "HYM", "HIA", "HEM", ""};\r
67   private static final String[] list9 = {"CHORE", ""};\r
68   private static final String[] list10 = {"VAN ", "VON ", ""};\r
69   private static final String[] list11 = {"SCH", ""};\r
70   private static final String[] list12 = {"ORCHES", "ARCHIT", "ORCHID", ""};\r
71   private static final String[] list13 = {"T", "S", ""};\r
72   private static final String[] list14 = {"A", "O", "U", "E", ""};\r
73   private static final String[] list15 = {"L", "R", "N", "M", "B", "H", "F", "V", "W", " ", ""};\r
74   private static final String[] list16 = {"MC", ""};\r
75   private static final String[] list17 = {"CZ", ""};\r
76   private static final String[] list18 = {"WICZ", ""};\r
77   private static final String[] list19 = {"CIA", ""};\r
78   private static final String[] list20 = {"CC", ""};\r
79   private static final String[] list21 = {"I", "E", "H", ""};\r
80   private static final String[] list22 = {"HU", ""};\r
81   private static final String[] list23 = {"UCCEE", "UCCES", ""};\r
82   private static final String[] list24 = {"CK", "CG", "CQ", ""};\r
83   private static final String[] list25 = {"CI", "CE", "CY", ""};\r
84 // DMV: used by the orininal code which returned two phonetic code, but not the current code\r
85 //    private static final String[] list26 = {\r
86 //        "CIO", "CIE", "CIA", ""\r
87 //    };\r
88   private static final String[] list27 = {" C", " Q", " G", ""};\r
89   private static final String[] list28 = {"C", "K", "Q", ""};\r
90   private static final String[] list29 = {"CE", "CI", ""};\r
91   private static final String[] list30 = {"DG", ""};\r
92   private static final String[] list31 = {"I", "E", "Y", ""};\r
93   private static final String[] list32 = {"DT", "DD", ""};\r
94   private static final String[] list33 = {"B", "H", "D", ""};\r
95   private static final String[] list34 = {"B", "H", "D", ""};\r
96   private static final String[] list35 = {"B", "H", ""};\r
97   private static final String[] list36 = {"C", "G", "L", "R", "T", ""};\r
98   private static final String[] list37 = {"EY", ""};\r
99   private static final String[] list38 = {"LI", ""};\r
100   private static final String[] list39 = {"ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER", ""};\r
101   private static final String[] list40 = {"ER", ""};\r
102   private static final String[] list41 = {"DANGER", "RANGER", "MANGER", ""};\r
103   private static final String[] list42 = {"E", "I", ""};\r
104   private static final String[] list43 = {"RGY", "OGY", ""};\r
105   private static final String[] list44 = {"E", "I", "Y", ""};\r
106   private static final String[] list45 = {"AGGI", "OGGI", ""};\r
107   private static final String[] list46 = {"VAN ", "VON ", ""};\r
108   private static final String[] list47 = {"SCH", ""};\r
109   private static final String[] list48 = {"ET", ""};\r
110 \r
111 //  DMV: used by the orininal code which returned two phonetic code, but not the current code\r
112 //    private static final String[] list49 = {\r
113 //        "IER ", ""\r
114 //    };\r
115   private static final String[] list50 = {"JOSE", ""};\r
116   private static final String[] list51 = {"SAN ", ""};\r
117   private static final String[] list52 = {"SAN ", ""};\r
118   private static final String[] list53 = {"JOSE", ""};\r
119   private static final String[] list54 = {"L", "T", "K", "S", "N", "M", "B", "Z", ""};\r
120   private static final String[] list55 = {"S", "K", "L", ""};\r
121   private static final String[] list56 = {"ILLO", "ILLA", "ALLE", ""};\r
122   private static final String[] list57 = {"AS", "OS", ""};\r
123   private static final String[] list58 = {"A", "O", ""};\r
124   private static final String[] list59 = {"ALLE", ""};\r
125   private static final String[] list60 = {"UMB", ""};\r
126   private static final String[] list61 = {"ER", ""};\r
127   private static final String[] list62 = {"P", "B", ""};\r
128   private static final String[] list63 = {"IE", ""};\r
129   private static final String[] list64 = {"ME", "MA", ""};\r
130   private static final String[] list65 = {"ISL", "YSL", ""};\r
131   private static final String[] list66 = {"SUGAR", ""};\r
132   private static final String[] list67 = {"SH", ""};\r
133   private static final String[] list68 = {"HEIM", "HOEK", "HOLM", "HOLZ", ""};\r
134   private static final String[] list69 = {"SIO", "SIA", ""};\r
135   private static final String[] list70 = {"SIAN", ""};\r
136   private static final String[] list71 = {"M", "N", "L", "W", ""};\r
137   private static final String[] list72 = {"Z", ""};\r
138   private static final String[] list73 = {"Z", ""};\r
139   private static final String[] list74 = {"SC", ""};\r
140   private static final String[] list75 = {"OO", "ER", "EN", "UY", "ED", "EM", ""};\r
141   private static final String[] list76 = {"ER", "EN", ""};\r
142   private static final String[] list77 = {"I", "E", "Y", ""};\r
143   private static final String[] list78 = {"AI", "OI", ""};\r
144   private static final String[] list79 = {"S", "Z", ""};\r
145   private static final String[] list80 = {"TION", ""};\r
146   private static final String[] list81 = {"TIA", "TCH", ""};\r
147   private static final String[] list82 = {"TH", ""};\r
148   private static final String[] list83 = {"TTH", ""};\r
149   private static final String[] list84 = {"OM", "AM", ""};\r
150   private static final String[] list85 = {"VAN ", "VON ", ""};\r
151   private static final String[] list86 = {"SCH", ""};\r
152   private static final String[] list87 = {"T", "D", ""};\r
153   private static final String[] list88 = {"WR", ""};\r
154   private static final String[] list89 = {"WH", ""};\r
155   private static final String[] list90 = {"EWSKI", "EWSKY", "OWSKI", "OWSKY", ""};\r
156   private static final String[] list91 = {"SCH", ""};\r
157   private static final String[] list92 = {"WICZ", "WITZ", ""};\r
158   private static final String[] list93 = {"IAU", "EAU", ""};\r
159   private static final String[] list94 = {"AU", "OU", ""};\r
160   private static final String[] list95 = {"C", "X", ""};\r
161 \r
162 //  DMV: used by the orininal code which returned two phonetic code, but not the current code\r
163 //    private static final String[] list96 = {\r
164 //        "ZO", "ZI", "ZA", ""\r
165 //    };\r
166 \r
167   /**\r
168    * put your documentation comment here\r
169    * @return\r
170    */\r
171   private final static boolean SlavoGermanic(String in) {\r
172     if ((in.indexOf("W") > -1) || (in.indexOf("K") > -1) || (in.indexOf("CZ") > -1) || (in.indexOf("WITZ") > -1))\r
173       return true;\r
174     return false;\r
175   }\r
176 \r
177   /**\r
178    * put your documentation comment here\r
179    * @param main\r
180    */\r
181   private final static void MetaphAdd(StringBuffer primary, String main) {\r
182     if (main != null) {\r
183       primary.append(main);\r
184     }\r
185   }\r
186 \r
187   private final static void MetaphAdd(StringBuffer primary, char main) {\r
188     primary.append(main);\r
189   }\r
190 \r
191   /**\r
192    * put your documentation comment here\r
193    * @param at\r
194    * @return\r
195    */\r
196   private final static boolean isVowel(String in, int at, int length) {\r
197     if ((at < 0) || (at >= length))\r
198       return false;\r
199     char it = in.charAt(at);\r
200     if ((it == 'A') || (it == 'E') || (it == 'I') || (it == 'O') || (it == 'U') || (it == 'Y'))\r
201       return true;\r
202     return false;\r
203   }\r
204 \r
205   /**\r
206    * put your documentation comment here\r
207    * @param string\r
208    * @param start\r
209    * @param length\r
210    * @param list\r
211    * @return\r
212    */\r
213   private final static boolean stringAt(String string, int start, int length, String[] list) {\r
214     if ((start < 0) || (start >= string.length()) || list.length == 0)\r
215       return false;\r
216     String substr = string.substring(start, start + length);\r
217     for (int i = 0; i < list.length; i++) {\r
218       if (list[i].equals(substr))\r
219         return true;\r
220     }\r
221     return false;\r
222   }\r
223 \r
224   /**\r
225    * Take the given word, and return the best phonetic hash for it.\r
226    * Vowels are minimized as much as possible, and consenants\r
227    * that have similiar sounds are converted to the same consenant\r
228    * for example, 'v' and 'f' are both converted to 'f'\r
229    * @param word the texte to transform\r
230    * @return the result of the phonetic transformation\r
231    */\r
232   public final String transform(String word) {\r
233     StringBuffer primary = new StringBuffer(word.length() + 5);\r
234     String in = word.toUpperCase() + "     ";\r
235     int current = 0;\r
236     int length = in.length();\r
237     if (length < 1)\r
238       return "";\r
239     int last = length - 1;\r
240     boolean isSlavoGermaic = SlavoGermanic(in);\r
241     if (stringAt(in, 0, 2, myList))\r
242       current += 1;\r
243     if (in.charAt(0) == 'X') {\r
244       MetaphAdd(primary, 'S');\r
245       current += 1;\r
246     }\r
247     while (current < length) {\r
248       switch (in.charAt(current)) {\r
249         case 'A':\r
250         case 'E':\r
251         case 'I':\r
252         case 'O':\r
253         case 'U':\r
254         case 'Y':\r
255           if (current == 0)\r
256             MetaphAdd(primary, 'A');\r
257           current += 1;\r
258           break;\r
259         case 'B':\r
260           MetaphAdd(primary, 'P');\r
261           if (in.charAt(current + 1) == 'B')\r
262             current += 2;\r
263           else\r
264             current += 1;\r
265           break;\r
266         case '\u00C7':\r
267           MetaphAdd(primary, 'S');\r
268           current += 1;\r
269           break;\r
270         case 'C':\r
271           if ((current > 1) && !isVowel(in, current - 2, length) && stringAt(in, (current - 1), 3, list1) && (in.charAt(current + 2) != 'I') && (in.charAt(current + 2) != 'E') || stringAt(in, (current - 2), 6, list2)) {\r
272             MetaphAdd(primary, 'K');\r
273             current += 2;\r
274             break;\r
275           }\r
276           if ((current == 0) && stringAt(in, current, 6, list3)) {\r
277             MetaphAdd(primary, 'S');\r
278             current += 2;\r
279             break;\r
280           }\r
281           if (stringAt(in, current, 4, list4)) {\r
282             MetaphAdd(primary, 'K');\r
283             current += 2;\r
284             break;\r
285           }\r
286           if (stringAt(in, current, 2, list5)) {\r
287             if ((current > 0) && stringAt(in, current, 4, list6)) {\r
288               MetaphAdd(primary, 'K');\r
289               current += 2;\r
290               break;\r
291             }\r
292             if ((current == 0) && stringAt(in, (current + 1), 5, list7) || stringAt(in, current + 1, 3, list8) && !stringAt(in, 0, 5, list9)) {\r
293               MetaphAdd(primary, 'K');\r
294               current += 2;\r
295               break;\r
296             }\r
297             if (stringAt(in, 0, 4, list10) || stringAt(in, 0, 3, list11) || stringAt(in, current - 2, 6, list12) || stringAt(in, current + 2, 1, list13) || (stringAt(in, current - 1, 1, list14) || (current == 0)) && stringAt(in, current + 2, 1, list15)) {\r
298               MetaphAdd(primary, 'K');\r
299             } else {\r
300               if (current > 0) {\r
301                 if (stringAt(in, 0, 2, list16))\r
302                   MetaphAdd(primary, 'K');\r
303                 else\r
304                   MetaphAdd(primary, 'X');\r
305               } else {\r
306                 MetaphAdd(primary, 'X');\r
307               }\r
308             }\r
309             current += 2;\r
310             break;\r
311           }\r
312           if (stringAt(in, current, 2, list17) && !stringAt(in, current, 4, list18)) {\r
313             MetaphAdd(primary, 'S');\r
314             current += 2;\r
315             break;\r
316           }\r
317           if (stringAt(in, current, 2, list19)) {\r
318             MetaphAdd(primary, 'X');\r
319             current += 2;\r
320             break;\r
321           }\r
322           if (stringAt(in, current, 2, list20) && !((current == 1) && in.charAt(0) == 'M')) {\r
323             if (stringAt(in, current + 2, 1, list21) && !stringAt(in, current + 2, 2, list22)) {\r
324               if (((current == 1) && (in.charAt(current - 1) == 'A')) || stringAt(in, (current - 1), 5, list23))\r
325                 MetaphAdd(primary, "KS");\r
326               else\r
327                 MetaphAdd(primary, 'X');\r
328               current += 3;\r
329               break;\r
330             } else {\r
331               MetaphAdd(primary, 'K');\r
332               current += 2;\r
333               break;\r
334             }\r
335           }\r
336           if (stringAt(in, current, 2, list24)) {\r
337             MetaphAdd(primary, 'K');\r
338             current += 2;\r
339             break;\r
340           } else if (stringAt(in, current, 2, list25)) {\r
341             MetaphAdd(primary, 'S');\r
342             current += 2;\r
343             break;\r
344           }\r
345 \r
346           MetaphAdd(primary, 'K');\r
347           if (stringAt(in, current + 1, 2, list27))\r
348             current += 3;\r
349           else if (stringAt(in, current + 1, 1, list28) && !stringAt(in, current + 1, 2, list29))\r
350             current += 2;\r
351           else\r
352             current += 1;\r
353           break;\r
354         case 'D':\r
355           if (stringAt(in, current, 2, list30)) {\r
356             if (stringAt(in, current + 2, 1, list31)) {\r
357               MetaphAdd(primary, 'J');\r
358               current += 3;\r
359               break;\r
360             } else {\r
361               MetaphAdd(primary, "TK");\r
362               current += 2;\r
363               break;\r
364             }\r
365           }\r
366           MetaphAdd(primary, 'T');\r
367           if (stringAt(in, current, 2, list32)) {\r
368             current += 2;\r
369           } else {\r
370             current += 1;\r
371           }\r
372           break;\r
373         case 'F':\r
374           if (in.charAt(current + 1) == 'F')\r
375             current += 2;\r
376           else\r
377             current += 1;\r
378           MetaphAdd(primary, 'F');\r
379           break;\r
380         case 'G':\r
381           if (in.charAt(current + 1) == 'H') {\r
382             if ((current > 0) && !isVowel(in, current - 1, length)) {\r
383               MetaphAdd(primary, 'K');\r
384               current += 2;\r
385               break;\r
386             }\r
387             if (current < 3) {\r
388               if (current == 0) {\r
389                 if (in.charAt(current + 2) == 'I')\r
390                   MetaphAdd(primary, 'J');\r
391                 else\r
392                   MetaphAdd(primary, 'K');\r
393                 current += 2;\r
394                 break;\r
395               }\r
396             }\r
397             if ((current > 1) && stringAt(in, current - 2, 1, list33) || ((current > 2) && stringAt(in, current - 3, 1, list34)) || ((current > 3) && stringAt(in, current - 4, 1, list35))) {\r
398               current += 2;\r
399               break;\r
400             } else {\r
401               if ((current > 2) && (in.charAt(current - 1) == 'U') && stringAt(in, current - 3, 1, list36)) {\r
402                 MetaphAdd(primary, 'F');\r
403               } else {\r
404                 if ((current > 0) && (in.charAt(current - 1) != 'I'))\r
405                   MetaphAdd(primary, 'K');\r
406               }\r
407               current += 2;\r
408               break;\r
409             }\r
410           }\r
411           if (in.charAt(current + 1) == 'N') {\r
412             if ((current == 1) && isVowel(in, 0, length) && !isSlavoGermaic) {\r
413               MetaphAdd(primary, "KN");\r
414             } else {\r
415               if (!stringAt(in, current + 2, 2, list37) && (in.charAt(current + 1) != 'Y') && !isSlavoGermaic) {\r
416                 MetaphAdd(primary, "N");\r
417               } else {\r
418                 MetaphAdd(primary, "KN");\r
419               }\r
420             }\r
421             current += 2;\r
422             break;\r
423           }\r
424           if (stringAt(in, current + 1, 2, list38) && !isSlavoGermaic) {\r
425             MetaphAdd(primary, "KL");\r
426             current += 2;\r
427             break;\r
428           }\r
429           if ((current == 0) && ((in.charAt(current + 1) == 'Y') || stringAt(in, current + 1, 2, list39))) {\r
430             MetaphAdd(primary, 'K');\r
431             current += 2;\r
432             break;\r
433           }\r
434           if ((stringAt(in, current + 1, 2, list40) || (in.charAt(current + 1) == 'Y')) && !stringAt(in, 0, 6, list41) && !stringAt(in, current - 1, 1, list42) && !stringAt(in, current - 1, 3, list43)) {\r
435             MetaphAdd(primary, 'K');\r
436             current += 2;\r
437             break;\r
438           }\r
439           if (stringAt(in, current + 1, 1, list44) || stringAt(in, current - 1, 4, list45)) {\r
440             if (stringAt(in, 0, 4, list46) || stringAt(in, 0, 3, list47) || stringAt(in, current + 1, 2, list48)) {\r
441               MetaphAdd(primary, 'K');\r
442             } else {\r
443               MetaphAdd(primary, 'J');\r
444             }\r
445             current += 2;\r
446             break;\r
447           }\r
448           if (in.charAt(current + 1) == 'G')\r
449             current += 2;\r
450           else\r
451             current += 1;\r
452           MetaphAdd(primary, 'K');\r
453           break;\r
454         case 'H':\r
455           if (((current == 0) || isVowel(in, current - 1, length)) && isVowel(in, current + 1, length)) {\r
456             MetaphAdd(primary, 'H');\r
457             current += 2;\r
458           } else {\r
459             current += 1;\r
460           }\r
461           break;\r
462         case 'J':\r
463           if (stringAt(in, current, 4, list50) || stringAt(in, 0, 4, list51)) {\r
464             if ((current == 0) && (in.charAt(current + 4) == ' ') || stringAt(in, 0, 4, list52)) {\r
465               MetaphAdd(primary, 'H');\r
466             } else {\r
467               MetaphAdd(primary, 'J');\r
468             }\r
469             current += 1;\r
470             break;\r
471           }\r
472           if ((current == 0) && !stringAt(in, current, 4, list53)) {\r
473             MetaphAdd(primary, 'J');\r
474           } else {\r
475             if (isVowel(in, current - 1, length) && !isSlavoGermaic && ((in.charAt(current + 1) == 'A') || in.charAt(current + 1) == 'O')) {\r
476               MetaphAdd(primary, 'J');\r
477             } else {\r
478               if (current == last) {\r
479                 MetaphAdd(primary, 'J');\r
480               } else {\r
481                 if (!stringAt(in, current + 1, 1, list54) && !stringAt(in, current - 1, 1, list55)) {\r
482                   MetaphAdd(primary, 'J');\r
483                 }\r
484               }\r
485             }\r
486           }\r
487           if (in.charAt(current + 1) == 'J')\r
488             current += 2;\r
489           else\r
490             current += 1;\r
491           break;\r
492         case 'K':\r
493           if (in.charAt(current + 1) == 'K')\r
494             current += 2;\r
495           else\r
496             current += 1;\r
497           MetaphAdd(primary, 'K');\r
498           break;\r
499         case 'L':\r
500           if (in.charAt(current + 1) == 'L') {\r
501             if (((current == (length - 3)) && stringAt(in, current - 1, 4, list56)) || ((stringAt(in, last - 1, 2, list57) || stringAt(in, last, 1, list58)) && stringAt(in, current - 1, 4, list59))) {\r
502               MetaphAdd(primary, 'L');\r
503               current += 2;\r
504               break;\r
505             }\r
506             current += 2;\r
507           } else\r
508             current += 1;\r
509           MetaphAdd(primary, 'L');\r
510           break;\r
511         case 'M':\r
512           if ((stringAt(in, current - 1, 3, list60) && (((current + 1) == last) || stringAt(in, current + 2, 2, list61))) || (in.charAt(current + 1) == 'M'))\r
513             current += 2;\r
514           else\r
515             current += 1;\r
516           MetaphAdd(primary, 'M');\r
517           break;\r
518         case 'N':\r
519           if (in.charAt(current + 1) == 'N')\r
520             current += 2;\r
521           else\r
522             current += 1;\r
523           MetaphAdd(primary, 'N');\r
524           break;\r
525         case '\u00D1':\r
526           current += 1;\r
527           MetaphAdd(primary, 'N');\r
528           break;\r
529         case 'P':\r
530           if (in.charAt(current + 1) == 'N') {\r
531             MetaphAdd(primary, 'F');\r
532             current += 2;\r
533             break;\r
534           }\r
535           if (stringAt(in, current + 1, 1, list62))\r
536             current += 2;\r
537           else\r
538             current += 1;\r
539           MetaphAdd(primary, 'P');\r
540           break;\r
541         case 'Q':\r
542           if (in.charAt(current + 1) == 'Q')\r
543             current += 2;\r
544           else\r
545             current += 1;\r
546           MetaphAdd(primary, 'K');\r
547           break;\r
548         case 'R':\r
549           if ((current == last) && !isSlavoGermaic && stringAt(in, current - 2, 2, list63) && !stringAt(in, current - 4, 2, list64)) {\r
550 //            MetaphAdd(primary, "");\r
551           } else\r
552             MetaphAdd(primary, 'R');\r
553           if (in.charAt(current + 1) == 'R')\r
554             current += 2;\r
555           else\r
556             current += 1;\r
557           break;\r
558         case 'S':\r
559           if (stringAt(in, current - 1, 3, list65)) {\r
560             current += 1;\r
561             break;\r
562           }\r
563           if ((current == 0) && stringAt(in, current, 5, list66)) {\r
564             MetaphAdd(primary, 'X');\r
565             current += 1;\r
566             break;\r
567           }\r
568           if (stringAt(in, current, 2, list67)) {\r
569             if (stringAt(in, current + 1, 4, list68))\r
570               MetaphAdd(primary, 'S');\r
571             else\r
572               MetaphAdd(primary, 'X');\r
573             current += 2;\r
574             break;\r
575           }\r
576           if (stringAt(in, current, 3, list69) || stringAt(in, current, 4, list70)) {\r
577             MetaphAdd(primary, 'S');\r
578             current += 3;\r
579             break;\r
580           }\r
581           if (((current == 0) && stringAt(in, current + 1, 1, list71)) || stringAt(in, current + 1, 1, list72)) {\r
582             MetaphAdd(primary, 'S');\r
583             if (stringAt(in, current + 1, 1, list73))\r
584               current += 2;\r
585             else\r
586               current += 1;\r
587             break;\r
588           }\r
589           if (stringAt(in, current, 2, list74)) {\r
590             if (in.charAt(current + 2) == 'H')\r
591               if (stringAt(in, current + 3, 2, list75)) {\r
592                 if (stringAt(in, current + 3, 2, list76)) {\r
593                   MetaphAdd(primary, "X");\r
594                 } else {\r
595                   MetaphAdd(primary, "SK");\r
596                 }\r
597                 current += 3;\r
598                 break;\r
599               } else {\r
600                 MetaphAdd(primary, 'X');\r
601                 current += 3;\r
602                 break;\r
603               }\r
604             if (stringAt(in, current + 2, 1, list77)) {\r
605               MetaphAdd(primary, 'S');\r
606               current += 3;\r
607               break;\r
608             }\r
609             MetaphAdd(primary, "SK");\r
610             current += 3;\r
611             break;\r
612           }\r
613           if ((current == last) && stringAt(in, current - 2, 2, list78)) {\r
614             //MetaphAdd(primary, "");\r
615           } else\r
616             MetaphAdd(primary, 'S');\r
617           if (stringAt(in, current + 1, 1, list79))\r
618             current += 2;\r
619           else\r
620             current += 1;\r
621           break;\r
622         case 'T':\r
623           if (stringAt(in, current, 4, list80)) {\r
624             MetaphAdd(primary, 'X');\r
625             current += 3;\r
626             break;\r
627           }\r
628           if (stringAt(in, current, 3, list81)) {\r
629             MetaphAdd(primary, 'X');\r
630             current += 3;\r
631             break;\r
632           }\r
633           if (stringAt(in, current, 2, list82) || stringAt(in, current, 3, list83)) {\r
634             if (stringAt(in, (current + 2), 2, list84) || stringAt(in, 0, 4, list85) || stringAt(in, 0, 3, list86)) {\r
635               MetaphAdd(primary, 'T');\r
636             } else {\r
637               MetaphAdd(primary, '0');\r
638             }\r
639             current += 2;\r
640             break;\r
641           }\r
642           if (stringAt(in, current + 1, 1, list87)) {\r
643             current += 2;\r
644           } else\r
645             current += 1;\r
646           MetaphAdd(primary, 'T');\r
647           break;\r
648         case 'V':\r
649           if (in.charAt(current + 1) == 'V')\r
650             current += 2;\r
651           else\r
652             current += 1;\r
653           MetaphAdd(primary, 'F');\r
654           break;\r
655         case 'W':\r
656           if (stringAt(in, current, 2, list88)) {\r
657             MetaphAdd(primary, 'R');\r
658             current += 2;\r
659             break;\r
660           }\r
661           if ((current == 0) && (isVowel(in, current + 1, length) || stringAt(in, current, 2, list89))) {\r
662             MetaphAdd(primary, 'A');\r
663           }\r
664           if (((current == last) && isVowel(in, current - 1, length)) || stringAt(in, current - 1, 5, list90) || stringAt(in, 0, 3, list91)) {\r
665             MetaphAdd(primary, 'F');\r
666             current += 1;\r
667             break;\r
668           }\r
669           if (stringAt(in, current, 4, list92)) {\r
670             MetaphAdd(primary, "TS");\r
671             current += 4;\r
672             break;\r
673           }\r
674           current += 1;\r
675           break;\r
676         case 'X':\r
677           if (!((current == last) && (stringAt(in, current - 3, 3, list93) || stringAt(in, current - 2, 2, list94))))\r
678             MetaphAdd(primary, "KS");\r
679           if (stringAt(in, current + 1, 1, list95))\r
680             current += 2;\r
681           else\r
682             current += 1;\r
683           break;\r
684         case 'Z':\r
685           if (in.charAt(current + 1) == 'H') {\r
686             MetaphAdd(primary, 'J');\r
687             current += 2;\r
688             break;\r
689           } else {\r
690             MetaphAdd(primary, 'S');\r
691           }\r
692           if (in.charAt(current + 1) == 'Z')\r
693             current += 2;\r
694           else\r
695             current += 1;\r
696           break;\r
697         default:\r
698           current += 1;\r
699       }\r
700     }\r
701     return primary.toString();\r
702   }\r
703 \r
704   /**\r
705    * @see com.swabunga.spell.engine.Transformator#getReplaceList()\r
706    */\r
707   public char[] getReplaceList() {\r
708     return replaceList;\r
709   }\r
710 }\r
711 \r
712 \r
713 \r