fork download
  1. import java.util.ArrayList;
  2. import java.util.HashSet;
  3. import java.util.Stack;
  4. import java.lang.StringBuilder;
  5. import java.util.regex.Pattern;
  6. import java.util.regex.Matcher;
  7.  
  8. class Main
  9. {
  10.  
  11. public static class BBCode {
  12. public final boolean closing;
  13. public final String tag;
  14. public final String param;
  15.  
  16. private BBCode(String tag, String param, boolean closing) {
  17. this.tag = tag;
  18. this.closing = closing;
  19. this.param = param;
  20. }
  21.  
  22. public String toString() {
  23. if (this.closing)
  24. return "[/" + this.tag + "]";
  25. if (this.param != null)
  26. return "[" + this.tag + "=" + this.param + "]";
  27. return "[" + this.tag + "]";
  28. }
  29.  
  30. private static Pattern openingPattern = Pattern.compile("([a-z]+)");
  31. private static Pattern openingPatternWithParam = Pattern.compile("([a-z]+)=(.*?)");
  32. private static Pattern closingPattern = Pattern.compile("/([a-z]+)");
  33.  
  34. public static BBCode valueOf(String s)
  35. {
  36. Matcher m = openingPattern.matcher(s);
  37. if (m.matches())
  38. return new BBCode(m.group(1), null, false);
  39.  
  40. m = openingPatternWithParam.matcher(s);
  41. if (m.matches())
  42. return new BBCode(m.group(1), m.group(2), false);
  43.  
  44. m = closingPattern.matcher(s);
  45. if (m.matches())
  46. return new BBCode(m.group(1), null, true);
  47.  
  48. return null;
  49. }
  50. }
  51.  
  52.  
  53. public static class Node {
  54.  
  55. public void render(StringBuilder buf) {
  56. }
  57.  
  58. }
  59.  
  60. public static class TextNode extends Node {
  61.  
  62. private String text;
  63.  
  64. TextNode(String text) {
  65. this.text = text;
  66. }
  67.  
  68. public void render(StringBuilder buf) {
  69. buf.append(this.text);
  70. }
  71.  
  72. }
  73.  
  74. public static class ContainerNode extends Node {
  75.  
  76. protected ArrayList<Node> children = new ArrayList<Node>();
  77.  
  78. public void add(Node node) {
  79. this.children.add(node);
  80. }
  81.  
  82. public void remove(Node node) {
  83. children.remove(node);
  84. }
  85.  
  86. public void render(StringBuilder buf) {
  87. renderChildren(buf);
  88. }
  89.  
  90. protected void renderChildren(StringBuilder buf) {
  91. for (Node node : this.children)
  92. node.render(buf);
  93. }
  94.  
  95. }
  96.  
  97. public static class RootNode extends ContainerNode
  98. {
  99. }
  100.  
  101. public static class BBCodeNode extends ContainerNode
  102. {
  103.  
  104. protected BBCode bbcode;
  105.  
  106. public BBCodeNode(BBCode bbcode) {
  107. this.bbcode = bbcode;
  108. }
  109.  
  110. public boolean isSameTag(BBCode bbcode) {
  111. return this.bbcode.tag.equals(bbcode.tag);
  112. }
  113.  
  114. public void flushTo(ContainerNode target) {
  115. target.add(new TextNode(this.bbcode.toString()));
  116. for (Node node : this.children)
  117. target.add(node);
  118. }
  119.  
  120. public void render(StringBuilder buf) {
  121. buf.append("<");
  122. buf.append(this.bbcode.tag);
  123. buf.append(">");
  124. renderChildren(buf);
  125. buf.append("</");
  126. buf.append(this.bbcode.tag);
  127. buf.append(">");
  128. }
  129.  
  130. }
  131.  
  132. public static class ColorNode extends BBCodeNode {
  133.  
  134. public ColorNode(BBCode t) {
  135. super(t);
  136. }
  137.  
  138. public void render(StringBuilder buf) {
  139. buf.append("<span style='color:");
  140. buf.append(bbcode.param);
  141. buf.append("'>");
  142. renderChildren(buf);
  143. buf.append("</span>");
  144. }
  145.  
  146. }
  147.  
  148.  
  149. public static class BBCodeNodeFactory {
  150.  
  151. private static HashSet<String> simpleCodes = new HashSet<String>();
  152. static {
  153. simpleCodes.add("b");
  154. simpleCodes.add("i");
  155. simpleCodes.add("s");
  156. simpleCodes.add("u");
  157. }
  158.  
  159. public static BBCodeNode createNode(BBCode bbcode) {
  160. if (simpleCodes.contains(bbcode.tag))
  161. return new BBCodeNode(bbcode);
  162. if ("color".equals(bbcode.tag))
  163. return new ColorNode(bbcode);
  164. return null;
  165. }
  166.  
  167. }
  168.  
  169.  
  170. public static class BBCodeProcessor {
  171.  
  172. public static String process(String input) {
  173. BBCodeProcessor processor = new BBCodeProcessor();
  174. processor.parse(input);
  175. StringBuilder buf = new StringBuilder();
  176. processor.render(buf);
  177. return buf.toString();
  178. }
  179.  
  180. private Stack<ContainerNode> stack = new Stack<ContainerNode>();
  181. private ContainerNode top = new RootNode();
  182.  
  183. private void parse(String s) {
  184. int len = s.length(), start = 0, i = 0;
  185.  
  186. while (i < len) {
  187.  
  188. int b = s.indexOf("[", i);
  189. if (b == -1)
  190. break;
  191.  
  192. int e = s.indexOf("]", b+1);
  193. if (e == -1)
  194. break;
  195.  
  196. BBCode bbcode = BBCode.valueOf(s.substring(b+1, e));
  197. if (bbcode != null) {
  198. if (start < b)
  199. handleText(s.substring(start, b));
  200. handleBBCode(bbcode);
  201. i = start = e+1;
  202. } else {
  203. i = b+1;
  204. }
  205. }
  206.  
  207. if (start < len)
  208. handleText(s.substring(start));
  209.  
  210. handleEnd();
  211. }
  212.  
  213. private void handleText(String text) {
  214. top.add(new TextNode(text));
  215. }
  216.  
  217. private void handleBBCode(BBCode bbcode) {
  218. if (bbcode.closing)
  219. handleClosing(bbcode);
  220. else
  221. handleOpening(bbcode);
  222. }
  223.  
  224. private void handleOpening(BBCode bbcode) {
  225. BBCodeNode node = BBCodeNodeFactory.createNode(bbcode);
  226. if (node == null) {
  227. handleText(bbcode.toString());
  228. } else {
  229. stack.push(top);
  230. top = node;
  231. }
  232. }
  233.  
  234. private void handleClosing(BBCode bbcode) {
  235. while (!stack.isEmpty()) {
  236. BBCodeNode top = (BBCodeNode)this.top;
  237. ContainerNode node = stack.pop();
  238. this.top = node;
  239. if (top.isSameTag(bbcode)) {
  240. node.add(top);
  241. this.top = node;
  242. return;
  243. }
  244. top.flushTo(node);
  245. }
  246. top.add(new TextNode(bbcode.toString()));
  247. }
  248.  
  249. private void handleEnd() {
  250. while (!stack.isEmpty()) {
  251. ContainerNode node = stack.pop();
  252. ((BBCodeNode)top).flushTo(node);
  253. top = node;
  254. }
  255. }
  256.  
  257. private void render(StringBuilder buf)
  258. {
  259. top.render(buf);
  260. }
  261.  
  262. }
  263.  
  264.  
  265. public static void main(String args[]) {
  266. java.io.BufferedReader r = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
  267. String s;
  268. try {
  269. while ((s = r.readLine()) != null) {
  270. System.out.println(s + " -> " + BBCodeProcessor.process(s));
  271. }
  272. } catch (Exception e) {
  273. }
  274. }
  275.  
  276. }
  277.  
Success #stdin #stdout 0.03s 245760KB
stdin
broken ta[gs handling
mixed [b]bold [i]and[/b] italic[/i]
some code [b]a[i] = 2[/b]
dsd[i]dasdas[b]dasdas[/b]dsadas[/i]dasdas
[color=blue][u]http://t...content-available-to-author-only...t.com[/u][/color]
[color=green]a[i]=c[b][/color]
stdout
broken ta[gs handling -> broken ta[gs handling
mixed [b]bold [i]and[/b] italic[/i] -> mixed <b>bold [i]and</b> italic[/i]
some code [b]a[i] = 2[/b] -> some code <b>a[i] = 2</b>
dsd[i]dasdas[b]dasdas[/b]dsadas[/i]dasdas -> dsd<i>dasdas<b>dasdas</b>dsadas</i>dasdas
[color=blue][u]http://t...content-available-to-author-only...t.com[/u][/color] -> <span style='color:blue'><u>http://t...content-available-to-author-only...t.com</u></span>
[color=green]a[i]=c[b][/color] -> <span style='color:green'>a[i]=c[b]</span>