]> gitweb.fperrin.net Git - DictionaryPC.git/blob - src/com/hughes/android/dictionary/WiktionaryXmlParser.java
3ed461776af5b1a85101d1b26a0d9d59112c71dc
[DictionaryPC.git] / src / com / hughes / android / dictionary / WiktionaryXmlParser.java
1 package com.hughes.android.dictionary;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.TreeMap;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.regex.Pattern;
13
14 import javax.xml.parsers.ParserConfigurationException;
15 import javax.xml.parsers.SAXParser;
16 import javax.xml.parsers.SAXParserFactory;
17
18 import org.xml.sax.Attributes;
19 import org.xml.sax.SAXException;
20
21 import com.hughes.util.MapUtil;
22 import com.hughes.util.StringUtil;
23
24 public class WiktionaryXmlParser extends org.xml.sax.helpers.DefaultHandler {
25
26   final Dictionary dict;
27
28   StringBuilder titleBuilder;
29   StringBuilder textBuilder;
30   StringBuilder currentBuilder = null;
31
32   public WiktionaryXmlParser(final Dictionary dict) {
33     this.dict = dict;
34   }
35
36   @Override
37   public void startElement(String uri, String localName, String qName,
38       Attributes attributes) {
39     currentBuilder = null;
40     if ("page".equals(qName)) {
41       titleBuilder = new StringBuilder();
42       textBuilder = new StringBuilder();
43     } else if ("title".equals(qName)) {
44       currentBuilder = titleBuilder;
45     } else if ("text".equals(qName)) {
46       currentBuilder = textBuilder;
47     }
48   }
49
50   @Override
51   public void characters(char[] ch, int start, int length) throws SAXException {
52     if (currentBuilder != null) {
53       currentBuilder.append(ch, start, length);
54     }
55   }
56
57   @Override
58   public void endElement(String uri, String localName, String qName)
59       throws SAXException {
60     currentBuilder = null;
61     if ("page".equals(qName)) {
62       endPage();
63     }
64   }
65
66   private static final Pattern NEWLINE = Pattern.compile("\n", Pattern.LITERAL);
67
68   // MULTILINE for ^
69   private static final Pattern SECTION_HEADER = Pattern
70       .compile("=== *\\{\\{Wortart\\|");
71
72   private static final Pattern WORTART_DELIM = Pattern.compile("===",
73       Pattern.LITERAL);
74   private static final Pattern GENDER = Pattern.compile("\\{\\{([mfn])\\}\\}");
75
76   private static final Pattern WIKI_QUOTE = Pattern.compile("''",
77       Pattern.LITERAL);
78   private static final Pattern WIKI_DOUBLE_BRACE = Pattern
79       .compile("\\{\\{([^}]+)\\}\\}");
80   private static final Pattern WIKI_DOUBLE_BRACKET = Pattern
81       .compile("\\[\\[([^\\]]+)\\]\\]");
82   private static final Pattern WIKI_NEW_SECTION = Pattern.compile("^\\{\\{([^}]+)\\}\\}|^=", Pattern.MULTILINE);
83
84   enum Field {
85     Wortart("Wortart", null),
86
87     Aussprache("Aussprache", null),
88
89     Bedeutungen("Bedeutungen", Pattern.compile("\\{\\{Bedeutungen\\}\\}")),
90
91     Verkleinerungsformen("Verkleinerungsformen", Pattern.compile("\\{\\{Verkleinerungsformen\\}\\}")),
92
93     Synonome("Synonyme", Pattern.compile("\\{\\{Synonyme\\}\\}")),
94
95     Gegenworte("Gegenworte", Pattern.compile("\\{\\{Gegenworte\\}\\}")),
96
97     Oberbegriffe("Oberbegriffe", Pattern.compile("\\{\\{Oberbegriffe\\}\\}")),
98
99     Unterbegriffe("Unterbegriffe", Pattern.compile("\\{\\{Unterbegriffe\\}\\}")),
100
101     Beispiele("Beispiele", Pattern.compile("\\{\\{Beispiele\\}\\}")),
102
103     Redewendungen("Redewendungen", Pattern.compile("\\{\\{Redewendungen\\}\\}")),
104
105     CharakteristischeWortkombinationen("Charakteristische Wortkombinationen",
106         Pattern.compile("\\{\\{Charakteristische Wortkombinationen\\}\\}")),
107
108     AbgeleiteteBegriffe("Abgeleitete Begriffe", Pattern
109         .compile("\\{\\{Abgeleitete Begriffe\\}\\}")),
110
111     Herkunft("Herkunft", Pattern.compile("\\{\\{Herkunft\\}\\}")),
112     
113     Silbentrennung(null, Pattern.compile("\\{\\{Silbentrennung\\}\\}")),
114     
115     ;
116
117     final String name;
118     final Pattern listPattern;
119
120     Field(final String name, final Pattern listPattern) {
121       this.name = name;
122       this.listPattern = listPattern;
123     }
124   }
125
126   private static final Pattern WORTART = Pattern
127       .compile("\\{\\{Wortart\\|([^}]+)\\|([^}]+)\\}\\}");
128   private static final Pattern AUSSPRACHE = Pattern.compile(":Hilfe:IPA|IPA:",
129       Pattern.LITERAL);
130
131   private final Map<String, AtomicInteger> errorCounts = new TreeMap<String, AtomicInteger>();
132
133   private void endPage() {
134
135     StringBuilder text = textBuilder;
136     text = new StringBuilder(WIKI_QUOTE.matcher(text).replaceAll("\""));
137     text = new StringBuilder(WIKI_DOUBLE_BRACKET.matcher(text).replaceAll("$1"));
138
139     // Remove comments.
140     StringUtil.removeAll(text, Pattern.compile("<!--", Pattern.LITERAL),
141         Pattern.compile("-->", Pattern.LITERAL));
142
143     String sectionString;
144     while ((sectionString = StringUtil.remove(text, SECTION_HEADER,
145         SECTION_HEADER, false)) != null) {
146       final StringBuilder section = new StringBuilder(sectionString);
147
148       String wortart = StringUtil.remove(section, WORTART_DELIM, WORTART_DELIM,
149           true);
150       if (wortart.contains("\n") || !wortart.contains("eutsch")) {
151         MapUtil.safeGet(errorCounts, "Invalid wortart: " + wortart,
152             AtomicInteger.class).incrementAndGet();
153         continue;
154       }
155
156       final LinkedHashMap<Field, List<String>> fieldToValue = new LinkedHashMap<Field, List<String>>();
157
158       wortart = wortart.replaceAll("===", "");
159       wortart = WORTART.matcher(wortart).replaceAll("$1");
160       wortart = GENDER.matcher(wortart).replaceAll("{$1}");
161       wortart = WIKI_DOUBLE_BRACE.matcher(wortart).replaceAll("$1");
162       wortart = wortart.replaceAll("Wortart\\|", "");
163       wortart = wortart.trim();
164       fieldToValue.put(Field.Wortart, Collections.singletonList(wortart));
165
166       String aussprache = StringUtil
167           .remove(section, AUSSPRACHE, NEWLINE, false);
168       if (aussprache != null) {
169         aussprache = AUSSPRACHE.matcher(aussprache).replaceFirst("");
170         aussprache = WIKI_DOUBLE_BRACE.matcher(aussprache).replaceAll("$1");
171         aussprache = aussprache.replaceAll("Lautschrift\\|ˈ?", "");
172         aussprache = aussprache.trim();
173         fieldToValue.put(Field.Aussprache, Collections
174             .singletonList(aussprache));
175       }
176
177       for (final Field field : Field.values()) {
178         if (field.listPattern != null) {
179           fieldToValue.put(field, extractList(section, field.listPattern));
180         }
181       }
182
183       System.out.println(titleBuilder);
184       for (final Field field : Field.values()) {
185         if (!fieldToValue.containsKey(field) || fieldToValue.get(field).isEmpty()) {
186           fieldToValue.remove(field);
187         } else {
188           if (field.name != null) {
189 //            System.out.println(field.name);
190 //            for (final String line : fieldToValue.get(field)) {
191 //              System.out.println("  " + line);
192 //            }
193           }
194         }
195       }
196 //      System.out.println("WHAT'S LEFT:");
197 //      System.out.println(section);
198 //      System.out.println("------------------------------------------------");
199
200     }
201
202   }
203
204   private List<String> extractList(final StringBuilder section,
205       final Pattern start) {
206     final List<String> result = new ArrayList<String>();
207     final String linesString = StringUtil.remove(section, start,
208         WIKI_NEW_SECTION, false);
209     if (linesString != null) {
210       String[] lines = linesString.split("\n");
211       for (int i = 1; i < lines.length; ++i) {
212         String bedeutung = lines[i];
213         bedeutung = bedeutung.replaceFirst("^:+", "");
214         bedeutung = bedeutung.trim();
215         if (bedeutung.length() > 0) {
216           result.add(bedeutung);
217         }
218       }
219     }
220     return result;
221   }
222
223   void parse(final File file) throws ParserConfigurationException,
224       SAXException, IOException {
225     final SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
226     parser.parse(file, this);
227     System.out.println(errorCounts);
228   }
229
230 }