OSDN Git Service

55a29eaa307cfec15bdc1c18fb2e45dd620861a6
[neighbornote/NeighborNote.git] / src / com / swabunga / spell / engine / SpellDictionaryHashMap.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 /*\r
21  * put your module comment here\r
22  * formatted with JxBeauty (c) johann.langhofer@nextra.at\r
23  */\r
24 \r
25 package com.swabunga.spell.engine;\r
26 \r
27 import java.io.BufferedReader;\r
28 import java.io.File;\r
29 import java.io.FileNotFoundException;\r
30 import java.io.FileReader;\r
31 import java.io.FileWriter;\r
32 import java.io.IOException;\r
33 import java.io.Reader;\r
34 import java.util.Hashtable;\r
35 import java.util.List;\r
36 import java.util.Vector;\r
37 \r
38 /**\r
39  * The SpellDictionaryHashMap holds the dictionary\r
40  * <p/>\r
41  * This class is thread safe. Derived classes should ensure that this preserved.\r
42  * <p/>\r
43  * There are many open source dictionary files. For just a few see:\r
44  * http://wordlist.sourceforge.net/\r
45  * <p/>\r
46  * This dictionary class reads words one per line. Make sure that your word list\r
47  * is formatted in this way (most are).\r
48  * <p/>\r
49  * Note that you must create the dictionary with a word list for the added\r
50  * words to persist.\r
51  */\r
52 public class SpellDictionaryHashMap extends SpellDictionaryASpell {\r
53   /** A field indicating the initial hash map capacity (16KB) for the main\r
54    *  dictionary hash map. Interested to see what the performance of a\r
55    *  smaller initial capacity is like.\r
56    */\r
57   private final static int INITIAL_CAPACITY = 16 * 1024;\r
58 \r
59   /**\r
60    * The hashmap that contains the word dictionary. The map is hashed on the doublemeta\r
61    * code. The map entry contains a LinkedList of words that have the same double meta code.\r
62    */\r
63   @SuppressWarnings("unchecked")\r
64 protected Hashtable mainDictionary = new Hashtable(INITIAL_CAPACITY);\r
65 \r
66   /** Holds the dictionary file for appending*/\r
67   private File dictFile = null;\r
68 \r
69   /**\r
70    * Dictionary Constructor.\r
71    * @throws java.io.IOException indicates a problem with the file system\r
72    */\r
73   public SpellDictionaryHashMap() throws IOException {\r
74     super((File) null);\r
75   }\r
76 \r
77   /**\r
78    * Dictionary Constructor.\r
79    * @param wordList The file containing the words list for the dictionary\r
80    * @throws java.io.IOException indicates problems reading the words list\r
81    * file\r
82    */\r
83   public SpellDictionaryHashMap(Reader wordList) throws IOException {\r
84     super((File) null);\r
85     createDictionary(new BufferedReader(wordList));\r
86   }\r
87 \r
88   /**\r
89    * Dictionary convenience Constructor.\r
90    * @param wordList The file containing the words list for the dictionary\r
91    * @throws java.io.FileNotFoundException indicates problems locating the\r
92    * words list file on the system\r
93    * @throws java.io.IOException indicates problems reading the words list\r
94    * file\r
95    */\r
96   public SpellDictionaryHashMap(File wordList) throws FileNotFoundException, IOException {\r
97     this(new FileReader(wordList));\r
98     dictFile = wordList;\r
99   }\r
100 \r
101   /**\r
102    * Dictionary constructor that uses an aspell phonetic file to\r
103    * build the transformation table.\r
104    * @param wordList The file containing the words list for the dictionary\r
105    * @param phonetic The file to use for phonetic transformation of the \r
106    * wordlist.\r
107    * @throws java.io.FileNotFoundException indicates problems locating the\r
108    * file on the system\r
109    * @throws java.io.IOException indicates problems reading the words list\r
110    * file\r
111    */\r
112   public SpellDictionaryHashMap(File wordList, File phonetic) throws FileNotFoundException, IOException {\r
113     super(phonetic);\r
114     dictFile = wordList;\r
115     createDictionary(new BufferedReader(new FileReader(wordList)));\r
116   }\r
117 \r
118   /**\r
119    * Dictionary constructor that uses an aspell phonetic file to\r
120    * build the transformation table. Encoding is used for phonetic file only; \r
121    * default encoding is used for wordList\r
122    * @param wordList The file containing the words list for the dictionary\r
123    * @param phonetic The file to use for phonetic transformation of the \r
124    * wordlist.\r
125    * @param phoneticEncoding Uses the character set encoding specified\r
126    * @throws java.io.FileNotFoundException indicates problems locating the\r
127    * file on the system\r
128    * @throws java.io.IOException indicates problems reading the words list\r
129    * or phonetic information\r
130    */\r
131   public SpellDictionaryHashMap(File wordList, File phonetic, String phoneticEncoding) throws FileNotFoundException, IOException {\r
132     super(phonetic, phoneticEncoding);\r
133     dictFile = wordList;\r
134     createDictionary(new BufferedReader(new FileReader(wordList)));\r
135   }\r
136 \r
137   /**\r
138    * Dictionary constructor that uses an aspell phonetic file to\r
139    * build the transformation table.\r
140    * @param wordList The file containing the words list for the dictionary\r
141    * @param phonetic The reader to use for phonetic transformation of the \r
142    * wordlist.\r
143    * @throws java.io.IOException indicates problems reading the words list\r
144    * or phonetic information\r
145    */\r
146   public SpellDictionaryHashMap(Reader wordList, Reader phonetic) throws IOException {\r
147     super(phonetic);\r
148     dictFile = null;\r
149     createDictionary(new BufferedReader(wordList));\r
150   }\r
151 \r
152   /**\r
153    * Add words from a file to existing dictionary hashmap.\r
154    * This function can be called as many times as needed to\r
155    * build the internal word list. Duplicates are not added.\r
156    * <p>\r
157    * Note that adding a dictionary does not affect the target\r
158    * dictionary file for the addWord method. That is, addWord() continues\r
159    * to make additions to the dictionary file specified in createDictionary()\r
160    * <P>\r
161    * @param wordList a File object that contains the words, on word per line.\r
162    * @throws FileNotFoundException\r
163    * @throws IOException\r
164    */\r
165   public void addDictionary(File wordList) throws FileNotFoundException, IOException {\r
166     addDictionaryHelper(new BufferedReader(new FileReader(wordList)));\r
167   }\r
168 \r
169   /**\r
170    * Add words from a Reader to existing dictionary hashmap.\r
171    * This function can be called as many times as needed to\r
172    * build the internal word list. Duplicates are not added.\r
173    * <p>\r
174    * Note that adding a dictionary does not affect the target\r
175    * dictionary file for the addWord method. That is, addWord() continues\r
176    * to make additions to the dictionary file specified in createDictionary()\r
177    * <P>\r
178    * @param wordList a Reader object that contains the words, on word per line.\r
179    * @throws IOException\r
180    */\r
181   public void addDictionary(Reader wordList) throws IOException {\r
182     addDictionaryHelper(new BufferedReader(wordList));\r
183   }\r
184 \r
185   /**\r
186    * Add a word permanently to the dictionary (and the dictionary file).\r
187    * <p>This needs to be made thread safe (synchronized)</p>\r
188    */\r
189   public void addWord(String word) {\r
190     putWord(word);\r
191     if (dictFile == null)\r
192       return;\r
193     try {\r
194       FileWriter w = new FileWriter(dictFile.toString(), true);\r
195       // Open with append.\r
196       w.write(word);\r
197       w.write("\n");\r
198       w.close();\r
199     } catch (IOException ex) {\r
200       System.out.println("Error writing to dictionary file");\r
201     }\r
202   }\r
203 \r
204   /**\r
205    * Constructs the dictionary from a word list file.\r
206    * <p>\r
207    * Each word in the reader should be on a separate line.\r
208    * <p>\r
209    * This is a very slow function. On my machine it takes quite a while to\r
210    * load the data in. I suspect that we could speed this up quite allot.\r
211    */\r
212   protected void createDictionary(BufferedReader in) throws IOException {\r
213     String line = "";\r
214     while (line != null) {\r
215       line = in.readLine();\r
216       if (line != null && line.length() > 0) {\r
217         line = new String(line.toCharArray());\r
218         putWord(line);\r
219       }\r
220     }\r
221   }\r
222 \r
223   /**\r
224    * Adds to the existing dictionary from a word list file. If the word\r
225    * already exists in the dictionary, a new entry is not added.\r
226    * <p>\r
227    * Each word in the reader should be on a separate line.\r
228    * <p>\r
229    * Note: for whatever reason that I haven't yet looked into, the phonetic codes\r
230    * for a particular word map to a vector of words rather than a hash table.\r
231    * This is a drag since in order to check for duplicates you have to iterate\r
232    * through all the words that use the phonetic code.\r
233    * If the vector-based implementation is important, it may be better\r
234    * to subclass for the cases where duplicates are bad.\r
235    */\r
236   protected void addDictionaryHelper(BufferedReader in) throws IOException {\r
237 \r
238     String line = "";\r
239     while (line != null) {\r
240       line = in.readLine();\r
241       if (line != null && line.length() > 0) {\r
242         line = new String(line.toCharArray());\r
243         putWordUnique(line);\r
244       }\r
245     }\r
246   }\r
247 \r
248   /**\r
249    * Allocates a word in the dictionary\r
250    * @param word The word to add\r
251    */\r
252   @SuppressWarnings("unchecked")\r
253 protected void putWord(String word) {\r
254     String code = getCode(word);\r
255     Vector list = (Vector) mainDictionary.get(code);\r
256     if (list != null) {\r
257       list.addElement(word);\r
258     } else {\r
259       list = new Vector();\r
260       list.addElement(word);\r
261       mainDictionary.put(code, list);\r
262     }\r
263   }\r
264 \r
265   /**\r
266    * Allocates a word, if it is not already present in the dictionary. A word\r
267    * with a different case is considered the same.\r
268    * @param word The word to add\r
269    */\r
270   @SuppressWarnings("unchecked")\r
271 protected void putWordUnique(String word) {\r
272 \r
273     String code = getCode(word);\r
274     Vector list = (Vector) mainDictionary.get(code);\r
275 \r
276     if (list != null) {\r
277 \r
278       boolean isAlready = false;\r
279 \r
280       for (int i = 0; i < list.size(); i++) {\r
281 \r
282         if (word.equalsIgnoreCase((String) list.elementAt(i))) {\r
283           isAlready = true;\r
284           break;\r
285         }\r
286       }\r
287 \r
288       if (!isAlready)\r
289         list.addElement(word);\r
290 \r
291     } else {\r
292 \r
293       list = new Vector();\r
294       list.addElement(word);\r
295       mainDictionary.put(code, list);\r
296 \r
297     }\r
298   }\r
299 \r
300   /**\r
301    * Returns a list of strings (words) for the code.\r
302    */\r
303   @Override\r
304 @SuppressWarnings("unchecked")\r
305 public List getWords(String code) {\r
306     //Check the main dictionary.\r
307     Vector mainDictResult = (Vector) mainDictionary.get(code);\r
308     if (mainDictResult == null)\r
309       return new Vector();\r
310     return mainDictResult;\r
311   }\r
312 \r
313   /**\r
314    * Returns true if the word is correctly spelled against the current word list.\r
315    */\r
316   @Override\r
317 @SuppressWarnings("unchecked")\r
318 public boolean isCorrect(String word) {\r
319     List possible = getWords(getCode(word));\r
320     if (possible.contains(word))\r
321       return true;\r
322     //JMH should we always try the lowercase version. If I dont then capitalised\r
323     //words are always returned as incorrect.\r
324     else if (possible.contains(word.toLowerCase()))\r
325       return true;\r
326     return false;\r
327   }\r
328 }\r