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