4 * Copyright(c) 2009 olyutorskii
\r
5 * $Id: EntityConverter.java 894 2009-11-04 07:26:59Z olyutorskii $
\r
8 package jp.sourceforge.jindolf.parser;
\r
10 import java.util.regex.Matcher;
\r
11 import java.util.regex.Pattern;
\r
14 * 人狼BBSで用いられる4種類のXHTML文字実体参照の
\r
15 * 解決を伴う{@link DecodedContent}の切り出しを行う。
\r
16 * 文字実体参照は{@code > < " &}が対象。
\r
17 * U+005C(バックスラッシュ)をU+00A5(円通貨)に直す処理も行われる。
\r
18 * ※ 人狼BBSはShift_JIS(⊃JISX0201)で運営されているので、
\r
20 * ※ が、バックスラッシュを生成するShift_JISデコーダは存在する。
\r
23 public class EntityConverter{
\r
25 private static final String[][] XCHG_TABLE = {
\r
30 {"\u005c\u005c", "\u00a5"},
\r
33 private static final Pattern XCHG_PATTERN;
\r
36 StringBuilder regex = new StringBuilder();
\r
37 for(String[] xchg : XCHG_TABLE){
\r
38 String xchgFrom = xchg[0];
\r
39 if(regex.length() > 0) regex.append('|');
\r
41 .append(Pattern.quote(xchgFrom))
\r
43 assert xchgFrom.indexOf(DecodedContent.ALTCHAR) < 0;
\r
45 XCHG_PATTERN = Pattern.compile(regex.toString());
\r
48 private final Matcher matcher = XCHG_PATTERN.matcher("");
\r
53 public EntityConverter(){
\r
60 * @param content 変換元文書
\r
61 * @return 切り出された変換済み文書
\r
63 public DecodedContent convert(DecodedContent content){
\r
64 return append(null, content, 0, content.length());
\r
69 * @param content 変換元文書
\r
71 * @return 切り出された変換済み文書
\r
72 * @throws IndexOutOfBoundsException 位置指定に不正があった
\r
74 public DecodedContent convert(DecodedContent content, SeqRange range)
\r
75 throws IndexOutOfBoundsException{
\r
76 return append(null, content, range.getStartPos(), range.getEndPos());
\r
81 * @param content 変換元文書
\r
82 * @param startPos 開始位置
\r
83 * @param endPos 終了位置
\r
84 * @return 切り出された変換済み文書
\r
85 * @throws IndexOutOfBoundsException 位置指定に不正があった
\r
87 public DecodedContent convert(DecodedContent content,
\r
88 int startPos, int endPos)
\r
89 throws IndexOutOfBoundsException{
\r
90 return append(null, content, startPos, endPos);
\r
94 * 実体参照の変換を行い既存のDecodedContentに追加を行う。
\r
95 * @param target 追加先文書。nullなら新たな文書が用意される。
\r
96 * @param content 変換元文書
\r
97 * @return targetもしくは新規に用意された文書
\r
98 * @throws IndexOutOfBoundsException 位置指定に不正があった
\r
100 public DecodedContent append(DecodedContent target,
\r
101 DecodedContent content)
\r
102 throws IndexOutOfBoundsException{
\r
103 return append(target, content, 0, content.length());
\r
107 * 実体参照の変換を行い既存のDecodedContentに追加を行う。
\r
108 * @param target 追加先文書。nullなら新たな文書が用意される。
\r
109 * @param content 変換元文書
\r
110 * @param range 範囲指定
\r
111 * @return targetもしくは新規に用意された文書
\r
112 * @throws IndexOutOfBoundsException 位置指定に不正があった
\r
114 public DecodedContent append(DecodedContent target,
\r
115 DecodedContent content,
\r
117 throws IndexOutOfBoundsException{
\r
118 return append(target, content,
\r
119 range.getStartPos(), range.getEndPos());
\r
123 * 実体参照の変換を行い既存のDecodedContentに追加を行う。
\r
124 * @param target 追加先文書。nullなら新たな文書が用意される。
\r
125 * @param content 変換元文書
\r
126 * @param startPos 開始位置
\r
127 * @param endPos 終了位置
\r
128 * @return targetもしくは新規に用意された文書
\r
129 * @throws IndexOutOfBoundsException 位置指定に不正があった
\r
131 public DecodedContent append(DecodedContent target,
\r
132 DecodedContent content,
\r
133 int startPos, int endPos)
\r
134 throws IndexOutOfBoundsException{
\r
135 if( startPos > endPos
\r
137 || content.length() < endPos){
\r
138 throw new IndexOutOfBoundsException();
\r
141 DecodedContent result;
\r
142 if(target == null){
\r
143 result = new DecodedContent(endPos - startPos);
\r
148 this.matcher.reset(content.getRawContent());
\r
149 this.matcher.region(startPos, endPos);
\r
151 int lastPos = startPos;
\r
152 while(this.matcher.find()){
\r
154 int matchStart = -1;
\r
155 for(group = 1; group <= XCHG_TABLE.length; group++){
\r
156 matchStart = this.matcher.start(group);
\r
157 if(matchStart >= 0) break;
\r
159 int matchEnd = this.matcher.end(group);
\r
161 result.append(content, lastPos, matchStart);
\r
163 String toStr = XCHG_TABLE[group - 1][1];
\r
164 result.append(toStr);
\r
166 lastPos = matchEnd;
\r
168 result.append(content, lastPos, endPos);
\r
170 this.matcher.reset("");
\r