4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sourceforge.jindolf.parser;
10 import java.util.regex.Pattern;
11 import jp.sourceforge.jindolf.corelib.TalkType;
14 * 人狼BBSシステムが出力する各発言箇所のパーサ。
15 * パース進行に従い{@link TalkHandler}の各種メソッドが呼び出される。
17 @SuppressWarnings("PMD.FieldDeclarationsShouldBeAtStartOfClass")
18 public class TalkParser extends AbstractParser{
20 private TalkHandler talkHandler;
22 private final SeqRange rangepool_1 = new SeqRange();
28 public TalkParser(ChainedParser parent){
34 * {@link TalkHandler}ハンドラを登録する。
35 * @param talkHandler ハンドラ
37 public void setTalkHandler(TalkHandler talkHandler){
38 this.talkHandler = talkHandler;
43 * 各Avatarの個別の発言をパースする。
46 * @param nameRange Aタグのname属性値の範囲
47 * @throws HtmlParseException パースエラー
49 public void parseTalk(int talkNo, SeqRange nameRange)
50 throws HtmlParseException{
51 this.talkHandler.startTalk();
53 this.talkHandler.talkNo(talkNo);
54 this.talkHandler.talkId(getContent(), nameRange);
63 this.talkHandler.endTalk();
68 private static final Pattern AVATARNAME_PATTERN =
73 * @throws HtmlParseException パースエラー
75 private void parseName() throws HtmlParseException{
76 setContextErrorMessage("lost dialog avatar-name");
78 SeqRange avatarRange = this.rangepool_1;
80 lookingAtAffirm(AVATARNAME_PATTERN);
81 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
84 this.talkHandler.talkAvatar(getContent(), avatarRange);
89 private static final Pattern TALKTIME_PATTERN =
93 +"<span class=\"time\">"
94 +"(?:(午前\u0020)|(午後\u0020))?"
95 +"([0-9][0-9]?)(?:時\u0020|\\:)"
96 +"([0-9][0-9]?)分?\u0020"
108 * @throws HtmlParseException パースエラー
110 private void parseTime() throws HtmlParseException{
111 setContextErrorMessage("lost dialog time");
113 lookingAtAffirm(TALKTIME_PATTERN);
114 int hour = parseGroupedInt(3);
115 int minute = parseGroupedInt(4);
116 if(isGroupMatched(2)){ // 午後指定
117 hour = (hour + 12) % 24;
122 this.talkHandler.talkTime(hour, minute);
127 private static final Pattern IMGSRC_PATTERN =
129 "<td\u0020[^>]*><img\u0020src=\"([^\"]*)\"></td>"
131 +"<td\u0020[^>]*><img\u0020[^>]*></td>"
136 * @throws HtmlParseException パースエラー
138 private void parseIcon() throws HtmlParseException{
139 setContextErrorMessage("lost icon url");
141 SeqRange urlRange = this.rangepool_1;
143 lookingAtAffirm(IMGSRC_PATTERN);
144 urlRange.setLastMatchedGroupRange(getMatcher(), 1);
148 this.talkHandler.talkIconUrl(getContent(), urlRange);
153 private static final Pattern TALKDIC_PATTERN =
155 "<td>" +SP_I+ "<div(?:\u0020[^>]*)?>"
158 +"(?:(say)|(think)|(whisper)|(groan))"
164 * @throws HtmlParseException パースエラー
166 private void parseType() throws HtmlParseException{
167 setContextErrorMessage("lost dialog type");
169 lookingAtAffirm(TALKDIC_PATTERN);
171 if(isGroupMatched(1)){
172 type = TalkType.PUBLIC;
173 }else if(isGroupMatched(2)){
174 type = TalkType.PRIVATE;
175 }else if(isGroupMatched(3)){
176 type = TalkType.WOLFONLY;
177 }else if(isGroupMatched(4)){
178 type = TalkType.GRAVE;
181 throw buildParseException();
185 this.talkHandler.talkType(type);
190 private static final Pattern TEXT_PATTERN =
191 compile("([^<>]+)|(<br />)|(<a href=\"[^\"]*\">)|(</a>)");
196 * @throws HtmlParseException パースエラー
198 private void parseText() throws HtmlParseException{
199 setContextErrorMessage("lost dialog text");
201 SeqRange textRange = this.rangepool_1;
203 while(lookingAtProbe(TEXT_PATTERN)){
204 if(isGroupMatched(1)){
205 textRange.setLastMatchedGroupRange(getMatcher(), 1);
206 this.talkHandler.talkText(getContent(), textRange);
207 }else if(isGroupMatched(2)){ // <br />
208 this.talkHandler.talkBreak();
209 }else if(isGroupMatched(3)){ // <a>
212 }else if(isGroupMatched(4)){ // </a>
217 throw buildParseException();
225 private static final Pattern TAIL_PATTERN =
227 "</div>" // F1603 2d21:12 ペーター発言には注意
231 +SP_I+ "(?:</tbody>)?"
237 * @throws HtmlParseException パースエラー
239 private void parseTail() throws HtmlParseException{
240 setContextErrorMessage("lost dialog termination");
242 lookingAtAffirm(TAIL_PATTERN);