JSP/Servletのお勉強メモ その11

昨日にひきつづき, テキストエリアへの文章入力で特定のHTMLタグ郡のみを反映させるのをやってる.
タグを許可してるはてなではどうなってんだろう?
今度実験してみよう.


とりあえず, こんなのを.
はてなで利用できるタグ一覧

                                                                                                                      • -

はてなダイアリーのヘルプ - はてなダイアリー利用可能タグ
http://hatenadiary.g.hatena.ne.jp/keyword/%e3%81%af%e3%81%a6%e3%81%aa%e3%83%80%e3%82%a4%e3%82%a2%e3%83%aa%e3%83%bc%e5%88%a9%e7%94%a8%e5%8f%af%e8%83%bd%e3%82%bf%e3%82%b0

                                                                                                                      • -

けっこう, つーか, かなり多い.
びっくりした. formとかも使えるなんて.


昨日書いたものを見直してみて, ビックリするくらいバグだらけだったということに気付く.
まいったまいった.
ちょっと(というか, かなり)修正.

package test.textarea;

import java.util.*;

public class ProcessInputData
{
    private String input;       // 入力文字列

    private StringBuffer output; // 出力文字列

    private static Hashtable<String, Integer> map = new Hashtable<String, Integer>();

    // コンストラクタ
    public ProcessInputData(){}

    public ProcessInputData( String input )
    {
        this.input  = input + '\n'; // 念のため, 文末に改行をつけておく.
        this.output = new StringBuffer();
    }

    public String getOutputString(){ return output.toString(); }

    // タグであれば0以上の値が, そうでなければ, 0が返戻される.
    private int getTagLength( int start )
    {
        int     check = 0;      // 検証した文字数
        int       tag = -1;     // タグならば, 0以上の値をとる

        char c;   // 一時保存用

        // 最大の長さのタグ, BLOCKQUOTEが10のため, 10個先まで検証.
        for( int i=1; i<11; i++ ){

            // 次の文字が改行, また, 空白だったならば, 終了.
            c = input.charAt( start+i-1 );
            if( c == '\n' || c == ' ' ){ return 0; }

            try{
                // <BLOCKQUOTE .... だったならば, BLOCKQUOTEの部分と一致するかどうか.
                tag = map.get( input.substring( start, start+i ).toUpperCase() );
            } catch( NullPointerException e ){
                // Hashtableに登録されていなかった.
                tag = -1;
            }

            if( tag > 0 ){
                c = input.charAt( start+i );
                if( c == ' ' || c == '>' ){
                    check = i;
                    break;
                }
                tag = -1;
            } else if ( tag == 0 ){
                // コメントだったならば,
                check = i;
                break;
            }
        }

        // 行末までに終端タグがあるかどうかを調べる
        if( check > 0 ){
            // ここで"c"が指すものは, ' ', '>'のどちらかのハズ(コメントを除いて).
            c = input.charAt( start+check );
            for( ; c!='>'; check++ ){
                if( c == '\n' ){ return 0; }
                // ここで"c"が指すものは, ' ', '>'のどちらかのハズ(コメントを除いて).
                c = input.charAt( start+check );
            }
        }

        return check;
    }

    public void processString()
    {
        int     count = 0;              // 入力文字列において読み込んだ文字数
        int     slash = 1;              // 終端タグにつく'/'の分の文字数+1(1が'/'なし, 2が'/'あり)
        int    length = input.length(); // 入力文字列の長さ
        int taglength = 0;              // タグの長さ

        char c;                 // 現在読み込んでいる文字

        for( count=0; count<length; ++count ){
            c = input.charAt(count);
            switch(c){
            case  '&':
                output.append( "&amp;" );
                break;
            case  '>':
                output.append( "&gt;" );
                break;
            case  '<':
                if( input.charAt( count+1 ) == '/' ){ slash = 2; }
                // slashは最低でも1.
                // '<', '</'の次の文字を指すようにするため.
                taglength = getTagLength( count+slash );
                if( taglength > 0 ){
                    // 第2引数で+1としているのは,
                    // substringが書き込む文字列の最終文字の次を指定しなければならないため.
                    output.append( input.substring( count, count+slash+taglength+1 ) );
                    count += slash+taglength; // 読み込んだ文字数を更新
                    // 初期状態に戻しておく
                    taglength = 0;
                } else {
                    output.append( "&lt;" );
                }
                slash = 1;      // 必ずslash=1に戻す
                break;
            case  ' ':
                output.append( "&nbsp;");
                break;
            case '\"':
                output.append( "&quot;" );
                break;
            case '\'':
                output.append( "&#39;" );
                break;
            case '\t':
                output.append( "&nbsp;&nbsp;&nbsp;&nbsp;" ); // タグは空白4つ
                break;
            case '\n':
                output.append( "\n" );
                break;
            default:
                output.append(c);
                break;
            }
        }
    }

