]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/SimpleEntry.java
d90d51fc78224a4934e0a731b3497b6269095cfd
[Dictionary.git] / src / com / hughes / android / dictionary / SimpleEntry.java
1 package com.hughes.android.dictionary;\r
2 \r
3 import java.io.IOException;\r
4 import java.io.RandomAccessFile;\r
5 import java.util.ArrayList;\r
6 import java.util.Arrays;\r
7 import java.util.LinkedHashMap;\r
8 import java.util.LinkedHashSet;\r
9 import java.util.List;\r
10 import java.util.Map;\r
11 import java.util.Set;\r
12 import java.util.regex.Matcher;\r
13 import java.util.regex.Pattern;\r
14 \r
15 import com.hughes.util.raf.RAFFactory;\r
16 import com.hughes.util.raf.RAFSerializable;\r
17 \r
18 public final class SimpleEntry implements Entry {\r
19 \r
20   static final byte LANG1 = 0;\r
21   static final byte LANG2 = 1;\r
22 \r
23   static final Pattern lineSplitPattern = Pattern.compile("\\s::\\s");\r
24   static final Pattern sublineSplitPattern = Pattern.compile("\\s\\|\\s");\r
25 \r
26   final String[] lang1;\r
27   final String[] lang2;\r
28   \r
29   SimpleEntry(final String[] lang1, final String[] lang2) {\r
30     this.lang1 = lang1;\r
31     this.lang2 = lang2;\r
32   }\r
33 \r
34   public static final RAFFactory<SimpleEntry> RAF_FACTORY = new RAFFactory<SimpleEntry>() {\r
35     public SimpleEntry create(RandomAccessFile raf) throws IOException {\r
36       final int rows = raf.readByte();\r
37       final String[] lang1 = new String[rows];\r
38       final String[] lang2 = new String[rows];\r
39       for (int i = 0; i < lang1.length; ++i) {\r
40         lang1[i] = raf.readUTF();\r
41         lang2[i] = raf.readUTF();\r
42       }\r
43       return new SimpleEntry(lang1, lang2);\r
44     }};\r
45   public void write(RandomAccessFile raf) throws IOException {\r
46     assert lang1.length == (byte) lang1.length;\r
47     raf.writeByte(lang1.length);\r
48     for (int i = 0; i < lang1.length; ++i) {\r
49       raf.writeUTF(lang1[i]);\r
50       raf.writeUTF(lang2[i]);\r
51     }\r
52   }\r
53 \r
54   @Override\r
55   public boolean equals(Object o) {\r
56     if (!(o instanceof SimpleEntry)) {\r
57       return false;\r
58     }\r
59     final SimpleEntry that = (SimpleEntry) o;\r
60     return Arrays.deepEquals(this.lang1, that.lang1) && Arrays.deepEquals(this.lang2, that.lang2); \r
61   }\r
62 \r
63   @Override\r
64   public int hashCode() {\r
65     return Arrays.deepHashCode(lang1) + Arrays.deepHashCode(lang2);\r
66   }\r
67 \r
68   @Override\r
69   public String toString() {\r
70     return getRawText(false);\r
71   }\r
72 \r
73   public int getRowCount() {\r
74     assert lang1.length == lang2.length;\r
75     return lang1.length;\r
76   }\r
77 \r
78   String[] getAllText(final byte lang) {\r
79     if (lang == LANG1) {\r
80       return lang1;\r
81     }\r
82     assert lang == LANG2;\r
83     return lang2;\r
84   }\r
85   \r
86   String getRawText(boolean onlyFirstSubentry) {\r
87     final StringBuilder result = new StringBuilder();\r
88     for (int i = 0; i < (onlyFirstSubentry ? 1 : lang1.length); ++i) {\r
89       result.append(i == 0 ? "" : " | ").append(lang1[i]);\r
90     }\r
91     result.append("\t");\r
92     for (int i = 0; i < (onlyFirstSubentry ? 1 : lang2.length); ++i) {\r
93       result.append(i == 0 ? "" : " | ").append(lang2[i]);\r
94     }\r
95     return result.toString();\r
96   }\r
97   \r
98   static byte otherLang(final byte lang) {\r
99     assert lang == LANG1 || lang == LANG2;\r
100     return lang == LANG1 ? LANG2 : LANG1;\r
101   }\r
102   \r
103 /*\r
104 Lu     Letter, Uppercase\r
105 Ll  Letter, Lowercase\r
106 Lt  Letter, Titlecase\r
107 Lm  Letter, Modifier\r
108 Lo  Letter, Other\r
109 Mn  Mark, Nonspacing\r
110 Mc  Mark, Spacing Combining\r
111 Me  Mark, Enclosing\r
112 Nd  Number, Decimal Digit\r
113 Nl  Number, Letter\r
114 No  Number, Other\r
115 Pc  Punctuation, Connector\r
116 Pd  Punctuation, Dash\r
117 Ps  Punctuation, Open\r
118 Pe  Punctuation, Close\r
119 Pi  Punctuation, Initial quote (may behave like Ps or Pe depending on usage)\r
120 Pf  Punctuation, Final quote (may behave like Ps or Pe depending on usage)\r
121 Po  Punctuation, Other\r
122 Sm  Symbol, Math\r
123 Sc  Symbol, Currency\r
124 Sk  Symbol, Modifier\r
125 So  Symbol, Other\r
126 Zs  Separator, Space\r
127 Zl  Separator, Line\r
128 Zp  Separator, Paragraph\r
129 */\r
130 \r
131   static Pattern htmlDecimalCode = Pattern.compile("&#([0-9]+);");\r
132   static Pattern htmlCode = Pattern.compile("&#[^;]+;");\r
133   \r
134   static SimpleEntry parseFromLine(String line, final boolean hasMultipleSubentries) {\r
135     \r
136     line = line.replaceAll("&lt;", "<");\r
137     line = line.replaceAll("&gt;", ">");\r
138     Matcher matcher;\r
139     while ((matcher = htmlDecimalCode.matcher(line)).find()) {\r
140       final int intVal = Integer.parseInt(matcher.group(1));\r
141       final String charCode = "" + ((char) intVal);\r
142       System.out.println("Replacing " + matcher.group() + " with " + charCode);\r
143       line = matcher.replaceAll(charCode);\r
144     }\r
145     if ((matcher = htmlCode.matcher(line)).find()) {\r
146       System.err.println("HTML code: " + matcher.group());\r
147     }\r
148     \r
149     final String[] parts = lineSplitPattern.split(line);\r
150     if (parts.length != 2) {\r
151       System.err.println("Entry:" + "Invalid line: " + line);\r
152       return null;\r
153     }\r
154     if (!hasMultipleSubentries) {\r
155       return new SimpleEntry(new String[] {parts[0].trim()}, new String[] {parts[1].trim()});\r
156     }\r
157     \r
158     final String[] lang1 = sublineSplitPattern.split(" " + parts[0].trim() + " ");\r
159     final String[] lang2 = sublineSplitPattern.split(" " + parts[1].trim() + " ");\r
160     if (lang1.length != lang2.length) {\r
161       System.err.println("Entry:" + "Invalid subline: " + line);\r
162       return null;\r
163     }\r
164     for (int i = 0; i < lang1.length; ++i) {\r
165       lang1[i] = lang1[i].trim();\r
166       lang2[i] = lang2[i].trim();\r
167     }\r
168     return new SimpleEntry(lang1, lang2);\r
169   }\r
170   \r
171   static final Map<String, String> bracketToClose = new LinkedHashMap<String, String>();\r
172   static {\r
173     bracketToClose.put("\"", "\"");\r
174     bracketToClose.put(" '", "' ");\r
175   }\r
176   \r
177   // This used to be called WHITESPACE.\r
178   static final Pattern NON_TOKEN_CHAR = Pattern.compile("\\s+");\r
179   \r
180   public Map<String,Integer> getIndexableTokens(final byte lang) {\r
181     final Set<String> result = new LinkedHashSet<String>();\r
182     String text = " ";\r
183     for (final String subentry : getAllText(lang)) {\r
184       text += subentry + " ";\r
185     }\r
186 \r
187     text = text.replaceAll("fig\\.", " ");\r
188     text = text.replaceAll("\\{[^\\}]+}", " ");\r
189     text = text.replaceAll("\"-", "-");\r
190     text = text.replaceAll("-\"", "-");\r
191     text = text.replaceAll("[\"/\\()<>\\[\\],;?!.]", " ");\r
192     text = text.replaceAll("[-:] ", " ");\r
193     text = text.replaceAll(" [-:]", " ");\r
194     \r
195     // Now be really conservative about what we allow inside a token:\r
196     // See: http://unicode.org/Public/UNIDATA/UCD.html#General_Category_Values\r
197     text = text.replaceAll("[^-:\\p{L}\\p{N}\\p{S}]", " ");\r
198     result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
199 \r
200     text = text.replaceAll("[-]", " ");\r
201     result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
202     \r
203     final Set<String> result2 = new LinkedHashSet<String>();\r
204     for (final String token : result) {\r
205       if (isIndexable(token)) {\r
206         result2.add(token);\r
207       }\r
208     }\r
209     return result2;\r
210   }\r
211 \r
212   static boolean isIndexable(final String text) {\r
213     // Does it have an alpha-numeric anywhere?\r
214     return text.matches(".*\\w.*");\r
215   }\r
216   \r
217 }