1 package com.hughes.android.dictionary.parser;
3 import java.util.ArrayList;
4 import java.util.LinkedHashMap;
7 import java.util.regex.Matcher;
8 import java.util.regex.Pattern;
10 public class WikiParser {
12 private static final Pattern markup = Pattern.compile("$|''|\\{\\{|\\[\\[|(==+)\\s*$|<!--|<pre>", Pattern.MULTILINE);
13 private static final Pattern listStart = Pattern.compile("^[*#;:]+");
14 private static final Pattern pipeSplit = Pattern.compile("\\s*\\|\\s*");
15 private static final Pattern whitespace = Pattern.compile("\\s+");
16 private static final Pattern headerStart = Pattern.compile("^==+");
19 static void parse(final String wikiText, final WikiCallback callback) {
21 boolean boldOn = false;
22 boolean italicOn = false;
23 int insideHeaderDepth = -1;
24 String lastListItem = null;
26 final List<String> positionalArgs = new ArrayList<String>();
27 final Map<String, String> namedArgs = new LinkedHashMap<String, String>();
29 String rest = wikiText;
30 while (rest.length() > 0) {
31 final Matcher matcher = markup.matcher(rest);
33 final int nextMarkupPos = matcher.start();
34 if (nextMarkupPos != 0) {
35 String text = rest.substring(0, nextMarkupPos);
36 whitespace.matcher(text).replaceAll(" ");
37 callback.onText(text);
39 rest = rest.substring(nextMarkupPos);
41 if (rest.startsWith("\n")) {
42 rest = rest.substring(1);
44 if (insideHeaderDepth != -1) {
45 throw new RuntimeException("barf");
47 if (lastListItem != null) {
48 callback.onListItemEnd(lastListItem, null);
51 final Matcher headerMatcher = headerStart.matcher(rest);
52 if (headerMatcher.find()) {
53 insideHeaderDepth = headerMatcher.group().length();
54 callback.onHeadingStart(insideHeaderDepth);
55 rest = rest.substring(headerMatcher.group().length());
59 if (listStart.matcher(rest).find()) {
60 lastListItem = matcher.group();
61 callback.onListItemStart(lastListItem, null);
62 rest = rest.substring(lastListItem.length());
64 } else if (lastListItem != null) {
65 callback.onNewParagraph();
69 if (rest.startsWith("\n")) {
70 callback.onNewParagraph();
74 } else if (rest.startsWith("'''")) {
76 callback.onFormatBold(boldOn);
77 rest = rest.substring(3);
78 } else if (rest.startsWith("''")) {
80 callback.onFormatItalic(italicOn);
81 rest = rest.substring(2);
82 } else if (rest.startsWith("{{")) {
83 int end = rest.indexOf("}}");
85 callback.onUnterminated("{{", rest);
88 final String template = rest.substring(2, end).trim();
89 final String[] templateArray = pipeSplit.split(template);
90 positionalArgs.clear();
92 for (int i = 0; i < templateArray.length; ++i) {
93 int equalPos = templateArray[i].indexOf('=');
95 positionalArgs.add(templateArray[i]);
97 namedArgs.put(templateArray[i].substring(0, equalPos), templateArray[i].substring(equalPos + 1));
100 callback.onTemplate(positionalArgs, namedArgs);
101 rest = rest.substring(end + 2);
102 } else if (rest.startsWith("[[")) {
103 int end = rest.indexOf("]]");
105 callback.onUnterminated("[[", rest);
108 final String wikiLink = rest.substring(2, end);
109 final String[] args = pipeSplit.split(wikiLink);
110 callback.onWikiLink(args);
111 rest = rest.substring(end + 2);
112 } else if (rest.startsWith("=")) {
113 final String match = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
114 if (insideHeaderDepth == -1) {
116 if (match.length() != insideHeaderDepth) {
117 callback.onInvalidHeaderEnd(rest);
120 callback.onHeadingEnd(insideHeaderDepth);
121 insideHeaderDepth = -1;
123 rest = rest.substring(match.length());
124 } else if (rest.startsWith("<!--")) {
125 int end = rest.indexOf("-->");
127 callback.onUnterminated("<!--", rest);
130 callback.onComment(rest.substring(4, end));
131 rest = rest.substring(end + 3);
132 } else if (rest.startsWith("<pre>")) {
133 int end = rest.indexOf("</pre>");
135 callback.onUnterminated("<pre>", rest);
138 callback.onText(rest.substring(5, end));
139 rest = rest.substring(end + 6);
141 throw new RuntimeException("barf!");