    // オブジェクト作成時, 自動で実行される.
    static {
        fillMap();
    }

    private static void setTag(String k, Integer v)
    {
        map.put( k, v );
    }

    // 値が無い場合はNullPointerExceptionを返す
    private static void fillMap()
    {
        setTag(        "!--",  0 );
        setTag(         "H1",  1 );
        setTag(         "H2",  2 );
        setTag(         "H3",  3 );
        setTag(         "H4",  4 );
        setTag(         "H5",  5 );
        setTag(         "H6",  6 );
        setTag(       "FONT",  7 );
        setTag(   "BASEFONT",  8 );
        setTag(        "BIG",  9 );
        setTag(      "SMALL", 10 );
        setTag(          "B", 11 );
        setTag(          "I", 12 );
        setTag(          "U", 13 );
        setTag(          "S", 14 );
        setTag(         "TT", 15 );
        setTag(        "SUP", 16 );
        setTag(        "SUB", 17 );
        setTag(      "BLINK", 18 );
        setTag(          "P", 19 );
        setTag(         "BR", 20 );
        setTag(         "HR", 21 );
        setTag(     "CENTER", 22 );
        setTag(        "DIV", 23 );
        setTag( "BLOCKQUOTE", 24 );
        setTag(        "PRE", 25 );
        setTag(        "XMP", 26 );
        setTag(       "NOBR", 27 );
        setTag(        "WBR", 28 );
        setTag(   "MULTICOL", 29 );
        setTag(     "SPACER", 30 );
        setTag(         "UL", 31 );
        setTag(         "OL", 32 );
        setTag(         "LI", 33 );
        setTag(         "DL", 34 );
        setTag(         "DT", 35 );
        setTag(         "DD", 36 );
        setTag(          "A", 37 );
        setTag(      "TABLE", 38 );
        setTag(         "TR", 39 );
        setTag(         "TD", 40 );
        setTag(         "TH", 41 );
        setTag(    "CAPTION", 42 );
        setTag(        "IMG", 43 );
        setTag(        "MAP", 44 );
        setTag(       "AREA", 45 );
    }
}

で, こんなテストプログラムを組んでみる.

package test.textarea;

import test.textarea.ProcessInputData;

public class ProcessInputDataTest
{
    public static void main(String[] argv)
    {
        String input  = "てすと<i>てすと</i>\"日本語よ\"" + "\n"
            + "\'かなーり問題\'ぱやぱや<html>びろーん</html>" + "\n"
            + "<big>やれやれ</big>うーん<b>えっ</b>" + "\n"
            + "<!--あらあら-->うふふ<big" + "\n";

        ProcessInputData test = new ProcessInputData( input );

        test.processString();
        String output = test.getOutputString();

        System.out.println( "--------------------------------------------------------------------------------"  );
        System.out.println( "入力データ"  );
        System.out.println( "--------------------------------------------------------------------------------"  );
        System.out.println( input  );
        System.out.println( "--------------------------------------------------------------------------------"  );
        System.out.println( "出力データ"  );
        System.out.println( "--------------------------------------------------------------------------------"  );
        System.out.println( output );
        System.out.println( "--------------------------------------------------------------------------------"  );
    }
}

それで結果はこう.

$ java test/textarea/ProcessInputDataTest
--------------------------------------------------------------------------------
入力データ
--------------------------------------------------------------------------------
てすと<i>てすと</i>"日本語よ"
'かなーり問題'ぱやぱや<html>びろーん</html>
<big>やれやれ</big>うーん<b>えっ</b>
<!--あらあら-->うふふ<big

--------------------------------------------------------------------------------
出力データ
--------------------------------------------------------------------------------
てすと<i>てすと</i>&quot;日本語よ&quot;
&#39;かなーり問題&#39;ぱやぱや&lt;html&gt;びろーん&lt;/html&gt;
<big>やれやれ</big>うーん<b>えっ</b>
<!--あらあら-->うふふ&lt;big


--------------------------------------------------------------------------------

昨日のソースにくらべれば100倍はましなはず.
もっとテストしないと.
色々なまずいパターンが考えられそう.
あと, ソースがそんなに綺麗じゃないのが気になる.
まあ, それはおいおい直していきますか.