]> gitweb.fperrin.net Git - DictionaryPC.git/blob - src/com/hughes/android/dictionary/parser/wiktionary/AbstractWiktionaryParser.java
Apply astyle code formatting.
[DictionaryPC.git] / src / com / hughes / android / dictionary / parser / wiktionary / AbstractWiktionaryParser.java
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package com.hughes.android.dictionary.parser.wiktionary;
16
17 import java.io.BufferedInputStream;
18 import java.io.DataInputStream;
19 import java.io.EOFException;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.util.LinkedHashMap;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.SortedMap;
29 import java.util.TreeMap;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 import java.util.regex.Pattern;
34
35 import com.hughes.android.dictionary.engine.EntrySource;
36 import com.hughes.android.dictionary.engine.EntryTypeName;
37 import com.hughes.android.dictionary.engine.IndexBuilder;
38 import com.hughes.android.dictionary.engine.IndexedEntry;
39 import com.hughes.android.dictionary.parser.Parser;
40 import com.hughes.android.dictionary.parser.WikiTokenizer;
41 import com.hughes.util.EnumUtil;
42
43 public abstract class AbstractWiktionaryParser implements Parser {
44
45     static final Logger LOG = Logger.getLogger("WiktionaryParser");
46
47     final SortedMap<String, AtomicInteger> counters = new TreeMap<String, AtomicInteger>();
48     final Set<String> pairsAdded = new LinkedHashSet<String>();
49
50     public EntrySource entrySource;
51     public String title;
52
53
54     abstract void parseSection(final String heading, final String text);
55
56     abstract void removeUselessArgs(final Map<String, String> namedArgs);
57
58     @Override
59     public void parse(final File file, final EntrySource entrySource, final int pageLimit) throws IOException {
60         this.entrySource = entrySource;
61         int pageCount = 0;
62         final DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
63         try {
64             while (true) {
65                 if (pageLimit >= 0 && pageCount >= pageLimit) {
66                     return;
67                 }
68
69                 try {
70                     title = dis.readUTF();
71                 } catch (EOFException e) {
72                     LOG.log(Level.INFO, "EOF reading split.");
73                     dis.close();
74                     return;
75                 }
76                 final String heading = dis.readUTF();
77                 final int bytesLength = dis.readInt();
78                 final byte[] bytes = new byte[bytesLength];
79                 dis.readFully(bytes);
80                 final String text = new String(bytes, "UTF8");
81
82                 parseSection(heading, text);
83
84                 ++pageCount;
85                 if (pageCount % 1000 == 0) {
86                     LOG.info("pageCount=" + pageCount);
87                 }
88             }
89         } finally {
90             dis.close();
91             LOG.info("***COUNTERS***");
92             for (final Map.Entry<String, AtomicInteger> entry : counters.entrySet()) {
93                 LOG.info(entry.getKey() + ": " + entry.getValue());
94             }
95         }
96     }
97
98     static final Pattern whitespace = Pattern.compile("\\s+");
99     static String trim(final String s) {
100         return whitespace.matcher(s).replaceAll(" ").trim();
101     }
102
103     public void incrementCount(final String string) {
104         AtomicInteger counter = counters.get(string);
105         if (counter == null) {
106             counter = new AtomicInteger();
107             counters.put(string, counter);
108         }
109         counter.incrementAndGet();
110     }
111
112     public void addLinkToCurrentEntry(final String token, final String lang, final EntryTypeName entryTypeName) {
113         assert false : token + ", title=" + title;
114     }
115
116
117     // -------------------------------------------------------------------------
118
119     static class AppendAndIndexWikiCallback<T extends AbstractWiktionaryParser> implements WikiTokenizer.Callback {
120
121         final T parser;
122         StringBuilder builder;
123         IndexedEntry indexedEntry;
124         IndexBuilder indexBuilder;
125         final Map<String,FunctionCallback<T>> functionCallbacks = new LinkedHashMap<String, FunctionCallback<T>>();
126
127         boolean entryTypeNameSticks = false;
128         EntryTypeName entryTypeName = null;
129
130         final Map<String,AtomicInteger> langCodeToTCount = new LinkedHashMap<String, AtomicInteger>();
131
132         final NameAndArgs<T> nameAndArgs = new NameAndArgs<T>();
133
134         public AppendAndIndexWikiCallback(final T parser) {
135             this.parser = parser;
136         }
137
138         public void reset(final StringBuilder builder, final IndexedEntry indexedEntry) {
139             this.builder = builder;
140             this.indexedEntry = indexedEntry;
141             this.indexBuilder = null;
142             entryTypeName = null;
143             entryTypeNameSticks = false;
144         }
145
146         public void dispatch(final String wikiText, final IndexBuilder indexBuilder, final EntryTypeName entryTypeName) {
147             final IndexBuilder oldIndexBuilder = this.indexBuilder;
148             final EntryTypeName oldEntryTypeName = this.entryTypeName;
149             this.indexBuilder = indexBuilder;
150             if (!entryTypeNameSticks) {
151                 this.entryTypeName = EnumUtil.min(entryTypeName, this.entryTypeName);
152             }
153             if (entryTypeName == null) this.entryTypeName = null;
154             WikiTokenizer.dispatch(wikiText, false, this);
155             this.indexBuilder = oldIndexBuilder;
156             this.entryTypeName = oldEntryTypeName;
157         }
158
159         public String dispatch(final String wikiText, final EntryTypeName entryTypeName) {
160             final int start = builder.length();
161             dispatch(wikiText, this.indexBuilder, entryTypeName);
162             return builder.substring(start);
163         }
164
165         @Override
166         public void onPlainText(final String plainText) {
167             // The only non-recursive callback.  Just appends to the builder, and indexes.
168             builder.append(plainText);
169             if (indexBuilder != null && entryTypeName != null && indexedEntry != null) {
170                 indexBuilder.addEntryWithString(indexedEntry, plainText, entryTypeName);
171             }
172         }
173
174         @Override
175         public void onWikiLink(WikiTokenizer wikiTokenizer) {
176             final String text = wikiTokenizer.wikiLinkText();
177             @SuppressWarnings("unused")
178             final String link = wikiTokenizer.wikiLinkDest();
179             dispatch(text, entryTypeName);
180         }
181
182         @Override
183         public void onFunction(
184             final WikiTokenizer wikiTokenizer,
185             final String name,
186             final List<String> args,
187             final Map<String, String> namedArgs) {
188
189             FunctionCallback<T> functionCallback = functionCallbacks.get(name);
190             if (functionCallback == null || !functionCallback.onWikiFunction(wikiTokenizer, name, args, namedArgs, parser, this)) {
191                 // Default function handling:
192                 parser.removeUselessArgs(namedArgs);
193                 final boolean single = args.isEmpty() && namedArgs.isEmpty();
194                 builder.append(single ? "{" : "{{");
195
196                 final IndexBuilder oldIndexBuilder = indexBuilder;
197                 indexBuilder = null;
198                 nameAndArgs.onWikiFunction(wikiTokenizer, name, args, namedArgs, parser, this);
199                 indexBuilder = oldIndexBuilder;
200
201                 builder.append(single ? "}" : "}}");
202             }
203         }
204
205         @Override
206         public void onHtml(WikiTokenizer wikiTokenizer) {
207             if (wikiTokenizer.token().startsWith("<ref>")) {
208                 // Do nothing.
209                 return;
210             }
211             // Unindexed for now.
212             builder.append(wikiTokenizer.token());
213         }
214
215         @Override
216         public void onMarkup(WikiTokenizer wikiTokenizer) {
217             // Do nothing.
218         }
219
220         @Override
221         public final void onComment(WikiTokenizer wikiTokenizer) {
222             // Do nothing.
223         }
224
225         @Override
226         public void onNewline(WikiTokenizer wikiTokenizer) {
227             assert false;
228         }
229
230         @Override
231         public void onHeading(WikiTokenizer wikiTokenizer) {
232             assert false;
233         }
234
235         @Override
236         public void onListItem(WikiTokenizer wikiTokenizer) {
237             assert false;
238         }
239
240     }
241
242     // --------------------------------------------------------------------
243
244     static final class NameAndArgs<T extends AbstractWiktionaryParser> implements FunctionCallback<T> {
245         @Override
246         public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
247                                       final Map<String, String> namedArgs, final T parser,
248                                       final AppendAndIndexWikiCallback<T> appendAndIndexWikiCallback) {
249
250             if (name != null) {
251                 appendAndIndexWikiCallback.dispatch(name, null);
252             }
253             for (int i = 0; i < args.size(); ++i) {
254                 if (args.get(i).length() > 0) {
255                     appendAndIndexWikiCallback.builder.append("|");
256                     appendAndIndexWikiCallback.dispatch(args.get(i), null, null);
257                 }
258             }
259             appendNamedArgs(namedArgs, appendAndIndexWikiCallback);
260             return true;
261         }
262     }
263     static NameAndArgs<AbstractWiktionaryParser> NAME_AND_ARGS = new NameAndArgs<AbstractWiktionaryParser>();
264
265     static void appendNamedArgs(final Map<String, String> namedArgs,
266                                 final AppendAndIndexWikiCallback<?> appendAndIndexWikiCallback) {
267         for (final Map.Entry<String, String> entry : namedArgs.entrySet()) {
268             appendAndIndexWikiCallback.builder.append("|");
269             appendAndIndexWikiCallback.dispatch(entry.getKey(), null, null);
270             appendAndIndexWikiCallback.builder.append("=");
271             EntryTypeName entryTypeName = null;
272             IndexBuilder indexBuilder = null;
273             // This doesn't work: we'd need to add to word-forms.
274 //      System.out.println(entry.getKey());
275 //      if (entry.getKey().equals("tr")) {
276 //        entryTypeName = EntryTypeName.WIKTIONARY_TRANSLITERATION;
277 //        indexBuilder = appendAndIndexWikiCallback.parser.foreignIndexBuilder;
278 //      }
279             appendAndIndexWikiCallback.dispatch(entry.getValue(), indexBuilder, entryTypeName);
280         }
281     }
282
283 }