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