OSDN Git Service

Merge commit '2234b50cfbe7c86237086a3bf4e62397814a390e'
[jindolf/JinParser.git] / src / main / java / jp / sourceforge / jindolf / parser / TalkParser.java
index 8f97cf0..e9337d8 100644 (file)
-/*\r
- * talk-part parser\r
- *\r
- * Copyright(c) 2009 olyutorskii\r
- * $Id: TalkParser.java 1016 2010-03-16 11:31:30Z olyutorskii $\r
- */\r
-\r
-package jp.sourceforge.jindolf.parser;\r
-\r
-import java.util.regex.Pattern;\r
-import jp.sourceforge.jindolf.corelib.TalkType;\r
-\r
-/**\r
- * 人狼BBSシステムが出力する各発言箇所のパーサ。\r
- * パース進行に従い{@link TalkHandler}の各種メソッドが呼び出される。\r
- */\r
-public class TalkParser extends AbstractParser{\r
-\r
-    private TalkHandler talkHandler;\r
-\r
-    private final SeqRange rangepool_1 = new SeqRange();\r
-\r
-    /**\r
-     * コンストラクタ。\r
-     * @param parent 親パーサ\r
-     */\r
-    public TalkParser(ChainedParser parent){\r
-        super(parent);\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * {@link TalkHandler}ハンドラを登録する。\r
-     * @param talkHandler ハンドラ\r
-     */\r
-    public void setTalkHandler(TalkHandler talkHandler){\r
-        this.talkHandler = talkHandler;\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * 各Avatarの個別の発言をパースする。\r
-     * 最初のAタグは既にパース済みとする。\r
-     * @param talkNo 白発言番号\r
-     * @param nameRange Aタグのname属性値の範囲\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    public void parseTalk(int talkNo, SeqRange nameRange)\r
-            throws HtmlParseException{\r
-        this.talkHandler.startTalk();\r
-\r
-        this.talkHandler.talkNo(talkNo);\r
-        this.talkHandler.talkId(getContent(), nameRange);\r
-\r
-        parseName();\r
-        parseTime();\r
-        parseIcon();\r
-        parseType();\r
-        parseText();\r
-        parseTail();\r
-\r
-        this.talkHandler.endTalk();\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern AVATARNAME_PATTERN =\r
-            compile("([^<]*)");\r
-\r
-    /**\r
-     * 発言者名をパースする。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseName() throws HtmlParseException{\r
-        setContextErrorMessage("lost dialog avatar-name");\r
-\r
-        SeqRange avatarRange = this.rangepool_1;\r
-\r
-        lookingAtAffirm(AVATARNAME_PATTERN);\r
-        avatarRange.setLastMatchedGroupRange(getMatcher(), 1);\r
-        shrinkRegion();\r
-\r
-        this.talkHandler.talkAvatar(getContent(), avatarRange);\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern TALKTIME_PATTERN =\r
-            compile(\r
-                 "</a>"\r
-                +SP_I\r
-                +"<span class=\"time\">"\r
-                +"(?:(午前\u0020)|(午後\u0020))?"\r
-                +"([0-9][0-9]?)(?:時\u0020|\\:)"\r
-                +"([0-9][0-9]?)分?\u0020"\r
-                +"</span>"\r
-                +SP_I\r
-                +"<table\u0020[^>]*>"\r
-                +SP_I\r
-                +"(?:<tbody>)?"\r
-                +SP_I\r
-                +"<tr>"\r
-            );\r
-\r
-    /**\r
-     * 発言時刻をパースする。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseTime() throws HtmlParseException{\r
-        setContextErrorMessage("lost dialog time");\r
-\r
-        lookingAtAffirm(TALKTIME_PATTERN);\r
-        int hour = parseGroupedInt(3);\r
-        int minute = parseGroupedInt(4);\r
-        if(isGroupMatched(2)){  // 午後指定\r
-            hour = (hour + 12) % 24;\r
-        }\r
-        shrinkRegion();\r
-        sweepSpace();\r
-\r
-        this.talkHandler.talkTime(hour, minute);\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern IMGSRC_PATTERN =\r
-            compile(\r
-                  "<td\u0020[^>]*><img\u0020src=\"([^\"]*)\"></td>"\r
-                 +SP_I\r
-                 +"<td\u0020[^>]*><img\u0020[^>]*></td>"\r
-            );\r
-\r
-    /**\r
-     * アイコンのURLをパースする。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseIcon() throws HtmlParseException{\r
-        setContextErrorMessage("lost icon url");\r
-\r
-        SeqRange urlRange = this.rangepool_1;\r
-\r
-        lookingAtAffirm(IMGSRC_PATTERN);\r
-        urlRange.setLastMatchedGroupRange(getMatcher(), 1);\r
-        shrinkRegion();\r
-        sweepSpace();\r
-\r
-        this.talkHandler.talkIconUrl(getContent(), urlRange);\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern TALKDIC_PATTERN =\r
-            compile(\r
-                 "<td>" +SP_I+ "<div(?:\u0020[^>]*)?>"\r
-                +SP_I\r
-                +"<div class=\"mes_"\r
-                +"(?:(say)|(think)|(whisper)|(groan))"\r
-                +"_body1\">"\r
-            );\r
-\r
-    /**\r
-     * 発言種別をパースする。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseType() throws HtmlParseException{\r
-        setContextErrorMessage("lost dialog type");\r
-\r
-        lookingAtAffirm(TALKDIC_PATTERN);\r
-        TalkType type;\r
-        if(isGroupMatched(1)){\r
-            type = TalkType.PUBLIC;\r
-        }else if(isGroupMatched(2)){\r
-            type = TalkType.PRIVATE;\r
-        }else if(isGroupMatched(3)){\r
-            type = TalkType.WOLFONLY;\r
-        }else if(isGroupMatched(4)){\r
-            type = TalkType.GRAVE;\r
-        }else{\r
-            assert false;\r
-            throw buildParseException();\r
-        }\r
-        shrinkRegion();\r
-\r
-        this.talkHandler.talkType(type);\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern TEXT_PATTERN =\r
-            compile("([^<>]+)|(<br />)|(<a href=\"[^\"]*\">)|(</a>)");\r
-\r
-    /**\r
-     * 発言テキストをパースする。\r
-     * 前後のホワイトスペースは無視しない。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseText() throws HtmlParseException{\r
-        setContextErrorMessage("lost dialog text");\r
-\r
-        SeqRange textRange = this.rangepool_1;\r
-\r
-        while(lookingAtProbe(TEXT_PATTERN)){\r
-            if(isGroupMatched(1)){\r
-                textRange.setLastMatchedGroupRange(getMatcher(), 1);\r
-                this.talkHandler.talkText(getContent(), textRange);\r
-            }else if(isGroupMatched(2)){      // <br />\r
-                this.talkHandler.talkBreak();\r
-            }else if(isGroupMatched(3)){      // <a>\r
-                // IGNORE\r
-                assert true;\r
-            }else if(isGroupMatched(4)){      // </a>\r
-                // IGNORE\r
-                assert true;\r
-            }else{\r
-                assert false;\r
-                throw buildParseException();\r
-            }\r
-            shrinkRegion();\r
-        }\r
-\r
-        return;\r
-    }\r
-\r
-    private static final Pattern TAIL_PATTERN =\r
-            compile(\r
-                       "</div>"  // F1603 2d21:12 ペーター発言には注意\r
-                +SP_I+ "</div>"\r
-                +SP_I+ "</td>"\r
-                +SP_I+ "</tr>"\r
-                +SP_I+ "(?:</tbody>)?"\r
-                +SP_I+ "</table>"\r
-            );\r
-\r
-    /**\r
-     * 発言末尾をパースする。\r
-     * @throws HtmlParseException パースエラー\r
-     */\r
-    private void parseTail() throws HtmlParseException{\r
-        setContextErrorMessage("lost dialog termination");\r
-\r
-        lookingAtAffirm(TAIL_PATTERN);\r
-        shrinkRegion();\r
-        sweepSpace();\r
-\r
-        return;\r
-    }\r
-\r
-}\r
+/*
+ * talk-part parser
+ *
+ * License : The MIT License
+ * Copyright(c) 2009 olyutorskii
+ */
+
+package jp.sourceforge.jindolf.parser;
+
+import java.util.regex.Pattern;
+import jp.sourceforge.jindolf.corelib.TalkType;
+
+/**
+ * 人狼BBSシステムが出力する各発言箇所のパーサ。
+ * パース進行に従い{@link TalkHandler}の各種メソッドが呼び出される。
+ */
+public class TalkParser extends AbstractParser{
+
+    private TalkHandler talkHandler;
+
+    private final SeqRange rangepool_1 = new SeqRange();
+
+    /**
+     * コンストラクタ。
+     * @param parent 親パーサ
+     */
+    public TalkParser(ChainedParser parent){
+        super(parent);
+        return;
+    }
+
+    /**
+     * {@link TalkHandler}ハンドラを登録する。
+     * @param talkHandler ハンドラ
+     */
+    public void setTalkHandler(TalkHandler talkHandler){
+        this.talkHandler = talkHandler;
+        return;
+    }
+
+    /**
+     * 各Avatarの個別の発言をパースする。
+     * 最初のAタグは既にパース済みとする。
+     * @param talkNo 白発言番号
+     * @param nameRange Aタグのname属性値の範囲
+     * @throws HtmlParseException パースエラー
+     */
+    public void parseTalk(int talkNo, SeqRange nameRange)
+            throws HtmlParseException{
+        this.talkHandler.startTalk();
+
+        this.talkHandler.talkNo(talkNo);
+        this.talkHandler.talkId(getContent(), nameRange);
+
+        parseName();
+        parseTime();
+        parseIcon();
+        parseType();
+        parseText();
+        parseTail();
+
+        this.talkHandler.endTalk();
+
+        return;
+    }
+
+    private static final Pattern AVATARNAME_PATTERN =
+            compile("([^<]*)");
+
+    /**
+     * 発言者名をパースする。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseName() throws HtmlParseException{
+        setContextErrorMessage("lost dialog avatar-name");
+
+        SeqRange avatarRange = this.rangepool_1;
+
+        lookingAtAffirm(AVATARNAME_PATTERN);
+        avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
+        shrinkRegion();
+
+        this.talkHandler.talkAvatar(getContent(), avatarRange);
+
+        return;
+    }
+
+    private static final Pattern TALKTIME_PATTERN =
+            compile(
+                 "</a>"
+                +SP_I
+                +"<span class=\"time\">"
+                +"(?:(午前\u0020)|(午後\u0020))?"
+                +"([0-9][0-9]?)(?:時\u0020|\\:)"
+                +"([0-9][0-9]?)分?\u0020"
+                +"</span>"
+                +SP_I
+                +"<table\u0020[^>]*>"
+                +SP_I
+                +"(?:<tbody>)?"
+                +SP_I
+                +"<tr>"
+            );
+
+    /**
+     * 発言時刻をパースする。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseTime() throws HtmlParseException{
+        setContextErrorMessage("lost dialog time");
+
+        lookingAtAffirm(TALKTIME_PATTERN);
+        int hour = parseGroupedInt(3);
+        int minute = parseGroupedInt(4);
+        if(isGroupMatched(2)){  // 午後指定
+            hour = (hour + 12) % 24;
+        }
+        shrinkRegion();
+        sweepSpace();
+
+        this.talkHandler.talkTime(hour, minute);
+
+        return;
+    }
+
+    private static final Pattern IMGSRC_PATTERN =
+            compile(
+                  "<td\u0020[^>]*><img\u0020src=\"([^\"]*)\"></td>"
+                 +SP_I
+                 +"<td\u0020[^>]*><img\u0020[^>]*></td>"
+            );
+
+    /**
+     * アイコンのURLをパースする。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseIcon() throws HtmlParseException{
+        setContextErrorMessage("lost icon url");
+
+        SeqRange urlRange = this.rangepool_1;
+
+        lookingAtAffirm(IMGSRC_PATTERN);
+        urlRange.setLastMatchedGroupRange(getMatcher(), 1);
+        shrinkRegion();
+        sweepSpace();
+
+        this.talkHandler.talkIconUrl(getContent(), urlRange);
+
+        return;
+    }
+
+    private static final Pattern TALKDIC_PATTERN =
+            compile(
+                 "<td>" +SP_I+ "<div(?:\u0020[^>]*)?>"
+                +SP_I
+                +"<div class=\"mes_"
+                +"(?:(say)|(think)|(whisper)|(groan))"
+                +"_body1\">"
+            );
+
+    /**
+     * 発言種別をパースする。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseType() throws HtmlParseException{
+        setContextErrorMessage("lost dialog type");
+
+        lookingAtAffirm(TALKDIC_PATTERN);
+        TalkType type;
+        if(isGroupMatched(1)){
+            type = TalkType.PUBLIC;
+        }else if(isGroupMatched(2)){
+            type = TalkType.PRIVATE;
+        }else if(isGroupMatched(3)){
+            type = TalkType.WOLFONLY;
+        }else if(isGroupMatched(4)){
+            type = TalkType.GRAVE;
+        }else{
+            assert false;
+            throw buildParseException();
+        }
+        shrinkRegion();
+
+        this.talkHandler.talkType(type);
+
+        return;
+    }
+
+    private static final Pattern TEXT_PATTERN =
+            compile("([^<>]+)|(<br />)|(<a href=\"[^\"]*\">)|(</a>)");
+
+    /**
+     * 発言テキストをパースする。
+     * 前後のホワイトスペースは無視しない。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseText() throws HtmlParseException{
+        setContextErrorMessage("lost dialog text");
+
+        SeqRange textRange = this.rangepool_1;
+
+        while(lookingAtProbe(TEXT_PATTERN)){
+            if(isGroupMatched(1)){
+                textRange.setLastMatchedGroupRange(getMatcher(), 1);
+                this.talkHandler.talkText(getContent(), textRange);
+            }else if(isGroupMatched(2)){      // <br />
+                this.talkHandler.talkBreak();
+            }else if(isGroupMatched(3)){      // <a>
+                // IGNORE
+                assert true;
+            }else if(isGroupMatched(4)){      // </a>
+                // IGNORE
+                assert true;
+            }else{
+                assert false;
+                throw buildParseException();
+            }
+            shrinkRegion();
+        }
+
+        return;
+    }
+
+    private static final Pattern TAIL_PATTERN =
+            compile(
+                       "</div>"  // F1603 2d21:12 ペーター発言には注意
+                +SP_I+ "</div>"
+                +SP_I+ "</td>"
+                +SP_I+ "</tr>"
+                +SP_I+ "(?:</tbody>)?"
+                +SP_I+ "</table>"
+            );
+
+    /**
+     * 発言末尾をパースする。
+     * @throws HtmlParseException パースエラー
+     */
+    private void parseTail() throws HtmlParseException{
+        setContextErrorMessage("lost dialog termination");
+
+        lookingAtAffirm(TAIL_PATTERN);
+        shrinkRegion();
+        sweepSpace();
+
+        return;
+    }
+
+}