    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.util;
    017
    018import java.awt.Color;
    019import java.io.PrintWriter;
    020import java.io.StringWriter;
    021import java.io.UnsupportedEncodingException;
    022import java.net.URLEncoder;
    023import java.net.URLDecoder;
    024import java.util.ArrayList;
    025import java.util.Arrays;
    026import java.util.Enumeration;
    027import java.util.HashMap;
    028import java.util.Iterator;
    029import java.util.Map;
    030import java.util.StringTokenizer;
    031import java.util.Locale ;                               // 5.7.2.3 (2014/01/31)
    032import java.nio.charset.Charset;                // 5.5.2.6 (2012/05/25)
    033
    034
    035/**
    036 * StringUtil.java は、共通的に使用される String関連メソッドを集約した、クラスです。
    037 *
    038 * @og.group ユーティリティ
    039 *
    040 * @version  4.0
    041 * @author       Kazuhiko Hasegawa
    042 * @since    JDK5.0,
    043 */
    044public final class StringUtil {
    045
    046        /** バッファの初期容量を通常より多い目に設定します。(200)  */
    047        private static final int BUFFER_MIDDLE = 200;
    048
    049        /** システム依存の改行記号をセットします。 */
    050        private static final String CR = System.getProperty("line.separator");
    051
    052        /**
    053         * プラットフォーム依存のデフォルトの Charset です。
    054         * プラットフォーム依存性を考慮する場合、エンコード指定で作成しておく事をお勧めします。
    055         *
    056         * @og.rev 5.5.2.6 (2012/05/25) findbugs対応
    057         */
    058        public static final Charset DEFAULT_CHARSET = Charset.defaultCharset() ;
    059
    060        /**
    061         * code39 のチェックデジット計算に使用する モジュラス４３ の変換表です。
    062         *
    063         */
    064        private static final String MODULUS_43 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" ;
    065
    066        /**
    067         * getUnicodeEscape で使用する桁合わせ用文字列配列です。
    068         * Unicodeの HexString 変換後の桁に応じて、埋め合わせします。
    069         *
    070         */
    071        private static final String[] UTF_STR = { "&#x0000", "&#x000", "&#x00", "&#x0", "&#x" };
    072
    073        // 4.0.3.0 (2007/12/26) 色コードにPURPLE を追加
    074        // 5.7.8.0 (2014/07/04) 透明追加
    075        private static final Map<String,Color> CLR_MAP;
    076        static {
    077                CLR_MAP = new HashMap<String,Color>();
    078                CLR_MAP.put( "BLACK"            ,Color.BLACK            );
    079                CLR_MAP.put( "BLUE"                     ,Color.BLUE                     );
    080                CLR_MAP.put( "CYAN"                     ,Color.CYAN                     );
    081                CLR_MAP.put( "DARK_GRAY"        ,Color.DARK_GRAY        );
    082                CLR_MAP.put( "GRAY"                     ,Color.GRAY                     );
    083                CLR_MAP.put( "GREEN"            ,Color.GREEN            );
    084                CLR_MAP.put( "LIGHT_GRAY"       ,Color.LIGHT_GRAY       );
    085                CLR_MAP.put( "MAGENTA"          ,Color.MAGENTA          );
    086                CLR_MAP.put( "ORANGE"           ,Color.ORANGE           );
    087                CLR_MAP.put( "PINK"                     ,Color.PINK                     );
    088                CLR_MAP.put( "RED"                      ,Color.RED                      );
    089                CLR_MAP.put( "WHITE"            ,Color.WHITE            );
    090                CLR_MAP.put( "YELLOW"           ,Color.YELLOW           );
    091                CLR_MAP.put( "PURPLE"           ,new Color( 8388736 )   );              // #800080
    092                CLR_MAP.put( "TRANSPARENT"      ,new Color( 255,255,255,0 )     );      // 5.7.8.0 (2014/07/04) 透明追加
    093        }
    094
    095        /**
    096         *      デフォルトコンストラクターをprivateにして、
    097         *      オブジェクトの生成をさせないようにする。
    098         *
    099         */
    100        private StringUtil() {}
    101
    102        /**
    103         * UTF-8 で、URLエンコードを行います。
    104         * このメソッドは、JDK1.4 以上でないと使用できません。
    105         *
    106         * @param       value エンコードする文字列
    107         *
    108         * @return       指定の文字コードでＵＲＬエンコードされた文字列
    109         */
    110        public static String urlEncode( final String value ) {
    111                if( value == null ) { return ""; }
    112
    113                try {
    114                        return URLEncoder.encode( value,"UTF-8" );
    115                }
    116                catch( UnsupportedEncodingException ex ) {
    117                        String errMsg = "UnsupportedEncodingException [UTF-8]" + CR
    118                                                + ex.getMessage() ;
    119                        throw new RuntimeException( errMsg,ex );
    120                }
    121                catch( RuntimeException ex2 ) {         // 3.6.0.0 (2004/09/17)
    122                        String errMsg = "予期せぬエラー value=[" + value + "] , encode=[UTF-8]" + CR
    123                                                + ex2.getMessage();
    124                        throw new RuntimeException( errMsg,ex2 );
    125                }
    126        }
    127
    128        /**
    129         * UTF-8 でURLエンコードされた文字列をデコードします。
    130         * このメソッドは、JDK1.4 以上でないと使用できません。
    131         *
    132         * @og.rev 5.4.5.0 追加
    133         * @param       value デコードする文字列
    134         *
    135         * @return       デコードされた文字列
    136         */
    137        public static String urlDecode( final String value ) {
    138                try {
    139                        return URLDecoder.decode( value,"UTF-8" );
    140                }
    141                catch( UnsupportedEncodingException ex ) {
    142                        String errMsg = "UnsupportedEncodingException [UTF-8]" + CR
    143                                                + ex.getMessage() ;
    144                        throw new RuntimeException( errMsg,ex );
    145                }
    146                catch( RuntimeException ex2 ) {         // 3.6.0.0 (2004/09/17)
    147                        String errMsg = "予期せぬエラー value=[" + value + "] , encode=[UTF-8]" + CR
    148                                                + ex2.getMessage();
    149                        throw new RuntimeException( errMsg,ex2 );
    150                }
    151        }
    152
    153        /**
    154         * 文字列の後ろのスペースを削除します。
    155         * String クラスの trim()メソッドは、文字列の両方のスペースを削除しますが、
    156         * この rTrim( String ) は、後ろの半角スペースのみ、詰めます。
    157         * 注意：'\u0020' (スペース文字) より小さい文字を切り取ります。
    158         *
    159         * @param       str 元の文字列
    160         *
    161         * @return      後ろの半角スペースを詰めた、新しい文字列
    162         */
    163        public static String rTrim( final String str ) {
    164                if( str == null )  { return null; }
    165                int count = str.length();
    166
    167                int len = count;
    168
    169                while ( 0 < len && str.charAt(len-1) <= ' ' ) {
    170                        len--;
    171                }
    172                return (len < count) ? str.substring(0, len) : str;
    173        }
    174
    175        /**
    176         * 文字列の後ろから、" .0" の文字を削除した数字型文字列を返します。
    177         * 数字型文字列は、入力文字列の後ろの スペース、小数点、ゼロを削除します。
    178         * また、先頭が、"." で始まる場合は、"0" を追加します。
    179         * 例: "123.00" ⇒ "123" , ".123" ⇒ "0.123"
    180         *
    181         * @og.rev 3.8.8.1 (2007/01/10) 新規作成
    182         *
    183         * @param       str 元の文字列
    184         *
    185         * @return      数字文字列化された、新しい文字列
    186         */
    187        public static String toNumber( final String str ) {
    188                if( str == null )  { return null; }
    189
    190                String rtn = str.trim() ;
    191
    192                int adrs = rtn.indexOf( '.' );
    193                int count = rtn.length();
    194                int len = count;
    195
    196                if( adrs >= 0 ) {
    197                        while ( adrs < len && ".0".indexOf( rtn.charAt(len-1) ) >= 0 ) {
    198                                len--;
    199                        }
    200                }
    201
    202                if( len < count ) { rtn = rtn.substring(0, len); }
    203                if( adrs == 0 ) { rtn = "0" + rtn; }
    204
    205                return rtn ;
    206        }
    207
    208        /**
    209         * 文字列の前方のゼロ(０)を削除します。
    210         * 先頭の０を削除するまえに、trim して、スペースを削除しておきます。
    211         *
    212         * @og.rev 3.5.4.5 (2004/01/23) 新規追加
    213         *
    214         * @param       in 元の文字列
    215         *
    216         * @return      前方のゼロ(０)を削除した、新しい文字列
    217         */
    218        public static String lTrim0( final String in ) {
    219                if( in == null )  { return null; }
    220                String str = in.trim();
    221                int count = str.length();
    222
    223                int len = 0;
    224
    225                while ( count > len && str.charAt(len) == '0' ) {
    226                        len++;
    227                }
    228
    229                if( len == 0 ) { return str; }                          // 先頭がゼロでない。
    230                else if( len == count ) { return "0"; }         // すべてがゼロ
    231                else if( str.charAt(len) == '.' ) { return "0" + str.substring(len); }
    232                else { return str.substring(len); }
    233        }
    234
    235        /**
    236         * 文字列配列の各要素の後ろのスペースを削除します。
    237         * 個々の配列要素に対して、rTrim( String str ) を適用します。
    238         * 元の文字列配列に直接作用するのではなく、新しい文字列配列に
    239         * 結果をコピーして返します。
    240         * ただし、元の文字列配列が、null か、length == 0 の場合は、
    241         * 元の文字列配列(アドレス)を返します。
    242         * 注意：'\u0020' (スペース文字) より小さい文字を切り取ります。
    243         *
    244         * @param       str 元の文字列
    245         *
    246         * @return      後ろの半角スペースを詰めた、新しい文字列
    247         */
    248        public static String[] rTrims( final String[] str ) {
    249                if( str == null || str.length == 0 ) { return str; }
    250
    251                String[] rtn = new String[ str.length ];
    252                for( int i=0; i<str.length; i++ ) {
    253                        rtn[i] = rTrim( str[i] );
    254                }
    255                return rtn ;
    256        }
    257
    258        /**
    259         * 文字列の前後のダブルクオートを取り外します。
    260         * 前後にダブルクオートが入っていなければ、そのままの文字列を返します。
    261         * 前後に入っていない(片方のみなど)場合も、そのままの文字列を返します。
    262         *
    263         * @param       str 元の文字列
    264         *
    265         * @return      ダブルクオートを取り外した新しい文字列
    266         */
    267        public static String csvOutQuote( final String str ) {
    268                if( str == null )  { return null; }
    269                int end = str.length();
    270
    271                if( end < 2 || str.charAt(0) != '"' || str.charAt( end-1 ) != '"' ) {
    272                        return str;
    273                }
    274
    275                return str.substring( 1,end-1 ) ;
    276        }
    277
    278        /**
    279         * 内部で使われる byte[] から String 生成 メソッド
    280         *
    281         * @param       byteValue        変換するバイト列
    282         * @param       start            変換開始アドレス
    283         * @param       length           変換バイト数
    284         * @param       encode           変換する文字エンコード
    285         *
    286         * @return      変換後文字列
    287         */
    288        public static String makeString( final byte[] byteValue, final int start, final int length,final String encode ) {
    289
    290                if( encode.startsWith( "Unicode" ) ) {
    291                        String errMsg = "Unicode文字列は、変換できません。[" + encode + "]"  + CR;
    292                        throw new RuntimeException( errMsg );
    293                }
    294
    295                String rtn = null;
    296                if( byteValue != null ) {
    297                        try {
    298                                // encode コードで変換されている byte[] を、String に変換。
    299                                rtn = new String( byteValue,start,length,encode );
    300                        } catch( UnsupportedEncodingException ex ) {      // 変換コードが存在しないエラー
    301                                String errMsg = "文字変換コードが存在しません。[" + encode + "]" + CR
    302                                                        + ex.getMessage() ;
    303                                throw new RuntimeException( errMsg,ex );
    304                        }
    305                }
    306                return rtn;
    307        }
    308
    309        /**
    310         * 指定の文字列をバイトコードに変換します。
    311         * 引数の文字列が null の場合は、return は、byte[0] を返します。
    312         *
    313         * @param       value    変換するストリング値
    314         * @param       encode   変換する文字エンコード
    315         *
    316         * @return      変換後文字列
    317         */
    318        public static byte[] makeByte( final String value,final String encode ) {
    319                byte[] rtnByte = new byte[0];
    320                if( value != null ) {
    321                        try {
    322                                rtnByte = value.getBytes( encode );             // byte[] に encode コードで変換。
    323                        } catch( UnsupportedEncodingException ex ) {      // 変換コードが存在しないエラー
    324                                String errMsg = "文字変換コードが存在しません。[" + encode + "]" + CR
    325                                                        + ex.getMessage();
    326                                throw new RuntimeException( errMsg,ex );
    327                        }
    328                }
    329                return rtnByte;
    330        }
    331
    332        /**
    333         * 半角スペースで固定長(半角換算の数)に変換した文字列を返します。
    334         * 半角スペース埋めは、文字が半角、全角混在でもかまいません。
    335         * 内部にセットした文字列は、変化しません。
    336         *
    337         * @param       str      Fill埋めする文字列
    338         * @param       su_fill  Fill埋めする文字列の長さ。(半角換算の数)
    339         *
    340         * @return      Fill埋めした新しいStringを返す。
    341         */
    342        public static String stringXFill( final String str,final int su_fill ) {
    343                char[] charValue ;
    344
    345                if( str == null ) { charValue = new char[0]; }
    346                else              { charValue = str.toCharArray(); }
    347                int len = charValue.length;
    348
    349                if( su_fill < len ) {
    350                        String errMsg = "元の文字数がフォームより長いです。(数字が壊れます。)"
    351                                        + "su_fill[" + su_fill + "], len[" + len + "]" + CR
    352                                        + "input=[" + str + "]" + CR;
    353                        throw new RuntimeException( errMsg );
    354                }
    355
    356                char[] charbuf = new char[ su_fill ];                   // 移す char 配列を新規作成
    357                Arrays.fill( charbuf,' ' );
    358                System.arraycopy( charValue,0,charbuf,0,len );
    359
    360                return new String( charbuf );            // コピーした配列全てを文字列に変換
    361        }
    362
    363        /**
    364         * 半角スペースで固定長(半角換算の数)に変換した文字列を返します。
    365         * 半角スペース埋めは、文字が半角、全角混在でもかまいません。
    366         * 内部にセットした文字列は、変化しません。
    367         *
    368         * @param       str      Fill埋めする文字列
    369         * @param       su_fill  Fill埋めする文字列の長さ。(半角換算の数)
    370         * @param       encode   Fill埋めする文字列の文字エンコード
    371         *
    372         * @return      Fill埋めした新しいStringを返す。
    373         */
    374        public static String stringFill( final String str,final int su_fill,final String encode ) {
    375                if( su_fill < 0 ) {
    376                        String errMsg = "指定文字数が負です。[" + su_fill + "]";
    377                        throw new RuntimeException( errMsg );
    378                }
    379
    380                byte[] byteValue = makeByte( str,encode );
    381                int len = byteValue.length;
    382
    383                // 内部文字列が指定長より長い場合
    384                if( len >= su_fill ) {
    385                        return makeString( byteValue,0,su_fill,encode );
    386                }
    387                else {
    388                        byte[] space = makeByte( " ",encode );
    389                        int spaceLen = space.length ;
    390                        if( spaceLen == 4 ) {   // encode が、UnicodeLittle の場合の特殊処理
    391                                space[0] = space[2];
    392                                space[1] = space[3];
    393                                spaceLen = 2;
    394                        }
    395                        byte[] bytebuf = new byte[ su_fill ];
    396                        for( int i=0; i<len; i++ ) { bytebuf[i] = byteValue[i]; }
    397
    398                        int k = 0;
    399                        for( int j=len; j<su_fill; j++ ) {           // 余った部分は、スペース埋め
    400                                if( k >= spaceLen ) { k = 0; }
    401                                bytebuf[j] = space[k++];
    402                        }
    403                        return makeString( bytebuf,0,su_fill,encode );  // 新たに、すべての長さの部分文字列を作成する。
    404                }
    405        }
    406
    407        /**
    408         * 整数のフォーム( 12 で、整数部 １２桁を表す)に合った新しい文字列を作り、それを返します。
    409         * 実行できるのは、整数の String に対してのみです。
    410         * 内部にセットした文字列は、変化しません。
    411         *
    412         *              String str = StringUtil.intFill( "123",10 );
    413         *
    414         *              実行結果："0000000123"
    415         *
    416         * @param       str     整数の String
    417         * @param       su_fill フォームを表す数字 ( 12 で、整数部 １２桁を表す)
    418         *
    419         * @return      整数のフォームに合った文字列
    420         */
    421        public static String intFill( final String str,final int su_fill ) {
    422                if( su_fill < 0 ) {
    423                        String errMsg = "指定文字数が負です。[" + su_fill + "]";
    424                        throw new RuntimeException( errMsg );
    425                }
    426
    427                char[] charbuf = new char[ su_fill ];                   // 移す char 配列を新規作成
    428                Arrays.fill( charbuf,'0' );
    429
    430                if( str == null ) { return new String( charbuf ); }
    431
    432                char[] charValue = str.toCharArray();
    433                int len = charValue.length;
    434
    435                if( su_fill < len ) {
    436                        String errMsg = "元の文字数がフォームより長いです。(数字が壊れます。) su_fill[" + su_fill + "], len[" + len + "]";
    437                        throw new RuntimeException( errMsg );
    438                }
    439
    440                System.arraycopy( charValue,0,charbuf,su_fill-len,len );
    441
    442                return new String( charbuf );            // コピーした配列全てを文字列に変換
    443        }
    444
    445        /**
    446         * 全角スペースで固定長(半角換算の数)に変換した文字列を返します。
    447         *
    448         * @param       str      Fill埋めする文字列
    449         * @param       su_fill  Fill埋めする文字列の長さ。(半角換算の数)
    450         * @param       encode   Fill埋めする文字列の文字エンコード
    451         *
    452         * @return      全角スペースでFill埋めした新しいStringを返す。
    453         */
    454        public static String stringKFill( final String str,final int su_fill,final String encode ) {
    455                if( su_fill < 0 ) {
    456                        String errMsg = "指定文字数が負です。[" + su_fill + "]";
    457                        throw new RuntimeException( errMsg );
    458                }
    459
    460                byte[] byteValue = makeByte( str,encode );
    461                int len = byteValue.length;
    462
    463                // 内部文字列が指定長より長い場合
    464                if( len >= su_fill ) {
    465                        return makeString( byteValue,0,su_fill,encode );
    466                }
    467                else {
    468                        byte[] space = makeByte( "　",encode );
    469                        int spaceLen = space.length ;
    470                        byte[] bytebuf = new byte[ su_fill ];
    471                        for( int i=0; i<len; i++ ) { bytebuf[i] = byteValue[i]; }
    472                        int k = 0;
    473                        for( int j=len; j<su_fill; j++ ) {           // 余った部分は、スペース埋め
    474                                if( k >= spaceLen ) { k = 0; }
    475                                bytebuf[j] = space[k++];
    476                        }
    477                        return makeString( bytebuf,0,su_fill,encode );  // 新たに、すべての長さの部分文字列を作成する。
    478                }
    479        }
    480
    481        /**
    482         * 小数点のフォームに合った新しい文字列を作り、文字列を返します。
    483         * 現在は、小数点が頭に付いたり、最後に付く場合の対応はしていません。
    484         * フォームは、12.4 で、 000000000010.1000 という形で、ピリオドを含みます。
    485         *
    486         *  // 半角 整数部 10 桁 小数部 ５桁で固定長の文字を得る。
    487         *  String str = StringUtil.realFill( "123.45" ,10.5 ) ;
    488         *
    489         *  実行結果：0000000123.45000
    490         *
    491         * @param       str             整数の String
    492         * @param       su_fill フォームを表す実数       ( 12.4 で、整数部 １２桁、小数部 ４桁 計１７桁 )
    493         *
    494         * @return      value   小数点のフォーム文字列
    495         */
    496        public static String realFill( final String str,final double su_fill ) {
    497                if( su_fill < 0 ) {
    498                        String errMsg = "指定文字数が負です。[" + su_fill + "]";
    499                        throw new RuntimeException( errMsg );
    500                }
    501
    502                int su_seisu = (int)(su_fill);                                             // 指定のフォームの整数部を取り出す。
    503                int su_shosu = (int)(su_fill*10 - su_seisu*10);            // 小数部を取り出しす。
    504                char[] charbuf = new char[ su_seisu + su_shosu + 1 ];  // 移す char 配列
    505                Arrays.fill( charbuf,'0' );
    506
    507                if( str == null ) {
    508                        charbuf[su_seisu] = '.' ;
    509                        return new String( charbuf );
    510                }
    511
    512                char[] charValue = str.toCharArray();
    513                int len = charValue.length;
    514
    515                // 検査する文字列の加工(検査文字列は、インデックスの値とバイト数で文字数を求める。)
    516                // 小数点の位置を求める。 本当は、String クラスの indexOf で求めず、byte[] で検索すべきである。
    517                int valueindex = str.indexOf( '.' );
    518                if( valueindex < 0 ) {                                                                       // valueform 自体が、合っていない。
    519                        String errMsg = "元の文字列に小数点が、含まれません。";
    520                        throw new RuntimeException( errMsg );
    521                }
    522                int su_valueseisu = valueindex;                                  // 整数部の文字数は、小数点の位置と同じ
    523                int su_valueshosu = len - valueindex - 1 ;              // 小数部の文字数は、全文字数−整数文字数−１
    524
    525                // フォームの整数文字数 ー 加工文字の整数文字部 ＝ 転送先配列位置
    526                int to_index = su_seisu - su_valueseisu;
    527                if( to_index < 0 ) {
    528                        String errMsg = "元の数字が、フォームより長いです。(数字が壊れます。) form[" + su_fill + "]";
    529                        throw new RuntimeException( errMsg );
    530                }
    531                int end_index;
    532                // 転送先配列終了位置は、お互いの小数部の文字数により、短い方を選ぶ。
    533                if( su_shosu < su_valueshosu ) { end_index = su_seisu + su_shosu + 1; }
    534                else                                               { end_index = su_seisu + su_valueshosu + 1; }
    535
    536                int from_index = 0;
    537                while( to_index < end_index ) {
    538                        charbuf[to_index++] = charValue[from_index++];     // 転送(移し替え)
    539                }
    540                return new String( charbuf );            // コピーした配列全てを文字列に変換
    541        }
    542
    543        /**
    544         * ストリングの部分文字列を,別の文字列に置換えたストリングを返します。
    545         * 例えば,リターンコードを&lt; br /&gt;に置換えて,画面上に改行表示させるが可能です。
    546         *
    547         * @og.rev 5.0.0.1 (2009/08/15) 不要なオブジェクトの生成を抑制する。
    548         *
    549         * @param       target 元の文字列
    550         * @param       from   置換元部分文字列
    551         * @param       to         置換先部分文字列
    552         *
    553         * @return      置換えた文字列
    554         */
    555        public static String replace( final String target,final String from,final String to ) {
    556                if( target == null || from == null || to == null || target.indexOf( from ) < 0 ) { return target; }
    557
    558                StringBuilder strBuf = new StringBuilder( target.length() );
    559
    560                int start = 0;
    561                int end   = target.indexOf( from,start );
    562                while( end >= 0 ) {
    563                        strBuf.append( target.substring( start,end ) );
    564                        strBuf.append( to );
    565                        start = end + from.length();
    566                        end   = target.indexOf( from,start );
    567                }
    568
    569                if( start > 0 ) {
    570                        strBuf.append( target.substring( start ) );
    571                        return strBuf.toString();
    572                }
    573                else {
    574                        return target;                  // 3.4.0.2 (2003/09/05)
    575                }
    576        }
    577
    578        /**
    579         * 引数の AA:01 BB:02 CC:03 … 形式の、元値:新値のｽﾍﾟｰｽ区切り文字列を元に、
    580         * 元値を新値に置き換えます。
    581         * これは、部分置換ではなく、完全一致で処理します。
    582         * caseStr が null や、マッチしなかった場合は、元の値を返します。
    583         * その場合、ignoreCase=true としている場合は、元の文字列 も大文字に変換されて返されます。
    584         *
    585         * ゼロ文字列を元値や新値で使用することは可能ですが、スペースを使用することはできません。
    586         *
    587         * @og.rev 5.7.2.3 (2014/01/31) 新規追加
    588         *
    589         * @param       target          元の文字列
    590         * @param       caseStr         置換リスト(AA:01 BB:02 CC:03 … 形式)。null の場合は、比較しない。
    591         * @param       ignoreCase      true:大文字として比較 / false:そのまま比較
    592         *
    593         * @return      元の文字列を置き換えた結果。置換リストに存在しなければ、元の文字列を返す。
    594         */
    595        public static String caseReplace( final String target,final String caseStr,final boolean ignoreCase ) {
    596                if( target == null ) { return target; }
    597
    598                String rtn = ignoreCase ? target.toUpperCase(Locale.JAPAN) : target ;
    599
    600                if( caseStr != null ) {
    601                        String caseTmp = " " + caseStr.trim() + " " ;           // CASE文字列の形式をそろえる。
    602
    603                        int adrs = caseTmp.indexOf( " " + rtn + ":" );          // 前スペースと後ろコロンで、単語を確定する。
    604                        if( adrs >= 0 ) {
    605                                int st = caseTmp.indexOf( ':' , adrs+1 );               // 最初のコロンの位置。元値:新値 の 新値 の取出
    606                                int ed = caseTmp.indexOf( ' ' , st+1 );                 // コロンの次から、最初のスペースの位置
    607                                if( st >= 0 && ed >= 0 ) {
    608                                        rtn = caseTmp.substring( st+1,ed );                     // コロンの次から、スペースの前までを切り出す。
    609                                }
    610                        }
    611                }
    612
    613                return rtn ;
    614        }
    615
    616        /**
    617         * String型の配列から、カンマ(,)で連結されたString を作成します。
    618         * これは，配列を表示用に変換する為のものです。
    619         * array2line( array, ",", 0 ); と同等です。
    620         *
    621         * @param       array           元の文字列配列
    622         *
    623         * @return      一列に変換した文字列(引数がnullの場合は、長さ０の文字列を返す)
    624         */
    625        public static String array2csv( final String[] array ) {
    626                return array2line( array, ",", 0 );
    627        }
    628
    629        /**
    630         * String型の配列から、セパレーターで連結されたString を作成します。
    631         * これは，配列を表示用に変換する為のものです。
    632         *
    633         * @param       array           元の文字列配列
    634         * @param       separator       区切り記号
    635         *
    636         * @return      一列に変換した文字列(引数がnullの場合は、長さ０の文字列を返す)
    637         */
    638        public static String array2line( final String[] array,final String separator ) {
    639                return array2line( array, separator,0 );
    640        }
    641
    642        /**
    643         * String型の配列から、セパレーターで連結されたString を作成します。
    644         * これは，配列を表示用に変換する為のものです。
    645         *
    646         * @param       array           元の文字列配列
    647         * @param       separator       区切り記号
    648         * @param       start           配列の連結開始アドレス
    649         *
    650         * @return      一列に変換した文字列(引数がnullの場合は、長さ０の文字列を返す)
    651         */
    652        public static String array2line( final String[] array,final String separator,final int start ) {
    653                if( array == null || array.length <= start ) { return ""; }
    654
    655                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    656
    657                rtn.append( valueOf( array[start] ) );
    658                for(int i=start+1; i < array.length; i++) {
    659                        rtn.append( separator );
    660                        rtn.append( valueOf( array[i] ) );
    661                }
    662                return rtn.toString();
    663        }
    664
    665        /**
    666         * Enumerationから、オブジェクト配列データを返します。
    667         * これは，Enumerationを表示用に変換する為のものです。
    668         *
    669         * @param       enume   元のEnumeration
    670         *
    671         * @return      オブジェクト配列
    672         */
    673        public static Object[] enume2Array( final Enumeration<?> enume ) {                // 4.3.3.6 (2008/11/15) Generics警告対応
    674                if( enume == null || ! enume.hasMoreElements() ) { return new Object[0]; }
    675
    676                ArrayList<Object> obj = new ArrayList<Object>();
    677
    678                while( enume.hasMoreElements() ) {
    679                        obj.add( enume.nextElement() );
    680                }
    681                return obj.toArray();
    682        }
    683
    684        /**
    685         * Enumerationから、オブジェクト配列データを返します。
    686         * これは，Enumerationを表示用に変換する為のものです。
    687         *
    688         * @param       enume   元のEnumeration
    689         * @param       objs - 配列が十分な大きさを持つ場合は、Vector の要素が格納される配列。
    690         *                      そうでない場合は、要素を格納するために同じ実行時の型の新しい配列が割り当てられる
    691         * @return      オブジェクト配列
    692         */
    693        public static Object[] enume2Array( final Enumeration<?> enume,final Object[] objs ) {    // 4.3.3.6 (2008/11/15) Generics警告対応
    694                if( enume == null || ! enume.hasMoreElements() ) { return objs ; }
    695
    696                ArrayList<Object> list = new ArrayList<Object>();
    697
    698                while( enume.hasMoreElements() ) {
    699                        list.add( enume.nextElement() );
    700                }
    701                return list.toArray( objs );
    702        }
    703
    704        /**
    705         * Iteratorから、セパレーターで連結されたString を作成します。
    706         * これは，Enumerationを表示用に変換する為のものです。
    707         *
    708         * @param       ite             元のIterator
    709         * @param       separator       区切り記号
    710         *
    711         * @return      一列に変換した文字列
    712         */
    713        public static String iterator2line( final Iterator<?> ite,final String separator ) {
    714                if( ite == null || ! ite.hasNext() ) { return ""; }
    715
    716                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    717
    718                rtn.append( valueOf( ite.next() ) );
    719                while( ite.hasNext() ) {
    720                        rtn.append( separator );
    721                        rtn.append( valueOf( ite.next() ) );
    722                }
    723                return rtn.toString();
    724        }
    725
    726        /**
    727         * カンマ(,)で連結された String を、配列に分解して、その値を返します。
    728         * これは，たとえば、AAA,BBB,CCC などのリソースデータを受けてから配列に入れ直して、
    729         * メニューなりリストを作成するのに便利です。
    730         * 要素が空の場合は、必ずカンマの間にスペースを入れて記述してください。
    731         * 分割後の文字列の前後のスペースは、削除されます。
    732         *
    733         * @param       csvData         元のデータ
    734         *
    735         * @return      文字列配列(引数がnull、ゼロ文字列の場合は、サイズ0の配列を返す)
    736         */
    737        public static String[] csv2Array( final String csvData ) {
    738                return csv2Array( csvData, ',', 0 );
    739        }
    740
    741        /**
    742         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    743         * これは，たとえば、AAA,BBB,CCC などのリソースデータを受けてから配列に入れ直して、
    744         * メニューなりリストを作成するのに便利です。
    745         * 連続した区切り文字は、１文字に分割します。
    746         * 分割後の文字列の前後のスペースは、削除されます。
    747         *
    748         * @param       csvData         元のデータ
    749         * @param       separator       区切り文字
    750         *
    751         * @return      文字列配列(引数がnull、ゼロ文字列の場合は、サイズ0の配列を返す)
    752         */
    753        public static String[] csv2Array( final String csvData,final char separator ) {
    754                return csv2Array( csvData,separator,0 );
    755        }
    756
    757        /**
    758         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    759         * これは，たとえば、AAA,BBB,CCC などのリソースデータを受けてから配列に入れ直して、
    760         * メニューなりリストを作成するのに便利です。
    761         * 連続した区切り文字は、１文字に分割します。
    762         * 分割後の文字列の前後のスペースは、削除されます。
    763         * 第３の引数は、リターンする配列の個数を指定します。ただし、第一引数がNULLや、ゼロ文字列
    764         * などの不正な情報の場合は、通常と同じく 長さゼロの配列を返します。
    765         * len=0 を指定すると分解したデータの個数分の配列を作成します。指定の長さが短い場合は、
    766         * そこまで分のみ取り込みます。指定の長さが長い場合は、余分に配列を作成します。
    767         * セットされる値は、"" です。
    768         *
    769         * @og.rev 3.8.5.1 (2006/05/08) 設定配列の数を指定できるように変更
    770         * @og.rev 3.8.8.2 (2007/01/26) 分割後の値の前後のスペースは削除します。
    771         *
    772         * @param       csvData         元のデータ
    773         * @param       separator       区切り文字
    774         * @param       len                     指定の長さの配列で返します。
    775         *
    776         * @return      文字列配列(引数がnull、ゼロ文字列の場合は、サイズ0の配列を返す)
    777         */
    778        public static String[] csv2Array( final String csvData,final char separator, final int len ) {
    779                if( csvData == null || csvData.length() == 0 ) { return new String[0] ; }
    780
    781                CSVTokenizer token = new CSVTokenizer( csvData,separator );
    782
    783                int count = (len > 0 ) ? len : token.countTokens() ;
    784                String[] rtn = new String[ count ];
    785                int i = 0;
    786                for( ; i<count && token.hasMoreTokens() ; i++ ) {
    787                        rtn[i] = token.nextToken().trim();      // 3.8.8.2 (2007/01/26)
    788                }
    789                for( ; i<count; i++ ) {
    790                        rtn[i] = "" ;
    791                }
    792
    793                return rtn;
    794        }
    795
    796        /**
    797         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    798         * これは，たとえば、AAA,BBB,CCC などのリソースデータを受けてから配列に入れ直して、
    799         * メニューなりリストを作成するのに便利です。
    800         * csv2Array と異なり、連続した区切り文字は、分割せずにトークンのみ切り出します。
    801         * トークンは、カンマ(,)のみで区切り、その後 trim() により
    802         * 前後のスペースを削除します。
    803         *
    804         * @param       csvData         元のデータ
    805         *
    806         * @return      文字列配列
    807         */
    808        public static String[] csv2ArrayOnly( final String csvData ) {
    809                if( csvData == null || csvData.length() == 0 ) { return new String[0] ; }
    810
    811                StringTokenizer token = new StringTokenizer( csvData,"," );
    812
    813                ArrayList<String> list = new ArrayList<String>();
    814                while( token.hasMoreTokens() ) {
    815                        String temp = token.nextToken().trim();
    816                        if( temp.length() > 0 ) { list.add( temp ); }
    817                }
    818
    819                return list.toArray( new String[list.size()] );
    820        }
    821
    822        /**
    823         * カンマ(,)、ハイフン(-)で連結された String を、配列に分解して、その値を返す処理のスペシャル版です。
    824         * 0,1,3,5-8,10-* などの数字文字列から、必要な数字をピックアップした文字配列を返します。
    825         * 引数の maxNo は、"*" が指定された場合の、最大の数値です。
    826         * よって、"*" は、単独(１文字)では、0-maxNo を表し、N-* では、N-maxNo を意味します。
    827         * カンマ区切りで指定される値は、基本的に数字で、重複(1,1,2,2)、逆転(3,2,1)で指定できます。
    828         * 5-3 と指定した場合は、5,4,3 に分解されます。逆順に登録されます。
    829         * 重複削除、昇順並べ替え等が、必要な場合は、取得後の配列を操作してください。
    830         *
    831         * @og.rev 5.5.7.2 (2012/10/09) 新規追加
    832         * @og.rev 5.9.12.4 (2016/09/30) アルファベットの対応を廃止し、数字配列のみサポートします。
    833         *
    834         * @param       csvData 0,1,3,5-8,10-* などのCSV-ハイフン文字列
    835         * @param       maxNo "*" が指定された場合の、最大数
    836         * @return      文字列配列(引数がnull、ゼロ文字列の場合は、サイズ0の配列を返す)
    837         */
    838        public static String[] csv2ArrayExt( final String csvData , final int maxNo )  {
    839                if( csvData == null || csvData.length() == 0 ) { return new String[0] ; }
    840
    841                String strData = csvData.replace( "-*" , "-" + maxNo );         // まず、N-* 形式を、N-maxNo に変換します。
    842                strData        = strData.replace( "*"  , "0-" + maxNo );        // その後、"*" 単独(１文字)を、0-maxNo に変換します。
    843
    844                ArrayList<String> noList = new ArrayList<String>();
    845
    846                String[] nos = strData.split( "," );            // カンマで分解。N , N-M , N-* のどれか
    847                for( int i=0; i<nos.length; i++ ) {
    848                        String sno = nos[i] ;
    849                        int hai = sno.indexOf( '-' );
    850                        // ハイフンが含まれているときは前後に分解して、間を埋める
    851                        if( hai > 0 ) {
    852                                String st1 = sno.substring( 0,hai );    // 先頭からハイフンまで
    853                                String st2 = sno.substring( hai+1 );    // ハイフンから最後まで
    854                                // 5.9.12.4 (2016/09/30) アルファベット対応をやめる
    855//                              if( st1.length() == 1 &&  st2.length() == 1 ) {         // ともに１文字の場合は、char化して処理。(英数字処理)
    856//                                      char ch1 = st1.charAt(0);
    857//                                      char ch2 = st2.charAt(0);
    858//                                      if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( String.valueOf(ch1++) ); } }
    859//                                      else                    { while( ch1 >= ch2 ) { noList.add( String.valueOf(ch1--) ); } }
    860//                              }
    861//                              else {
    862                                        int ch1 = Integer.parseInt( st1 );
    863                                        int ch2 = Integer.parseInt( st2 );
    864                                        if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( String.valueOf(ch1++) ); } }
    865                                        else                    { while( ch1 >= ch2 ) { noList.add( String.valueOf(ch1--) ); } }
    866//                              }
    867                        }
    868                        else {
    869                                noList.add( String.valueOf(sno) );
    870                        }
    871                }
    872                return noList.toArray( new String[noList.size()] ) ;
    873        }
    874
    875        /**
    876         * Integer限定版です。
    877         * V6では返り値の型変更をしていますが、V5では一旦別名にしておきます。
    878         *
    879         * @og.rev 5.9.0.0 (2015/09/04) 新規追加
    880         * @og.rev 5.9.12.4 (2016/09/30) アルファベットの対応を廃止し、数字配列のみサポートします。
    881         *
    882         * @param       csvData 0,1,3,5-8,10-* などのCSV-ハイフン文字列
    883         * @param       maxNo "*" が指定された場合の、最大数
    884         * @return      文字列配列(引数がnull、ゼロ文字列の場合は、サイズ0の配列を返す)
    885         */
    886        public static Integer[] csv2ArrayExt2( final String csvData , final int maxNo )  {
    887                if( csvData == null || csvData.length() == 0 ) { return new Integer[0] ; }
    888
    889                String strData = csvData.replace( "-*" , "-" + maxNo );         // まず、N-* 形式を、N-maxNo に変換します。
    890                strData        = strData.replace( "*"  , "0-" + maxNo );        // その後、"*" 単独(１文字)を、0-maxNo に変換します。
    891
    892                ArrayList<Integer> noList = new ArrayList<Integer>();
    893
    894                String[] nos = strData.split( "," );            // カンマで分解。N , N-M , N-* のどれか
    895                for( int i=0; i<nos.length; i++ ) {
    896                        String sno = nos[i] ;
    897                        int hai = sno.indexOf( '-' );
    898                        // ハイフンが含まれているときは前後に分解して、間を埋める
    899                        if( hai > 0 ) {
    900                                String st1 = sno.substring( 0,hai );    // 先頭からハイフンまで
    901                                String st2 = sno.substring( hai+1 );    // ハイフンから最後まで
    902                                // 5.9.12.4 (2016/09/30) アルファベット対応をやめる
    903//                              if( st1.length() == 1 &&  st2.length() == 1 ) {         // ともに１文字の場合は、char化して処理。(英数字処理)
    904//                                      char ch1 = st1.charAt(0);
    905//                                      char ch2 = st2.charAt(0);
    906//                                      if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( Integer.valueOf(ch1++) ); } }
    907//                                      else                    { while( ch1 >= ch2 ) { noList.add( Integer.valueOf(ch1--) ); } }
    908//                              }
    909//                              else {
    910                                        int ch1 = Integer.parseInt( st1 );
    911                                        int ch2 = Integer.parseInt( st2 );
    912                                        if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( Integer.valueOf(ch1++) ); } }
    913                                        else                    { while( ch1 >= ch2 ) { noList.add( Integer.valueOf(ch1--) ); } }
    914//                              }
    915                        }
    916                        else {
    917                                noList.add( Integer.valueOf(sno) );
    918                        }
    919                }
    920                return noList.toArray( new Integer[noList.size()] ) ;
    921        }
    922
    923        /**
    924         * Object 引数の文字列表現を返します。
    925         * これは，String.valueOf とほぼ同じ動作をしますが、引数が null の場合に、
    926         * "null" という文字列を返すのではなく、なにもない文字列 "" を返します。
    927         *
    928         * @param       obj    文字列表現すべき元のオブジェクト
    929         *
    930         * @return      引数が null の場合は、"" に等しい文字列。そうでない場合は、obj.toString() の値
    931         */
    932        public static String valueOf( final Object obj ) {
    933                if( obj == null ) { return "";                     }
    934                else                      { return obj.toString(); }
    935        }
    936
    937        /**
    938         * HTML上のエスケープ文字を変換します。
    939         *
    940         * HTMLで表示する場合にきちんとエスケープ文字に変換しておかないと
    941         * Script を実行されたり、不要なHTMLコマンドを潜り込まされたりするため、
    942         * セキュリティーホールになる可能性があるので、注意してください。
    943         *
    944         * @param       input HTMLエスケープ前の文字列
    945         *
    946         * @return      エスケープ文字に変換後の文字列
    947         */
    948        public static String htmlFilter( final String input ) {
    949                if( input == null || input.length() == 0 ) { return ""; }
    950                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    951                char ch;
    952                for(int i=0; i<input.length(); i++) {
    953                        ch = input.charAt(i);
    954                        switch( ch ) {
    955                                case '<'  : rtn.append("&lt;");   break;
    956                                case '>'  : rtn.append("&gt;");   break;
    957                                case '"'  : rtn.append("&quot;"); break;
    958                                case '\'' : rtn.append("&#39;");  break;
    959                                case '&'  : rtn.append("&amp;");  break;
    960                                default   : rtn.append(ch);
    961                        }
    962                }
    963                return rtn.toString() ;
    964        }
    965
    966        /**
    967         * XML上のエスケープ文字を変換します。
    968         *
    969         * HTMLとの違いはアポストロフィです。
    970         *
    971         * @og.rev 5.8.2.2 (2014/12/19) 新規作成
    972         *
    973         * @param       input XMLエスケープ前の文字列
    974         *
    975         * @return      エスケープ文字に変換後の文字列
    976         */
    977        public static String xmlFilter( final String input ) {
    978                if( input == null || input.length() == 0 ) { return ""; }
    979                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    980                char ch;
    981                for(int i=0; i<input.length(); i++) {
    982                        ch = input.charAt(i);
    983                        switch( ch ) {
    984                                case '<'  : rtn.append("&lt;");   break;
    985                                case '>'  : rtn.append("&gt;");   break;
    986                                case '"'  : rtn.append("&quot;"); break;
    987                                case '\'' : rtn.append("&apos;");  break;
    988                                case '&'  : rtn.append("&amp;");  break;
    989                                default   : rtn.append(ch);
    990                        }
    991                }
    992                return rtn.toString() ;
    993        }
    994
    995        /**
    996         * JavaScript 等の引数でのクオート文字をASCII変換します。
    997         *
    998         * JavaScript の引数の値に、ダブルクオート(")、シングルクオート(')が
    999         * 含まれると、文字列を表す為に前後に指定しているクオートと混乱し、
    1000         * データを表現できないケースがあります。その場合には、クオート文字を
    1001         * ASCII文字に置き換える事で、指定の文字を渡すことが可能になります。
    1002         * ここでは、引数文字列に、ダブルクオート(")、シングルクオート(')が、
    1003         * 含まれると、それぞれ、ASCII コード(￥ｘ２２、￥ｘ２７)に置き換えます。
    1004         * なお、null は、ゼロ文字列に変換して返します。
    1005         *
    1006         * @param       input 入力文字列
    1007         *
    1008         * @return      クオート文字をASCII文字に置き換えた文字列
    1009         */
    1010        public static String quoteFilter( final String input ) {
    1011                if( input == null || input.length() == 0 ) { return ""; }
    1012                if( input.indexOf( '\'' ) < 0 && input.indexOf( '"' ) < 0 ) { return input; }
    1013
    1014                StringBuilder rtn = new StringBuilder();
    1015                char ch;
    1016                for(int i=0; i<input.length(); i++) {
    1017                        ch = input.charAt(i);
    1018                        switch( ch ) {
    1019                                case '"'  : rtn.append( "\\x22" ); break;
    1020                                case '\'' : rtn.append( "\\x27" ); break;
    1021                                default   : rtn.append( ch );
    1022                        }
    1023                }
    1024                return rtn.toString() ;
    1025        }
    1026
    1027        /**
    1028         * JSON形式で出力する場合のためのエスケープ処理です。
    1029         *
    1030         *
    1031         * @og.rev 5.9.6.4(2016/03/25) 新規作成
    1032         *
    1033         * @param       input XMLエスケープ前の文字列
    1034         *
    1035         * @return      エスケープ文字に変換後の文字列
    1036         */
    1037        public static String jsonFilter( final String input ) {
    1038                if( input == null || input.length() == 0 ) { return ""; }
    1039                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1040                char ch;
    1041                for(int i=0; i<input.length(); i++) {
    1042                        ch = input.charAt(i);
    1043                        switch( ch ) {
    1044                                case '"'  : rtn.append("\\\"");   break;
    1045                                case '\\'  : rtn.append("\\\\");   break;
    1046                                case '/'  : rtn.append("\\/"); break;
    1047                                case '\b' : rtn.append("\\b");  break;
    1048                                case '\f'  : rtn.append("\\f");  break;
    1049                                case '\n'  : rtn.append("\\n"); break;
    1050                                case '\r' : rtn.append("\\r");  break;
    1051                                case '\t'  : rtn.append("\\t");  break;
    1052                                default   : rtn.append(ch);
    1053                        }
    1054                }
    1055                return rtn.toString() ;
    1056        }
    1057
    1058        /**
    1059         * 所定のキャラクタコードを取り除いた文字列を作成します。
    1060         *
    1061         * 実現したい機能は、String#replace( 'x','' ) 的な表現です。
    1062         * つまり、指定のキャラクタを取り除きたいのですが、上記コマンドでは、
    1063         * コンパイル時にエラーが発生します。
    1064         * 取り除きたいキャラクタコードが存在しない場合は、指定の文字列を
    1065         * そのまま返します。
    1066         *
    1067         * @param       value 処理対象の文字列
    1068         * @param       ch 取り除きたいキャラクタ
    1069         *
    1070         * @return      処理後の文字列
    1071         */
    1072        public static String deleteChar( final String value,final char ch ) {
    1073                if( value == null || value.indexOf( ch ) < 0 ) { return value; }
    1074                char[] chs = value.toCharArray() ;
    1075                int j=0;
    1076                for( int i=0;i<chs.length; i++ ) {
    1077                        if( chs[i] == ch ) { continue; }
    1078                        chs[j] = chs[i];
    1079                        j++;
    1080                }
    1081                return String.valueOf( chs,0,j );
    1082        }
    1083
    1084        /**
    1085         * 文字列に含まれる、特定の文字の個数をカウントして返します。
    1086         *
    1087         * @og.rev 5.2.0.0 (2010/09/01)
    1088         *
    1089         * @param       value 処理対象の文字列
    1090         * @param       ch カウントする文字
    1091         *
    1092         * @return      カウント数
    1093         */
    1094        public static int countChar( final String value,final char ch ) {
    1095                if( value == null || value.indexOf( ch ) < 0 ) { return 0; }
    1096                char[] chs = value.toCharArray() ;
    1097                int cnt=0;
    1098                for( int i=0;i<chs.length; i++ ) {
    1099                        if( chs[i] == ch ) { cnt++; }
    1100                }
    1101                return cnt;
    1102        }
    1103
    1104        /**
    1105         * CODE39 の 文字列を作成します。
    1106         *
    1107         * CODE39 は、『0〜9, A〜Z,-,・,　,$,/,+,%』のコードが使用できる
    1108         * バーコードの体系です。通常 * で始まり * で終了します。
    1109         * また、チェックデジット に、モジュラス43 が使われます。
    1110         * ここでは、指定の文字列の前後に、* を付与し、必要であれば
    1111         * チェックデジットも付与します。
    1112         * 指定の入力文字列には、* を付けないでください。
    1113         *
    1114         * @param       value 処理対象の文字列
    1115         * @param       checkDigit チェックデジットの付与(true:付ける/false:付けない)
    1116         *
    1117         * @return      処理後の文字列
    1118         */
    1119        public static String code39( final String value,final boolean checkDigit ) {
    1120                String rtn = ( value == null ) ? "" : value ;
    1121                if( ! checkDigit ) { return "*" + rtn + "*"; }
    1122
    1123                int kei = 0;
    1124                int cd;
    1125                for( int i=0; i<rtn.length(); i++ ) {
    1126                        cd = MODULUS_43.indexOf( rtn.charAt(i) );
    1127                        if( cd < 0 ) {
    1128                                String errMsg = "指定の文字中に、CODE39 規定外文字が使用されています。[" + rtn.charAt(i) + "]" ;
    1129                                throw new RuntimeException( errMsg );
    1130                        }
    1131                        kei += cd ;
    1132                }
    1133                char digit = MODULUS_43.charAt( kei % 43 );
    1134
    1135                return "*" + rtn + digit + "*" ;
    1136        }
    1137
    1138        /**
    1139         * 引数 in が、null または、ゼロ文字列の場合は､デフォルト値 def を返します。
    1140         * もちろん、in も def も null の場合は､null を返します。
    1141         *
    1142         * @param    in 基準となる文字列
    1143         * @param    def デフォルト文字列
    1144         *
    1145         * @return   ( in != null ) ? in : def ;
    1146         */
    1147        public static String nval( final String in,final String def ) {
    1148                return ( in == null || in.length() == 0 ) ? def : in ;
    1149        }
    1150
    1151        /**
    1152         * 引数 in が、null または、ゼロ文字列の場合は､デフォルト値 def を返します。
    1153         *
    1154         * @param    in 基準となる文字列
    1155         * @param    def デフォルト数字
    1156         *
    1157         * @return   引数 in を変換した数字。変換できない場合は デフォルト値 def
    1158         */
    1159        public static int nval( final String in,final int def ) {
    1160                return ( in == null || in.length() == 0 ) ? def : Integer.parseInt( in ) ;
    1161        }
    1162
    1163        /**
    1164         * 引数 in が、null または、ゼロ文字列の場合は､デフォルト値 def を返します。
    1165         *
    1166         * @param    in 基準となる文字列
    1167         * @param    def デフォルト数字
    1168         *
    1169         * @return   引数 in を変換した数字。変換できない場合は デフォルト値 def
    1170         */
    1171        public static long nval( final String in,final long def ) {
    1172                return ( in == null || in.length() == 0 ) ? def : Long.parseLong( in ) ;
    1173        }
    1174
    1175        /**
    1176         * 引数 in が、null または、ゼロ文字列の場合は､デフォルト値 def を返します。
    1177         * 通常は、"true" または、 "TRUE" 文字列を、論理値の true に変換します。
    1178         * ただし、文字列長が 1文字の場合のみ、"0" 以外を true に変換します。
    1179         *
    1180         * @param    in 基準となる文字列
    1181         * @param    def デフォルト論理値
    1182         *
    1183         * @return   引数 in を変換した論理値。変換できない場合は デフォルト値 def
    1184         */
    1185        public static boolean nval( final String in,final boolean def ) {
    1186                boolean rtn = def;
    1187                if( in != null && in.length() != 0 ) {
    1188                        rtn = "true".equalsIgnoreCase( in )  ;
    1189                        if( in.length() == 1 ) { rtn = ! "0".equals( in ); }
    1190                }
    1191                return rtn ;
    1192        }
    1193
    1194        /**
    1195         * 引数 in が、null、"_"、ゼロ文字列の場合は､デフォルト値 def を返します。
    1196         *
    1197         * さらに、メモリ領域を節約する為、intern() の結果を返します。
    1198         *
    1199         * @og.rev  5.2.2.0 (2010/11/01) "_" の取り扱い変更
    1200         *
    1201         * @param    in 基準となる文字列
    1202         * @param    def デフォルト文字列
    1203         *
    1204         * @return  null、"_"、ゼロ文字列の場合は、デフォルト文字列を、そうでなければ、入力文字を返す。
    1205         */
    1206        public static String nval2( final String in,final String def ) {
    1207                return ( in == null || in.length() == 0 || "_".equals( in ) ) ? def : in.intern() ;
    1208        }
    1209
    1210        /**
    1211         * 引数 in が、null または、ゼロ文字列の場合は､デフォルト値 def を返します。
    1212         * ただし、NULL代替文字(_)は デフォルト値 def2 に置き換えます。
    1213         *
    1214         * さらに、メモリ領域を節約する為、intern() の結果を返します。
    1215         *
    1216         * @og.rev  5.2.2.0 (2010/11/01) "_" の取り扱い変更
    1217         *
    1218         * @param    in 基準となる文字列
    1219         * @param    def デフォルト文字列
    1220         * @param    def2 NULL代替文字(_)の場合のデフォルト文字列
    1221         *
    1222         * @return  NULL文字列関係の場合は、ゼロ文字列を、そうでなければ、入力文字を返す。
    1223         */
    1224        public static String nval2( final String in,final String def,final String def2 ) {
    1225                return ( in == null || in.length() == 0 ) ? def : ( "_".equals( in ) ? def2 : in.intern() ) ;
    1226        }
    1227
    1228        /**
    1229         * 引数 in が、null または、ゼロ文字列、またはすべて空白文字の場合は､true を返します。
    1230         * それ以外は false を返します。
    1231         *
    1232         * 注意は、オールスペースやタブ文字、改行文字も true になります。
    1233         *
    1234         * @param    in 基準となる文字列
    1235         *
    1236         * @return  NULL文字列関係の場合は、true を、そうでなければ、false を返す。
    1237         */
    1238        public static boolean isNull( final String in ) {
    1239                if( in == null || in.length() == 0 ) { return true; }
    1240
    1241                // String.trim().length()==0 の高速版
    1242                for( int i=0; i<in.length(); i++ ) {
    1243                        if( !Character.isWhitespace( in.charAt(i) ) ) {
    1244                                return false;
    1245                        }
    1246                }
    1247                return true;
    1248        }
    1249
    1250        /**
    1251         * Throwable の printStackTrace() 結果を文字列に変換して返します。
    1252         *
    1253         * @param    th   printStackTraceすべき元のThrowableオブジェクト
    1254         *
    1255         * @return   Throwableの詳細メッセージ( th.printStackTrace() )
    1256         */
    1257        public static String stringStackTrace( final Throwable th ) {
    1258                if( th == null ) { return null; }
    1259
    1260                StringWriter sw = new StringWriter();
    1261                th.printStackTrace( new PrintWriter( sw ) );
    1262
    1263                return String.valueOf( sw );
    1264        }
    1265
    1266        /**
    1267         * Throwable の printStackTrace() 結果の内、opengion に関する箇所だけを文字列に変換して返します。
    1268         *
    1269         * printStackTrace() すると、膨大なメッセージが表示されるため、その中の、"org.opengion" を
    1270         * 含む箇所だけを、抜粋します。
    1271         *
    1272         * @og.rev 5.7.2.0 (2014/01/10) 新規作成
    1273         *
    1274         * @param    th 元のThrowableオブジェクト
    1275         *
    1276         * @return   Throwableの詳細メッセージ( StackTraceElement の抜粋 )
    1277         */
    1278        public static String ogStackTrace( final Throwable th ) {
    1279                if( th == null ) { return null; }
    1280
    1281                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1282
    1283                StackTraceElement[] eles = th.getStackTrace();
    1284                if( eles.length > 0 ) {
    1285                        rtn.append( "  " ).append( eles[0].toString() ).append( CR );
    1286                }
    1287
    1288                for( int i=1; i<eles.length; i++ ) {
    1289                        String cls = eles[i].getClassName();
    1290                        if( cls.indexOf( "org.opengion" ) >= 0 ) {
    1291                                rtn.append( "    at " ).append( eles[i].toString() ).append( CR );
    1292                        }
    1293                }
    1294
    1295                return rtn.toString();
    1296        }
    1297
    1298        /**
    1299         * 大きな浮動小数点数について、カンマ編集を行います。
    1300         *
    1301         * このメソッドでは、1.23 E12 などの数字は扱いません。通常の
    1302         * 数字とピリオドで構成された文字列のみ、変換対象になります。
    1303         * (ただし、不正な文字列を与えてもエラーチェックはしていません。)
    1304         * minFraction には、少数点部に与える固定値を指定します。入力文字列が
    1305         * その桁数より少ない場合は、０埋めします。
    1306         * 多い場合でもカットしません。
    1307         * minFraction が 0 の場合は、少数点は付きません。
    1308         * ".12" などの少数点は、必ず先頭に 0 が付きます。
    1309         * 入力文字列が null か、ゼロ文字列時は、そのまま入力データを返します。
    1310         *
    1311         * <pre>
    1312         *      DecimalFormat format = new DecimalFormat( "#,##0.00########" );
    1313         *      double dd = Double.parseDouble( val );
    1314         *      return format.format( dd );
    1315         * </pre>
    1316         * に対して、minFraction分の少数以下のゼロの指定と、inに ',' が
    1317         * 含まれた処理を追加した感じになります。
    1318         *
    1319         * @og.rev  4.0.0.0 (2007/10/26) 空白のトリム処理を追加
    1320         *
    1321         * @param       in              変換元の文字列
    1322         * @param       minFraction     変換時の少数点以下の固定桁数
    1323         *
    1324         * @return      カンマ編集後の数字型文字列
    1325         */
    1326        public static String numberFormat( final String in, final int minFraction ) {
    1327                if( in == null || in.length() == 0 ) { return in ; }
    1328
    1329                // 4.0.0.0 (2007/10/26)
    1330                String tmp = in.trim();
    1331
    1332                if( tmp.length() == 0 ) { return tmp ; }
    1333
    1334                char[] chs = tmp.toCharArray();
    1335                int pos = 0;
    1336
    1337                // 整数部の設定
    1338                boolean firstZero = true;
    1339                StringBuilder buf1 = new StringBuilder();
    1340                while( pos < chs.length ) {
    1341                        char ch = chs[pos++];
    1342                        if( ch == '.' ) { break; }
    1343                        else if( ch != '-' && ch != ',' && ( ch != '0' || !firstZero )) {
    1344                                buf1.append( ch );
    1345                                firstZero = false;
    1346                        }
    1347                }
    1348                if( buf1.length() == 0 ) {
    1349                        buf1.append( '0' );
    1350                }
    1351
    1352                for( int i=buf1.length()-3; i>0; i-=3 ) {
    1353                        buf1.insert( i,',' );
    1354                }
    1355                if( chs[0] == '-' ) { buf1.insert( 0,'-' ); }
    1356
    1357                // 少数部の設定
    1358                // 3.6.0.3 (2004/10/05) 桁数が多い場合でもカットしない
    1359                StringBuilder buf2 = new StringBuilder();
    1360                while( pos < chs.length ) {
    1361                        buf2.append( chs[pos++] );
    1362                }
    1363
    1364                while( buf2.length() < minFraction ) {
    1365                        buf2.append( '0' );
    1366                }
    1367
    1368                if( buf2.length() > 0 ) {
    1369                        buf1.append( '.' ).append( buf2 );
    1370                }
    1371
    1372                return buf1.toString();
    1373        }
    1374
    1375        /**
    1376         * 識別id に応じた オブジェクトを作成します。
    1377         * 作成するには、デフォルトコンストラクターが必要です。
    1378         *
    1379         * @param       cls 作成するクラスのフルネーム
    1380         *
    1381         * @return      オブジェクト
    1382         * @throws RuntimeException 何らかのエラーが発生した場合
    1383         */
    1384        public static Object newInstance( final String cls ) {
    1385                return newInstance( cls,Thread.currentThread().getContextClassLoader() );
    1386        }
    1387
    1388        /**
    1389         * 指定されたクラスローダを使って、識別id に応じた オブジェクトを作成します。
    1390         * 作成するには、デフォルトコンストラクターが必要です。
    1391         * initialize パラメータは true 相当(それまでに初期化されていない場合だけ初期化)です。
    1392         *
    1393         * @param       cls             作成するクラスのフルネーム
    1394         * @param       loader  作成するクラスのクラスローダ
    1395         *
    1396         * @return      オブジェクト
    1397         * @throws RuntimeException 何らかのエラーが発生した場合
    1398         */
    1399        public static Object newInstance( final String cls,final ClassLoader loader ) {
    1400                try {
    1401                        return Class.forName( cls,true,loader ).newInstance();
    1402                }
    1403                catch( ClassNotFoundException ex1 ) {
    1404                        String errMsg = "クラスが見つかりません。class=[" + cls + "]" + CR
    1405                                                + ex1.getMessage() ;
    1406                        throw new RuntimeException( errMsg,ex1 );
    1407                }
    1408                catch( LinkageError ex2 ) {
    1409                        String errMsg = "リンケージが失敗しました。class=[" + cls + "]" + CR
    1410                                                + ex2.getMessage();
    1411                        throw new RuntimeException( errMsg,ex2 );
    1412                }
    1413                catch( InstantiationException ex3 ) {
    1414                        String errMsg = "インスタンスの生成が失敗しました。class=[" + cls + "]" + CR
    1415                                                + ex3.getMessage() ;
    1416                        throw new RuntimeException( errMsg,ex3 );
    1417                }
    1418                catch( IllegalAccessException ex4 ) {
    1419                        String errMsg = "クラスまたは初期化子にアクセスできません。class=[" + cls + "]" + CR
    1420                                                + ex4.getMessage();
    1421                        throw new RuntimeException( errMsg,ex4 );
    1422                }
    1423                catch( RuntimeException ex5 ) {         // 3.6.0.0 (2004/09/17)
    1424                        String errMsg = "予期せぬエラー class=[" + cls + "]" + CR
    1425                                                + ex5.getMessage() ;
    1426                        throw new RuntimeException( errMsg,ex5 );
    1427                }
    1428        }
    1429
    1430        /**
    1431         * 指定のURL文字列同士を連結させます。
    1432         * そのとき、後方URLが、絶対パスの場合は、連結せず 後方URLを返します。
    1433         * 第２引数以降は、絶対パス判定をせず直前のURLの末尾判定のみで連結します。
    1434         *
    1435         * 絶対パスかどうかは、通常のファイル属性と同様に、先頭が、'/' (UNIX)または、
    1436         * ２文字目が、":" (Windows)の場合、または、先頭が "\" (ネットワークパス)で
    1437         * 始まる場合で判断します。
    1438         * 連結時に、前方URLの末尾に "/" を付加します。
    1439         *
    1440         * 処理の互換性確保のため、第３引数の可変長引数を追加しています。
    1441         *
    1442         * @og.rev  5.0.0.1 (2009/08/15) 不要なオブジェクトの生成を抑制する。
    1443         * @og.rev  5.6.5.2 (2013/06/21) 第３引数を可変長引数に変更
    1444         *
    1445         * @param       url1 先頭URL文字列
    1446         * @param       url2 後方URL文字列(絶対パスの場合は、返り値)
    1447         * @param       urls 後方URL文字列
    1448         *
    1449         * @return      URL文字列同士の連結結果 url1 + url2(url2が絶対パスの場合は、url2から連結開始)
    1450         */
    1451        public static String urlAppend( final String url1,final String url2,final String... urls ) {
    1452                StringBuilder rtnUrl = new StringBuilder( 200 );
    1453
    1454                if(        url2 == null || url2.length() == 0 ) { rtnUrl.append( url1 ) ; }
    1455                else if( ( url1 == null || url1.length() == 0 ) ||
    1456                                 ( url2.charAt(0) == '/'  ) ||                                                  // 実ディレクトリが UNIX
    1457                                 ( url2.length() > 1 && url2.charAt(1) == ':' ) ||           // 実ディレクトリが Windows
    1458                                 ( url2.charAt(0) == '\\' )     ) {                                                     // 実ディレクトリが ネットワークパス
    1459                                        rtnUrl.append( url2 ) ;
    1460                }
    1461                else {
    1462                        char ch = url1.charAt( url1.length()-1 ) ;
    1463                        if( ch == '/' || ch == '\\' ) {
    1464                                rtnUrl.append( url1 ).append( url2 ) ;
    1465                        }
    1466                        else {
    1467                                rtnUrl.append( url1 ).append( "/" ).append( url2 ) ;
    1468                        }
    1469                }
    1470
    1471                // ここからが、追加分
    1472                for( String url : urls ) {
    1473                        if( url != null && url.length() > 0 ) {
    1474                                char ch = rtnUrl.charAt( rtnUrl.length()-1 ) ;
    1475                                if( ch == '/' || ch == '\\' ) {
    1476                                        rtnUrl.append( url ) ;
    1477                                }
    1478                                else {
    1479                                        rtnUrl.append( "/" ).append( url ) ;
    1480                                }
    1481                        }
    1482                }
    1483
    1484                return rtnUrl.toString() ;
    1485        }
    1486
    1487        /**
    1488         * Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します。
    1489         *
    1490         * SJIS(JA16SJIS) で作成されたデータベースに、(NVARCHAR2)を使用して中国語等を登録するのは
    1491         * 非常に複雑でかつ、リスクが大きい処理になります。
    1492         * ORACLE殿でも、自信を持っては勧められない機能とのコメントを頂いています。
    1493         * そこで、HTMLでのエスケープ文字を使用して、Unicodeを文字列化して登録する為の
    1494         * DBType として、新規に作成します。
    1495         * ここでは、入力文字を、キャラクタ(char)型に分解し、(&amp;#xZZZZ;)に変換していきます。
    1496         * よって、通常に１文字(Shift-JISで２Byte,UTF-8で３Byte)が、８Byteになります。
    1497         * この変換された文字列を、HTML上でそのまま取り出すと、元のUnicode文字に戻る為、
    1498         * 通常のShift-JISでは、扱えない文字(中国語など)でも表示可能になります。
    1499         * ここでは、2バイト文字のみ、変換しています。
    1500         *
    1501         * @param       value 変換前の文字列
    1502         *
    1503         * @return      HTMLのエスケープ記号(&amp;#xZZZZ;)
    1504         */
    1505        public static String getUnicodeEscape( final String value ) {
    1506                if( value == null || value.length() == 0 ) { return ""; }
    1507
    1508                StringBuilder rtn = new StringBuilder( value.length() * 4 );
    1509
    1510                for( int i=0; i<value.length(); i++ ) {
    1511                        char ch = value.charAt(i);
    1512
    1513                        if( ch > 0xff ) {
    1514                                String hex = Integer.toHexString( (int)ch ) ;
    1515                                rtn.append( UTF_STR[hex.length()] ).append( hex ).append( ";" );
    1516                        }
    1517                        else {
    1518                                rtn.append( ch );
    1519                        }
    1520                }
    1521
    1522                return rtn.toString();
    1523        }
    1524
    1525        /**
    1526         * HTML のエスケープ記号(&amp;#xZZZZ;)をUnicode文字列に戻します。
    1527         *
    1528         * HTMLでのエスケープ文字を使用して登録された文字を、Unicodeに戻します。
    1529         * (&amp;#xZZZZ;)の８Byteを、もとのキャラクタコードに戻し、合成します。
    1530         * ここでは、通常の文字列に混在したエスケープ文字も戻せるようにします。
    1531         *
    1532         * @param       value   HTMLのエスケープ記号(&amp;#xZZZZ;)を含む文字列
    1533         *
    1534         * @og.rev 5.9.5.3 (2016/02/26) 無限ループ対応
    1535         *
    1536         * @return      通常のUnicode文字列
    1537         */
    1538        public static String getReplaceEscape( final String value ) {
    1539                if( value == null || value.length() == 0 ) { return ""; }
    1540
    1541                StringBuilder rtn = new StringBuilder( value );
    1542
    1543                int st = rtn.indexOf( "&#" );
    1544                while( st >= 0 ) {
    1545                        if( st+7 < rtn.length() && rtn.charAt( st+7 ) == ';' ) {
    1546                                int ch = Integer.parseInt( rtn.substring( st+3,st+7 ),16 );
    1547                                rtn.replace( st,st+8, Character.toString( (char)ch ) );
    1548                        }
    1549//                      st = rtn.indexOf( "&#",st );
    1550                        st = rtn.indexOf( "&#",st + 1 ); // 5.9.5.3 (2016/02/26) 無限ループ対応
    1551                }
    1552
    1553                return rtn.toString();
    1554        }
    1555
    1556        /**
    1557         * 文字列をdoubleに変換します。
    1558         *
    1559         * これは、Double.parseDouble( value ) と、ほぼ同じ動作を行います。
    1560         * 内部的には、引数の カンマ(,) を削除した文字列を、Double.parseDouble( value )
    1561         * に渡します。
    1562         * また、引数が、null,ゼロ文字列,'_' の時には、0.0 を返します。
    1563         *
    1564         * @param       value   doubleに変換する元の文字列
    1565         *
    1566         * @return      変換後のdouble数値
    1567         */
    1568        public static double parseDouble( final String value ) {
    1569                double rtn ;
    1570
    1571                if( value == null || value.length() == 0 || value.equals( "_" ) ) {
    1572                        rtn = 0.0d;
    1573                }
    1574                else if( value.indexOf( ',' ) < 0 ) {
    1575                        rtn = Double.parseDouble( value );
    1576                }
    1577                else {
    1578                        char[] chs = value.toCharArray() ;
    1579                        int j=0;
    1580                        for( int i=0;i<chs.length; i++ ) {
    1581                                if( chs[i] == ',' ) { continue; }
    1582                                chs[j] = chs[i];
    1583                                j++;
    1584                        }
    1585                        rtn = Double.parseDouble( String.valueOf( chs,0,j ) );
    1586                }
    1587
    1588                return rtn ;
    1589        }
    1590
    1591        /**
    1592         * カラーキーワードより、Colorオブジェクトを作成します。
    1593         *
    1594         * 指定文字列は、java.awt.Color クラスのstatic フィールド名で指定します。
    1595         * BLACK , BLUE , CYAN , DARK_GRAY , GRAY , GREEN , LIGHT_GRAY ,
    1596         * MAGENTA , ORANGE , PINK , RED , WHITE , YELLOW , PURPLE , TRANSPARENT(透明) が指定できます。
    1597         * また、先頭に、# を付ける事で、#XXXXXX形式の16bitRGB表記 でも指定可能です。
    1598         * static フィールド名のMapを管理していますが、存在しない場合は、エラーになります。
    1599         *
    1600         * @og.rev 3.8.9.1 (2007/06/29) 新規作成
    1601         * @og.rev 4.1.1.0 (2008/02/04) CLR_MAP に存在しない場合はエラーにします。
    1602         *
    1603         * @param       value java.awt.Color フィールドを示す文字列または、#XXXXXX形式の16bitRGB表記
    1604         *
    1605         * @return      Colorオブジェクト
    1606         * @see         java.awt.Color#BLACK
    1607         */
    1608        public static Color getColorInstance( final String value ) {
    1609                final Color clr ;
    1610
    1611                if( value.startsWith("#") ) {
    1612                        int code = Integer.parseInt( value.substring(1),16 );
    1613                        clr = new Color( code );
    1614                }
    1615                else {
    1616                        clr = CLR_MAP.get( value );
    1617                        if( clr == null ) {
    1618                                String errMsg = "指定の色コードは使用できません Color=[" + value + "]" + CR
    1619                                                        + "ColorMap=" + CLR_MAP.keySet().toString();
    1620                                throw new RuntimeException( errMsg );
    1621                        }
    1622                }
    1623
    1624                return clr;
    1625        }
    1626
    1627        /**
    1628         * 引数からspanタグを取り除いて返します。
    1629         *
    1630         * 引数が、&lt;span ･･･&gt;XXXX&lt;/span&gt;形式の場合、XXXX のみ出力します。
    1631         *
    1632         * @og.rev 4.3.4.3 (2008/12/22) TableWriterで利用していたものを移動
    1633         * @og.rev 5.9.11.1 (2016/08/10) spanだけでなく、pre,textareaも除外するようにしておく
    1634         *
    1635         * @param        data 元のString文字列
    1636         *
    1637         * @return       spanタグが取り除かれた文字列
    1638         */
    1639        public static String spanCut( final String data ) {
    1640                String rtn = data;
    1641                if( data != null ){
    1642                        if( data.startsWith( "<span" ) ) {
    1643                                int st = data.indexOf( '>' );
    1644                                int ed = data.indexOf( "</span>",st );
    1645                                rtn = data.substring( st+1,ed );
    1646                        }
    1647                        else if( data.startsWith( "<pre" ) ) {  // 5.9.11.1 本来はV6のようにするべきだが、V5は暫定的な対応にしておく
    1648                                int st = data.indexOf( '>' );
    1649                                int ed = data.indexOf( "</pre>",st );
    1650                                rtn = data.substring( st+1,ed );
    1651                        }
    1652                        else if( data.startsWith( "<textarea" ) ) {
    1653                                int st = data.indexOf( '>' );
    1654                                int ed = data.indexOf( "</textarea>",st );
    1655                                rtn = data.substring( st+1,ed );
    1656                        }
    1657                }
    1658
    1659                return rtn ;
    1660        }
    1661
    1662        /**
    1663         * 簡易CSS形式のフォーマットを、Mapにセットします。
    1664         *
    1665         * 簡易CSS形式とは、セレクタのない、{ プロパティ1 : 値1 ; ・・・ } 形式とします。
    1666         * これを、プロパティ1 と 値1 のMap にセットする処理を行います。
    1667         * コメントは、削除されます。また、同一プロパティが記述されている場合は、後処理を採用します。
    1668         *
    1669         * なお、入力テキストが、null か、{…} が存在しない場合は、null を返します。
    1670         *
    1671         * @og.rev 5.6.5.2 (2013/06/21) 新規追加
    1672         *
    1673         * @param        cssText 簡易CSS形式のフォーマット文字列
    1674         *
    1675         * @return       パース結果のMap
    1676         */
    1677        public static Map<String,String> cssParse( final String cssText ) {
    1678                Map<String,String> map = null;
    1679
    1680                if( cssText != null ) {
    1681                        // まずコメントを削除します。
    1682                        StringBuilder buf = new StringBuilder( cssText );
    1683
    1684                        int ad1 = buf.indexOf( "/*" );
    1685                        while( ad1 >= 0 ) {
    1686                                int ad2 = buf.indexOf( "*/" , ad1 );
    1687                                if( ad2 < 0 ) { buf = buf.delete( ad1,buf.length() ); break; }               // 閉じてなければ以降を全削除
    1688                                buf = buf.delete( ad1,ad2+2 );
    1689                                ad1 = buf.indexOf( "/*" );              // コメントは削除されたので、初めから検索する。
    1690                        }
    1691
    1692                        // 処理対象は、{ 〜 } の間の文字列。
    1693                        ad1 = buf.indexOf( "{" );
    1694                        int ad2 = buf.indexOf( "}",ad1 );
    1695                        if( ad1 >= 0 && ad2 > 0 ) {
    1696                                String tempText = buf.substring( ad1+1,ad2 );           // これが処理対象の文字列
    1697
    1698                                String[] recode = tempText.split( ";" );                        // KEY1 : VAL1; の ; で分割する。
    1699
    1700                                for( int i=0; i<recode.length; i++ ) {
    1701                                        int ad = recode[i].indexOf( ':' );
    1702                                        if( ad > 0 ) {
    1703                                                String key = recode[i].substring( 0,ad ).trim();
    1704                                                String val = recode[i].substring( ad+1 ).trim();
    1705                                                if( key.isEmpty() || val.isEmpty() ) { continue; }
    1706
    1707                                                if( map == null ) { map = new HashMap<String,String>(); } // 対象データがある時だけMapを作りたかったので。
    1708                                                map.put( key,val );
    1709                                        }
    1710                                }
    1711                        }
    1712                }
    1713                return map ;
    1714        }
    1715
    1716        /**
    1717         * 引数から空白文字を削除して返します。
    1718         *
    1719         *
    1720         * @og.rev 5.6.9.4 (2013/10/31) TableWriterで利用していたものを移動
    1721         *
    1722         * @param        data 元のString文字列
    1723         *
    1724         * @return       空白文字が取り除かれた文字列
    1725         */
    1726        public static String deleteWhitespace( final String data ) {
    1727                if( data == null || data.length() == 0 ){
    1728                        return data;
    1729                }
    1730                return data.replaceAll( "\\s", "" ) ;
    1731        }
    1732
    1733        /**
    1734         * 引数から指定文字の分のバイト数で切った文字列を返します。
    1735         * 文字列のバイト数は指定のエンコードでカウントします。
    1736         * （文字の途中で切れる事はありません）
    1737         *
    1738         *
    1739         * @og.rev 5.9.1.3 (2015/10/30) 新規作成
    1740         *
    1741         * @param       org 元のString文字列
    1742         * @param       cutBytes 切るバイト数
    1743         * @param       enc 文字列のエンコード
    1744         *
    1745         * @return       バイト数で切った文字列
    1746         */
    1747        public static String cut( String org, int cutBytes, String enc ) {
    1748                try {
    1749                        if ( org == null   || org.length() == 0 || cutBytes <= 0 || org.getBytes(enc).length <= cutBytes ) {
    1750                                return org;
    1751                        }
    1752
    1753                        StringBuilder cutSb = new StringBuilder();
    1754                        StringBuilder tmpSb = new StringBuilder();
    1755
    1756                        for (int i = 0; i < org.length(); i++) {
    1757                                String cut = org.substring(i, i + 1);
    1758                                if (cutBytes < tmpSb.toString().getBytes(enc).length + cut.getBytes(enc).length) {
    1759                                        cutSb.append(tmpSb.toString());
    1760                                        break;
    1761                                }
    1762                                tmpSb.append(cut);
    1763                        }
    1764                        return cutSb.toString();
    1765
    1766                }
    1767                catch (UnsupportedEncodingException e) {
    1768                        e.printStackTrace();
    1769                        return org;
    1770                }
    1771        }
    1772
    1773        /**
    1774         * 引数から指定文字の分のバイト数で切った文字列を返します。
    1775         * バイト数のカウントはUTF-8として行います。
    1776         *
    1777         *
    1778         * @og.rev 5.9.1.3 (2015/10/30) 新規作成
    1779         *
    1780         * @param       org 元のString文字列
    1781         * @param       cutBytes 切るバイト数
    1782         *
    1783         * @return       バイト数で切った文字列
    1784         */
    1785        public static String cut( String org, int cutBytes ) {
    1786                return cut( org, cutBytes, "UTF-8");
    1787        }
    1788}