    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 org.opengion.fukurou.system.OgRuntimeException;                          // 6.4.2.0 (2016/01/29)
    019import java.lang.reflect.InvocationTargetException;                                     // 7.0.0.0
    020import java.io.UnsupportedEncodingException;
    021import java.net.URLEncoder;
    022import java.net.URLDecoder;
    023import java.util.List;                                                                                          // 8.5.0.0 (2023/04/21)
    024import java.util.ArrayList;
    025import java.util.Arrays;
    026import java.util.Enumeration;
    027import java.util.StringJoiner;                                                                          // 6.4.4.2 (2016/04/01)
    028import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
    029import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
    030import java.util.Iterator;
    031// import java.util.StringTokenizer;                                                            // 8.5.0.0 (2023/04/21) Delete
    032import java.util.Locale;                                                                                        // 5.7.2.3 (2014/01/31)
    033import java.text.DecimalFormat;                                                                         // 6.2.0.0 (2015/02/27)
    034import java.util.function.UnaryOperator;                                                        // 6.9.2.1 (2018/03/12)
    035import java.util.function.Consumer;                                                                     // 8.0.0.2 (2021/10/15)
    036
    037import org.opengion.fukurou.system.ThrowUtil;                                           // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system
    038// import org.opengion.fukurou.system.OgRuntimeException ;                      // 8.0.0.0 (2021/09/30)
    039
    040import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
    041import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.4.2.0 (2016/01/29) ﾛｰｶﾙ定義をやめて、HybsConst を使用する様に変更。
    042
    043/**
    044 * StringUtil.java は、共通的に使用される String関連ﾒｿｯﾄﾞを集約した、ｸﾗｽです。
    045 *
    046 * @og.group    ﾕｰﾃｨﾘﾃｨ
    047 *
    048 * @version     4.0
    049 * @author      Kazuhiko Hasegawa
    050 * @since       JDK5.0,
    051 */
    052public final class StringUtil {
    053
    054        /**
    055         * code39 のﾁｪｯｸﾃﾞｼﾞｯﾄ計算に使用する ﾓｼﾞｭﾗｽ４３ の変換表です。
    056         *
    057         */
    058        private static final String MODULUS_43 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" ;
    059
    060        /**
    061         * getUnicodeEscape で使用する桁合わせ用文字列配列です。
    062         * Unicodeの HexString 変換後の桁に応じて、埋め合わせします。
    063         *
    064         */
    065        private static final String[] UTF_STR = { "&#x0000", "&#x000", "&#x00", "&#x0", "&#x" };
    066
    067        // 4.0.3.0 (2007/12/26) 色ｺｰﾄﾞにPURPLE を追加
    068        // 5.7.8.0 (2014/07/04) 透明追加
    069        // 6.0.2.1 (2014/09/26) ColorMap ｸﾗｽに移動
    070
    071        // 6.2.0.0 (2015/02/27) #numberFormat( String , int ) で使用するﾌｫｰﾏｯﾄ変換ｵﾌﾞｼﾞｪｸﾄ
    072        private static final DecimalFormat[] FMT1 = new DecimalFormat[] {
    073                                                                        new DecimalFormat( "#,##0" ) ,
    074                                                                        new DecimalFormat( "#,##0.0" ) ,
    075                                                                        new DecimalFormat( "#,##0.00" ) ,
    076                                                                        new DecimalFormat( "#,##0.000" ) ,
    077                                                                        new DecimalFormat( "#,##0.0000" ) } ;
    078
    079        private static final String ZERO = "00000000000000000000" ;             // ｾﾞﾛ埋めの種
    080
    081        private static final String[][] ESC_ARY = new String[][] {              // 6.9.8.1 (2018/06/11)
    082                                                                         { "&lt;", "<" }
    083                                                                        ,{ "&LT;", "<" }
    084                                                                        ,{ "&gt;", ">" }
    085                                                                        ,{ "&GT;", ">" }        };
    086
    087        /**
    088         *      ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰをprivateにして、
    089         *      ｵﾌﾞｼﾞｪｸﾄの生成をさせないようにする。
    090         *
    091         */
    092        private StringUtil() {}
    093
    094        /**
    095         * UTF-8 で、URLｴﾝｺｰﾄﾞを行います。
    096         * このﾒｿｯﾄﾞは、JDK1.4 以上でないと使用できません。
    097         *
    098         * @param       value ｴﾝｺｰﾄﾞする文字列
    099         *
    100         * @return       指定の文字ｺｰﾄﾞでＵＲＬｴﾝｺｰﾄﾞされた文字列
    101         * @see         #urlEncode2( String )
    102         * @og.rtnNotNull
    103         */
    104        public static String urlEncode( final String value ) {
    105                if( value == null ) { return ""; }
    106
    107                try {
    108                        return URLEncoder.encode( value,"UTF-8" );
    109                }
    110                catch( final UnsupportedEncodingException ex ) {
    111                        final String errMsg = "UnsupportedEncodingException [UTF-8]" + CR
    112                                                + ex.getMessage() ;
    113                        throw new OgRuntimeException( errMsg,ex );
    114                }
    115                catch( final RuntimeException ex2 ) {           // 3.6.0.0 (2004/09/17)
    116                        final String errMsg = "予期せぬエラー value=[" + value + "] , encode=[UTF-8]" + CR
    117                                                + ex2.getMessage();
    118                        throw new OgRuntimeException( errMsg,ex2 );
    119                }
    120        }
    121
    122        private static final String UN_CHANGE = ":/?=&._~" ;
    123
    124        /**
    125         * UTF-8 で、ASCII以外の文字の、URLｴﾝｺｰﾄﾞします。
    126         *
    127         * 00 ～ 7F までのｺｰﾄﾞは、変換しません。
    128         *
    129         * これは、日本語ﾌｧｲﾙ名の直ﾘﾝｸなど、URLｴﾝｺｰﾄﾞが必要ですが、
    130         * http:// などのURL の場合は、':' , '/' は、ｴﾝｺｰﾄﾞしたくありません。
    131         * また、openGion では、[ｶﾗﾑ] などの特殊な変数を渡して、処理させているので
    132         * それらのｷｰﾜｰﾄﾞも変換してほしくありません。
    133         * ただし、"%" と、";" は、変換します。
    134         *
    135         * @og.rev 6.2.0.1 (2015/03/06) ASCII以外の文字の、URLｴﾝｺｰﾄﾞを行う。
    136         * @og.rev 6.9.0.0 (2018/01/31) 半角の中でも ':' , '/' , '?' , '=' , '&amp;' , '.' , '_' , '~' 以外の文字は置き換えます。
    137         *
    138         * @param       value ｴﾝｺｰﾄﾞする文字列
    139         *
    140         * @return      指定の文字ｺｰﾄﾞでURLｴﾝｺｰﾄﾞされた文字列(ASCII は省く)
    141         * @see         #urlEncode( String )
    142         * @og.rtnNotNull
    143         */
    144        public static String urlEncode2( final String value ) {
    145                if( value == null ) { return ""; }
    146
    147                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    148                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    149
    150                for( int i=0; i<value.length(); i++ ) {
    151                        final char ch = value.charAt(i);
    152//                      if( ch > 0x7f ) { buf.append( ch ); }                                                                   // ASCII以外は、とりあえず貯めておく
    153                        if( ch > 0x7f || UN_CHANGE.indexOf( ch ) < 0 ) { buf.append( ch ); }    // ASCII以外は、とりあえず貯めておく
    154                        else {
    155                                if( buf.length() > 0 ) {                                                                                        // 前回のﾃﾞｰﾀが残っている
    156                                        rtn.append( urlEncode( buf.toString() ) );                                              // ASCII以外のurlEncode処理と追加
    157                                        buf.setLength(0);                                                                                               // 初期化
    158                                }
    159                                rtn.append( ch );
    160        //                      // ファイル名に、";" や "%" が存在すると、認識できないため、半角文字でも変換しておきます。
    161        //                      if(      ch == ';' ) {  rtn.append( "%3B" ); }                                          // 特殊処理
    162        //                      else if( ch == '%' ) {  rtn.append( "%25" ); }
    163        //                      else {                                  rtn.append( ch );    }                                          // ASCII文字の追加
    164                        }
    165                }
    166
    167                if( buf.length() > 0 ) {                                                                                                        // 残っている分
    168                        rtn.append( urlEncode( buf.toString() ) );                                                              // ASCII以外のurlEncode処理と追加
    169                }
    170
    171                return rtn.toString();
    172        }
    173
    174        /**
    175         * UTF-8 でURLｴﾝｺｰﾄﾞされた文字列をﾃﾞｺｰﾄﾞします。
    176         * このﾒｿｯﾄﾞは、JDK1.4 以上でないと使用できません。
    177         *
    178         * @og.rev 5.4.5.0 (2012/02/29) 追加
    179         * @param       value ﾃﾞｺｰﾄﾞする文字列
    180         *
    181         * @return      ﾃﾞｺｰﾄﾞされた文字列
    182         */
    183        public static String urlDecode( final String value ) {
    184                try {
    185                        return URLDecoder.decode( value,"UTF-8" );
    186                }
    187                catch( final UnsupportedEncodingException ex ) {
    188                        final String errMsg = "UnsupportedEncodingException [UTF-8]" + CR
    189                                                + ex.getMessage() ;
    190                        throw new OgRuntimeException( errMsg,ex );
    191                }
    192                catch( final RuntimeException ex2 ) {           // 3.6.0.0 (2004/09/17)
    193                        final String errMsg = "予期せぬエラー value=[" + value + "] , encode=[UTF-8]" + CR
    194                                                + ex2.getMessage();
    195                        throw new OgRuntimeException( errMsg,ex2 );
    196                }
    197        }
    198
    199        /**
    200         * 文字列の後ろのｽﾍﾟｰｽを削除します。
    201         * String ｸﾗｽの trim()ﾒｿｯﾄﾞは、文字列の両方のｽﾍﾟｰｽを削除しますが、
    202         * この rTrim( String ) は、後ろの半角ｽﾍﾟｰｽのみ、詰めます。
    203         * 注意：'\u0020' (ｽﾍﾟｰｽ文字) より小さい文字を切り取ります。
    204         *
    205         * @param       str     元の文字列
    206         *
    207         * @return      後ろの半角ｽﾍﾟｰｽを詰めた、新しい文字列
    208         */
    209        public static String rTrim( final String str ) {
    210                if( str == null ) { return null; }
    211                final int count = str.length();
    212
    213                int len = count;
    214
    215                while( 0 < len && str.charAt(len-1) <= ' ' ) {
    216                        len--;
    217                }
    218                return len < count ? str.substring(0, len) : str;       // len==0 の場合は、空文字列
    219        }
    220
    221        /**
    222         * 文字列の後ろから、指定の文字を削除します。
    223         * 右側の文字が、指定の文字の場合、除去します。
    224         *
    225         * @og.rev 8.0.2.0 (2021/11/30) 新規作成
    226         *
    227         * @param       str     対象文字列
    228         * @param       chr     指定文字
    229         * @return      右側から指定文字を除去後の文字列
    230         */
    231        public static String rTrim( final String str, final char chr ) {
    232                if( str == null ) { return null; }
    233                final int count = str.length();
    234
    235                int len = count;
    236
    237                while( 0 < len && str.charAt(len-1) == chr ) {
    238                        len--;
    239                }
    240                return len < count ? str.substring(0, len) : str;       // len==0 の場合は、空文字列
    241        }
    242
    243        /**
    244         * 文字列の後ろから、" .0" の文字を削除した数字型文字列を返します。
    245         * 数字型文字列は、入力文字列の後ろの ｽﾍﾟｰｽ、小数点、ｾﾞﾛを削除します。
    246         * また、先頭が、"." で始まる場合は、"0" を追加します。
    247         * 例: "123.00" ⇒ "123" , ".123" ⇒ "0.123"
    248         *
    249         * @og.rev 3.8.8.1 (2007/01/10) 新規作成
    250         *
    251         * @param       str     元の文字列
    252         *
    253         * @return      数字文字列化された、新しい文字列
    254         */
    255        public static String toNumber( final String str ) {
    256                if( str == null ) { return null; }
    257
    258                String rtn = str.trim() ;
    259
    260                final int adrs = rtn.indexOf( '.' );
    261                final int count = rtn.length();
    262                int len = count;
    263
    264                if( adrs >= 0 ) {
    265                        while( adrs < len && ".0".indexOf( rtn.charAt(len-1) ) >= 0 ) {
    266                                len--;
    267                        }
    268                }
    269
    270                if( len < count ) { rtn = rtn.substring(0, len); }
    271                if( adrs == 0 ) { rtn = "0" + rtn; }
    272
    273                return rtn ;
    274        }
    275
    276        /**
    277         * 文字列の前方のｾﾞﾛ(０)を削除します。
    278         * 先頭の０を削除するまえに、trim して、ｽﾍﾟｰｽを削除しておきます。
    279         * すべてがｾﾞﾛ(０)の場合は、"0" を返します。
    280         * 小数点( 0.01 など )の場合は、先頭の 0 がすべて消えるとまずいので、
    281         * "0." 部分は、残します。
    282         *
    283         * @og.rev 3.5.4.5 (2004/01/23) 新規追加
    284         *
    285         * @param       inStr   元の文字列
    286         *
    287         * @return      前方のｾﾞﾛ(0)を削除した、新しい文字列
    288         */
    289        public static String lTrim0( final String inStr ) {
    290                if( inStr == null ) { return null; }
    291                final String str = inStr.trim();
    292                final int count = str.length();
    293
    294                int len = 0;
    295                while( count > len && str.charAt(len) == '0' ) {
    296                        len++;
    297                }
    298
    299                if( len == 0 ) { return str; }                                  // 先頭がゼロでない。
    300                else if( len == count ) { return "0"; }                 // すべてがゼロ
    301                else if( str.charAt(len) == '.' ) { return "0" + str.substring(len); }
    302                else { return str.substring(len); }
    303        }
    304
    305        /**
    306         * 文字列配列の各要素の後ろのｽﾍﾟｰｽを削除します。
    307         * 個々の配列要素に対して、rTrim( String str ) を適用します。
    308         * 元の文字列配列に直接作用するのではなく、新しい文字列配列に
    309         * 結果をｺﾋﾟｰして返します。
    310         * ただし、元の文字列配列が、null か、length == 0 の場合は、
    311         * 元の文字列配列(ｱﾄﾞﾚｽ)を返します。
    312         * 注意：'\u0020' (ｽﾍﾟｰｽ文字) より小さい文字を切り取ります。
    313         *
    314         * @param       str     元の文字列配列(可変長引数)
    315         *
    316         * @return      後ろの半角ｽﾍﾟｰｽを詰めた、新しい文字列配列
    317         */
    318        public static String[] rTrims( final String... str ) {
    319                // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    320                if( str == null || str.length == 0 ) { return str; }
    321
    322                String[] rtn = new String[str.length];  // str.length == 0 の場合、長さゼロの新しい配列を返す。
    323                for( int i=0; i<str.length; i++ ) {
    324                        rtn[i] = rTrim( str[i] );
    325                }
    326                return rtn ;
    327        }
    328
    329        /**
    330         * 文字列の前後のﾀﾞﾌﾞﾙｸｵｰﾄを取り外します。
    331         * 前後にﾀﾞﾌﾞﾙｸｵｰﾄが入っていなければ、そのままの文字列を返します。
    332         * 前後に入っていない(片方のみなど)場合も、そのままの文字列を返します。
    333         * ※ 先頭に、'0 が含まれる場合は、ｶﾝﾏを削除します。
    334         *    従来は、ﾀﾞﾌﾞﾙｸｵｰﾄしてから、rTrim してましたが、trim してから、
    335         *    ﾀﾞﾌﾞﾙｸｵｰﾄ外しを行います。
    336         *
    337         * @og.rev 6.2.1.0 (2015/03/13) 先頭に、'0 が含まれる場合は、ｶﾝﾏを削除
    338         *
    339         * @param       str     元の文字列
    340         *
    341         * @return      ﾀﾞﾌﾞﾙｸｵｰﾄを取り外した新しい文字列
    342         */
    343        public static String csvOutQuote( final String str ) {
    344                if( str == null ) { return null; }
    345
    346                // 6.2.1.0 (2015/03/13) 先頭に、'0 が含まれる場合は、ｶﾝﾏを削除
    347                String rtn = str.trim();                                                                        // ①前後のｽﾍﾟｰｽ削除
    348                if( rtn.startsWith( "'0" ) ) { rtn = rtn.substring(1); }        // ②先頭の'0 のｶﾝﾏ外し
    349                else {
    350                        final int end = rtn.length();                                                   // ③前後のﾀﾞﾌﾞﾙｸｵｰﾄ外し
    351                        if( end >= 2 && str.charAt(0) == '"' && str.charAt( end-1 ) == '"' ) {
    352                                rtn = rtn.substring( 1,end-1 );
    353                        }
    354                }
    355                return rtn;
    356        }
    357
    358        /**
    359         * 内部で使われる byte[] から String 生成 ﾒｿｯﾄﾞ。
    360         *
    361         * @param       byteValue       変換するﾊﾞｲﾄ列
    362         * @param       start           変換開始ｱﾄﾞﾚｽ
    363         * @param       length          変換ﾊﾞｲﾄ数
    364         * @param       encode          変換する文字ｴﾝｺｰﾄﾞ
    365         *
    366         * @return      変換後文字列
    367         */
    368        public static String makeString( final byte[] byteValue, final int start, final int length,final String encode ) {
    369
    370                if( encode.startsWith( "Unicode" ) ) {
    371                        final String errMsg = "Unicode文字列は、変換できません。[" + encode + "]" + CR;
    372                        throw new OgRuntimeException( errMsg );
    373                }
    374
    375                String rtn = null;
    376                if( byteValue != null ) {
    377                        try {
    378                                // encode ｺｰﾄﾞで変換されている byte[] を、String に変換。
    379                                rtn = new String( byteValue,start,length,encode );
    380                        } catch( final UnsupportedEncodingException ex ) {      // 変換ｺｰﾄﾞが存在しないｴﾗｰ
    381                                final String errMsg = "文字変換コードが存在しません。[" + encode + "]" + CR
    382                                                        + ex.getMessage() ;
    383                                throw new OgRuntimeException( errMsg,ex );
    384                        }
    385                }
    386                return rtn;
    387        }
    388
    389        /**
    390         * 指定の文字列をﾊﾞｲﾄｺｰﾄﾞに変換します。
    391         * 引数の文字列が null の場合は、return は、byte[0] を返します。
    392         *
    393         * @param       value   変換するｽﾄﾘﾝｸﾞ値
    394         * @param       encode  変換する文字ｴﾝｺｰﾄﾞ
    395         *
    396         * @return      変換後文字列
    397         */
    398        public static byte[] makeByte( final String value,final String encode ) {
    399                byte[] rtnByte = new byte[0];
    400                if( value != null ) {
    401                        try {
    402                                rtnByte = value.getBytes( encode );                             // byte[] に encode ｺｰﾄﾞで変換。
    403                        } catch( final UnsupportedEncodingException ex ) {      // 変換ｺｰﾄﾞが存在しないｴﾗｰ
    404                                final String errMsg = "文字変換コードが存在しません。[" + encode + "]" + CR
    405                                                        + ex.getMessage();
    406                                throw new OgRuntimeException( errMsg,ex );
    407                        }
    408                }
    409                return rtnByte;
    410        }
    411
    412        /**
    413         * 半角ｽﾍﾟｰｽで固定長(半角換算の数)に変換した文字列を返します。
    414         * 半角ｽﾍﾟｰｽ埋めは、文字が半角、全角混在でもかまいません。
    415         * 内部にｾｯﾄした文字列は、変化しません。
    416         *
    417         * @param       str             Fill埋めする文字列
    418         * @param       su_fill Fill埋めする文字列の長さ。(半角換算の数)
    419         *
    420         * @return      Fill埋めした新しいStringを返す。
    421         * @og.rtnNotNull
    422         */
    423        public static String stringXFill( final String str,final int su_fill ) {
    424                char[] charValue ;
    425
    426                if( str == null ) { charValue = new char[0]; }
    427                else              { charValue = str.toCharArray(); }
    428                final int len = charValue.length;
    429
    430                if( su_fill < len ) {
    431                        final String errMsg = "元の文字数がフォームより長いです。(数字が壊れます。)"
    432                                        + "su_fill[" + su_fill + "], len[" + len + "]" + CR
    433                                        + "input=[" + str + "]" + CR;
    434                        throw new OgRuntimeException( errMsg );
    435                }
    436
    437                final char[] charbuf = new char[ su_fill ];                     // 移す char 配列を新規作成
    438                Arrays.fill( charbuf,' ' );
    439                System.arraycopy( charValue,0,charbuf,0,len );
    440
    441                return new String( charbuf );           // ｺﾋﾟｰした配列全てを文字列に変換
    442        }
    443
    444        /**
    445         * 半角ｽﾍﾟｰｽで固定長(半角換算の数)に変換した文字列を返します。
    446         * 半角ｽﾍﾟｰｽ埋めは、文字が半角、全角混在でもかまいません。
    447         * 内部にｾｯﾄした文字列は、変化しません。
    448         *
    449         * @og.rev 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
    450         *
    451         * @param       str             Fill埋めする文字列
    452         * @param       su_fill Fill埋めする文字列の長さ。(半角換算の数)
    453         * @param       encode  Fill埋めする文字列の文字ｴﾝｺｰﾄﾞ
    454         *
    455         * @return      Fill埋めした新しいStringを返す。
    456         */
    457        public static String stringFill( final String str,final int su_fill,final String encode ) {
    458                if( su_fill < 0 ) {
    459                        final String errMsg = "指定文字数が負です。[" + su_fill + "]";
    460                        throw new OgRuntimeException( errMsg );
    461                }
    462
    463                final byte[] byteValue = makeByte( str,encode );
    464                final int len = byteValue.length;
    465
    466                // 内部文字列が指定長より長い場合
    467                if( len >= su_fill ) {
    468                        return makeString( byteValue,0,su_fill,encode );
    469                }
    470                else {
    471                        byte[] space = makeByte( " ",encode );
    472                        int spaceLen = space.length ;
    473                        if( spaceLen == 4 ) {                                   // encode が、UnicodeLittle の場合の特殊処理
    474                                space[0] = space[2];
    475                                space[1] = space[3];
    476                                spaceLen = 2;
    477                        }
    478                        byte[] bytebuf = new byte[su_fill];
    479                        // 6.3.6.0 (2015/08/16) System.arraycopy が使える箇所は、置き換えます。
    480                        System.arraycopy( byteValue,0,bytebuf,0,len );          // 6.3.6.0 (2015/08/16)
    481
    482                        int k = 0;
    483                        for( int j=len; j<su_fill; j++ ) {              // 余った部分は、ｽﾍﾟｰｽ埋め
    484                                if( k >= spaceLen ) { k = 0; }
    485                                bytebuf[j] = space[k++];
    486                        }
    487                        return makeString( bytebuf,0,su_fill,encode );  // 新たに、すべての長さの部分文字列を作成する。
    488                }
    489        }
    490
    491        /**
    492         * 整数のﾌｫｰﾑ( 12 で、整数部 12桁を表す)に合った新しい文字列を作り、それを返します。
    493         * 実行できるのは、整数の String に対してのみです。
    494         * 内部にｾｯﾄした文字列は、変化しません。
    495         * 桁数がｵｰﾊﾞｰする場合は、RuntimeException を throw します。
    496         *
    497         *   String str = StringUtil.intFill( "123",10 );
    498         *
    499         *   実行結果："0000000123"
    500         *
    501         * @param       str             整数の String
    502         * @param       su_fill ﾌｫｰﾑを表す正の数字 ( 12 で、整数部 12桁を表す)
    503         *
    504         * @return      整数のﾌｫｰﾑに合った文字列
    505         * @og.rtnNotNull
    506         * @see         #intFill( int ,int )
    507         * @throws      RuntimeException su_fill が、負の数か、元の文字数がﾌｫｰﾑより長い場合、ｴﾗｰ
    508         */
    509        public static String intFill( final String str,final int su_fill ) {
    510                if( su_fill < 0 ) {
    511                        final String errMsg = "指定文字数が負です。[" + su_fill + "]";
    512                        throw new OgRuntimeException( errMsg );
    513                }
    514
    515                final char[] charbuf = new char[ su_fill ];                     // 移す char 配列を新規作成
    516                Arrays.fill( charbuf,'0' );
    517
    518                if( str == null ) { return new String( charbuf ); }
    519
    520                final char[] charValue = str.toCharArray();
    521                final int len = charValue.length;
    522
    523                if( su_fill < len ) {
    524                        final String errMsg = "元の文字数がフォームより長いです。(数字が壊れます。) su_fill[" + su_fill + "], len[" + len + "]";
    525                        throw new OgRuntimeException( errMsg );
    526                }
    527
    528                System.arraycopy( charValue,0,charbuf,su_fill-len,len );
    529
    530                return new String( charbuf );           // ｺﾋﾟｰした配列全てを文字列に変換
    531        }
    532
    533        /**
    534         * 整数のﾌｫｰﾑ( 12 で、整数部 12桁を表す)に合った新しい文字列を作り、それを返します。
    535         * 実行できるのは、正の整数に対してのみです。
    536         * 桁数がｵｰﾊﾞｰする場合は、ｵｰﾊﾞｰしたまま返します。
    537         *
    538         *   String str = StringUtil.intFill( 123,10 );
    539         *
    540         *   実行結果："0000000123"
    541         *
    542         * @og.rev 6.0.2.4 (2014/10/17) 新規追加
    543         *
    544         * @param       num             正の整数
    545         * @param       su_fill ﾌｫｰﾑを表す数字 ( 12 で、整数部 12桁を表す)
    546         *
    547         * @return      整数のﾌｫｰﾑに合った文字列
    548         * @see         #intFill( String ,int )
    549         * @throws      RuntimeException su_fill または、num が、負の数の場合、ｴﾗｰ
    550         */
    551        public static String intFill( final int num,final int su_fill ) {
    552                if( num < 0 || su_fill < 0 ) {
    553                        final String errMsg = "指定文字数が負です。num=[" + num + "] , su_fill=[" + su_fill + "]";
    554                        throw new OgRuntimeException( errMsg );
    555                }
    556
    557                String rtn = String.valueOf( num );
    558
    559                final int len = su_fill - rtn.length();                                         // 桁の不足分を算出
    560                if( len > 0 ) {
    561                        rtn = "00000000000000000000".substring( 0,len ) + rtn ;
    562                }
    563
    564                return rtn;
    565        }
    566
    567        /**
    568         * 全角ｽﾍﾟｰｽで固定長(半角換算の数)に変換した文字列を返します。
    569         *
    570         * @param       str             Fill埋めする文字列
    571         * @param       su_fill Fill埋めする文字列の長さ。(半角換算の数)
    572         * @param       encode  Fill埋めする文字列の文字ｴﾝｺｰﾄﾞ
    573         *
    574         * @return      全角ｽﾍﾟｰｽでFill埋めした新しいStringを返す。
    575         */
    576        public static String stringKFill( final String str,final int su_fill,final String encode ) {
    577                if( su_fill < 0 ) {
    578                        final String errMsg = "指定文字数が負です。[" + su_fill + "]";
    579                        throw new OgRuntimeException( errMsg );
    580                }
    581
    582                final byte[] byteValue = makeByte( str,encode );
    583                final int len = byteValue.length;
    584
    585                // 内部文字列が指定長より長い場合
    586                if( len >= su_fill ) {
    587                        return makeString( byteValue,0,su_fill,encode );
    588                }
    589                else {
    590                        final byte[] bytebuf = new byte[ su_fill ];
    591                        System.arraycopy( byteValue, 0, bytebuf, 0, len );                              // 6.3.9.0 (2015/11/06) System.arraycopy is more efficient(PMD)
    592
    593                        final byte[] space = makeByte( "　",encode );
    594                        final int spaceLen = space.length ;
    595                        int k = 0;
    596                        for( int j=len; j<su_fill; j++ ) {              // 余った部分は、ｽﾍﾟｰｽ埋め
    597                                if( k >= spaceLen ) { k = 0; }
    598                                bytebuf[j] = space[k++];
    599                        }
    600                        return makeString( bytebuf,0,su_fill,encode );  // 新たに、すべての長さの部分文字列を作成する。
    601                }
    602        }
    603
    604        /**
    605         * 小数点のﾌｫｰﾑに合った新しい文字列を作り、文字列を返します。
    606         * 現在は、小数点が頭に付いたり、最後に付く場合の対応はしていません。
    607         * ﾌｫｰﾑは、12.4 で、 000000000010.1000 という形で、ﾋﾟﾘｵﾄﾞを含みます。
    608         *
    609         *  // 半角 整数部 10 桁 小数部 5桁で固定長の文字を得る。
    610         *  String str = StringUtil.realFill( "123.45" ,10.5 ) ;
    611         *
    612         *  実行結果：0000000123.45000
    613         *
    614         * @param       str             整数の String
    615         * @param       su_fill ﾌｫｰﾑを表す実数       ( 12.4 で、整数部 12桁、小数部 4桁 計17桁 )
    616         *
    617         * @return      value   小数点のﾌｫｰﾑ文字列
    618         * @og.rtnNotNull
    619         */
    620        public static String realFill( final String str,final double su_fill ) {
    621                if( su_fill < 0 ) {
    622                        final String errMsg = "指定文字数が負です。[" + su_fill + "]";
    623                        throw new OgRuntimeException( errMsg );
    624                }
    625
    626                final int su_seisu = (int)(su_fill);                                            // 指定のﾌｫｰﾑの整数部を取り出す。
    627                final int su_shosu = (int)(su_fill*10 - su_seisu*10);           // 小数部を取り出しす。
    628                char[] charbuf = new char[ su_seisu + su_shosu + 1 ];           // 移す char 配列
    629                Arrays.fill( charbuf,'0' );
    630
    631                if( str == null ) {
    632                        charbuf[su_seisu] = '.' ;
    633                        return new String( charbuf );
    634                }
    635
    636                // 検査する文字列の加工(検査文字列は、ｲﾝﾃﾞｯｸｽの値とﾊﾞｲﾄ数で文字数を求める。)
    637                // 小数点の位置を求める。 本当は、String ｸﾗｽの indexOf で求めず、byte[] で検索すべきである。
    638                final int valueindex = str.indexOf( '.' );
    639                if( valueindex < 0 ) {                                                                  // valueform 自体が、合っていない。
    640                        final String errMsg = "元の文字列に小数点が、含まれません。";
    641                        throw new OgRuntimeException( errMsg );
    642                }
    643                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    644
    645                // ﾌｫｰﾑの整数文字数 － 加工文字の整数文字部 ＝ 転送先配列位置
    646                int toIndex = su_seisu - valueindex;                                                    // 6.4.1.1 (2016/01/16)
    647                if( toIndex < 0 ) {
    648                        final String errMsg = "元の数字が、フォームより長いです。(数字が壊れます。) form[" + su_fill + "]";
    649                        throw new OgRuntimeException( errMsg );
    650                }
    651                int endIndex;
    652                // 転送先配列終了位置は、お互いの小数部の文字数により、短い方を選ぶ。
    653                final char[] charValue  = str.toCharArray();
    654                final int su_valueshosu = charValue.length - valueindex - 1 ;   // 小数部の文字数は、全文字数－整数文字数－1
    655                if( su_shosu < su_valueshosu ) { endIndex = su_seisu + su_shosu + 1; }
    656                else                                               { endIndex = su_seisu + su_valueshosu + 1; }
    657
    658                int fromIndex = 0;
    659                while( toIndex < endIndex ) {
    660                        charbuf[toIndex++] = charValue[fromIndex++];    // 転送(移し替え)
    661                }
    662                return new String( charbuf );           // ｺﾋﾟｰした配列全てを文字列に変換
    663        }
    664
    665        /**
    666         * ｽﾄﾘﾝｸﾞの部分文字列を,別の文字列に置換えたｽﾄﾘﾝｸﾞを返します。
    667         * 例えば、ﾘﾀｰﾝｺｰﾄﾞを&lt; br /&gt;に置換えて、画面上に改行表示させるが可能です。
    668         *
    669         * @og.rev 5.0.0.1 (2009/08/15) 不要なｵﾌﾞｼﾞｪｸﾄの生成を抑制する。
    670         *
    671         * @param       target  元の文字列
    672         * @param       from    置換元部分文字列
    673         * @param       to              置換先部分文字列
    674         *
    675         * @return      置換えた文字列
    676         */
    677        public static String replace( final String target,final String from,final String to ) {
    678                if( target == null || from == null || to == null || target.indexOf( from ) < 0 ) { return target; }
    679
    680                final StringBuilder strBuf = new StringBuilder( target.length() );
    681
    682                int start = 0;
    683                int end   = target.indexOf( from,start );
    684                while( end >= 0 ) {
    685                        strBuf.append( target.substring( start,end ) );
    686                        strBuf.append( to );
    687                        start = end + from.length();
    688                        end   = target.indexOf( from,start );
    689                }
    690
    691                if( start > 0 ) {
    692                        strBuf.append( target.substring( start ) );
    693                        return strBuf.toString();
    694                }
    695                else {
    696                        return target;                  // 3.4.0.2 (2003/09/05)
    697                }
    698        }
    699
    700        /**
    701         * 変数の置き換え処理を行います。
    702         *
    703         * 変換元の文字列から、prefix と、suffix で囲まれた文字列をﾋﾟｯｸｱｯﾌﾟして、
    704         * func で指定の関数を、適用します。
    705         * 変換元の文字列に、複数含まれていてもかまいません。
    706         *
    707         * これは、単純な変数ではなく、${env.XXX}または、{&#064;ENV..XXX} の XXX を環境変数に置き換えたり、
    708         * {&#064;DATE.XXXX} を、日付文字列に置き換えたりする場合に、使用できます。
    709         * 例えば、環境変数 の置き換えは、
    710         * replaceText( orgText , "${env." , "}" , System::getenv ); または、
    711         * replaceText( orgText , "{&#064;ENV." , "}" , System::getenv );
    712         * とします。
    713         * 日付関数の置き換えは、
    714         * replaceText( orgText , "{&#064;DATE." , "}" , HybsDateUtil::getDateFormat );
    715         * とします。
    716         * orgTxt , prefix , suffix , func は必須で、null,ｾﾞﾛ文字列、空白文字等の判定で、
    717         * true の場合は、変換元の文字列 をそのまま返します。
    718         *
    719         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    720         *
    721         * @param       orgTxt  変換元の文字列
    722         * @param       prefix  変換処理を行うｷｰﾜｰﾄﾞの先頭文字列
    723         * @param       suffix  変換処理を行うｷｰﾜｰﾄﾞの終了文字列
    724         * @param       func    変換処理を行う、関数型ｲﾝﾀﾌｪｰｽ
    725         * @return      置換処理したﾃｷｽﾄ
    726         */
    727        public static String replaceText( final String orgTxt,final String prefix,final String suffix,final UnaryOperator<String> func ) {
    728                if( isEmpty( orgTxt,prefix,suffix ) || func == null ) { return orgTxt; }
    729
    730                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    731
    732                // 環境変数の処理
    733                int st0 = 0;
    734                int st1 = orgTxt.indexOf( prefix );
    735                final int preLen = prefix.length() ;
    736                final int sufLen = suffix.length() ;
    737                while( st1 >= 0 ) {
    738                        final int ed = orgTxt.indexOf( suffix , st1 );
    739                        if( ed >= 0 ) {
    740                                buf.append( orgTxt.substring( st0,st1 ) );
    741                                final String key = orgTxt.substring( st1 + preLen , ed );
    742                                buf.append( func.apply( key ) );
    743
    744                                st0 = ed + sufLen ;                                                             // suffix の長さ分
    745                                st1 = orgTxt.indexOf( prefix,st0 );
    746                        }
    747                        else {
    748                                final String errMsg = orgTxt + "の、prefix[" + prefix + "] と、suffix[" + suffix + "]の整合性が取れていません。" ;
    749                                throw new OgRuntimeException( errMsg );
    750                        }
    751                }
    752
    753                return buf.append( orgTxt.substring( st0 ) ).toString();
    754        }
    755
    756        /**
    757         * 引数の AA:01 BB:02 CC:03 … 形式の、元値:新値のｽﾍﾟｰｽ区切り文字列を元に、
    758         * 元値を新値に置き換えます。
    759         * これは、部分置換ではなく、完全一致で処理します。
    760         * caseStr が null や、ﾏｯﾁしなかった場合は、元の値を返します。
    761         * その場合、ignoreCase=true としている場合は、元の文字列 も大文字に変換されて返されます。
    762         *
    763         * ｾﾞﾛ文字列を元値や新値で使用することは可能ですが、ｽﾍﾟｰｽを使用することはできません。
    764         *
    765         * @og.rev 5.7.2.3 (2014/01/31) 新規追加
    766         *
    767         * @param       target          元の文字列
    768         * @param       caseStr         置換ﾘｽﾄ(AA:01 BB:02 CC:03 … 形式)。null の場合は、比較しない。
    769         * @param       ignoreCase      true:大文字として比較 / false:そのまま比較
    770         *
    771         * @return      元の文字列を置き換えた結果。置換ﾘｽﾄに存在しなければ、元の文字列を返す。
    772         */
    773        public static String caseReplace( final String target,final String caseStr,final boolean ignoreCase ) {
    774                if( target == null ) { return target; }
    775
    776                String rtn = ignoreCase ? target.toUpperCase(Locale.JAPAN) : target ;
    777
    778                if( caseStr != null ) {
    779                        final String caseTmp = " " + caseStr.trim() + " " ;                     // CASE文字列の形式をそろえる。
    780
    781                        final int adrs = caseTmp.indexOf( " " + rtn + ":" );            // 前ｽﾍﾟｰｽと後ろｺﾛﾝで、単語を確定する。
    782                        if( adrs >= 0 ) {
    783                                final int st = caseTmp.indexOf( ':' , adrs+1 );                 // 最初のｺﾛﾝの位置。元値:新値 の 新値 の取出
    784                                final int ed = caseTmp.indexOf( ' ' , st+1 );                   // ｺﾛﾝの次から、最初のｽﾍﾟｰｽの位置
    785                                if( st >= 0 && ed >= 0 ) {
    786                                        rtn = caseTmp.substring( st+1,ed );                                     // ｺﾛﾝの次から、ｽﾍﾟｰｽの前までを切り出す。
    787                                }
    788                        }
    789                }
    790
    791                return rtn ;
    792        }
    793
    794        /**
    795         * String型の配列から、ｶﾝﾏ(,)で連結されたString を作成します。
    796         * これは、配列を表示用に変換する為のものです。
    797         * array2line( array, ",", 0 ); と同等です。
    798         *
    799         * @param       array   元の文字列配列(可変長引数)
    800         *
    801         * @return      一列に変換した文字列(引数がnullの場合は、長さ0の文字列を返す)
    802         * @og.rtnNotNull
    803         */
    804        public static String array2csv( final String... array ) {
    805                return array2line( array, ",", 0 );
    806        }
    807
    808        /**
    809         * String型の配列から、ｾﾊﾟﾚｰﾀｰで連結されたString を作成します。
    810         * これは、配列を表示用に変換する為のものです。
    811         *
    812         * @param       array           元の文字列配列
    813         * @param       separator       区切り記号
    814         *
    815         * @return      一列に変換した文字列(引数がnullの場合は、長さ0の文字列を返す)
    816         * @og.rtnNotNull
    817         */
    818        public static String array2line( final String[] array,final String separator ) {
    819                return array2line( array, separator,0 );
    820        }
    821
    822        /**
    823         * String型の配列から、ｾﾊﾟﾚｰﾀｰで連結されたString を作成します。
    824         * これは、配列を表示用に変換する為のものです。
    825         *
    826         * @param       array           元の文字列配列
    827         * @param       separator       区切り記号
    828         * @param       start           配列の連結開始ｱﾄﾞﾚｽ
    829         *
    830         * @return      一列に変換した文字列(引数がnullの場合は、長さ0の文字列を返す)
    831         * @og.rtnNotNull
    832         */
    833        public static String array2line( final String[] array,final String separator,final int start ) {
    834                if( array == null || array.length <= start ) { return ""; }
    835
    836                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    837
    838                rtn.append( valueOf( array[start] ) );
    839                for( int i=start+1; i<array.length; i++ ) {
    840                        rtn.append( separator );
    841                        rtn.append( valueOf( array[i] ) );
    842                }
    843                return rtn.toString();
    844        }
    845
    846        /**
    847         * Enumerationから、ｵﾌﾞｼﾞｪｸﾄ配列ﾃﾞｰﾀを返します。
    848         * これは、Enumerationを表示用に変換する為のものです。
    849         *
    850         * @param       enume   元のEnumeration
    851         *
    852         * @return      ｵﾌﾞｼﾞｪｸﾄ配列
    853         * @og.rtnNotNull
    854         */
    855        public static Object[] enume2Array( final Enumeration<?> enume ) {              // 4.3.3.6 (2008/11/15) Generics警告対応
    856                if( enume == null || ! enume.hasMoreElements() ) { return new Object[0]; }
    857
    858//              final ArrayList<Object> obj = new ArrayList<>();
    859                final List<Object> obj = new ArrayList<>();             // 8.5.0.0 (2023/04/21)
    860
    861                while( enume.hasMoreElements() ) {
    862                        obj.add( enume.nextElement() );
    863                }
    864                return obj.toArray();
    865        }
    866
    867        /**
    868         * Enumerationから、ｵﾌﾞｼﾞｪｸﾄ配列ﾃﾞｰﾀを返します。
    869         * これは、Enumerationを表示用に変換する為のものです。
    870         *
    871         * @param       enume   元のEnumeration
    872         * @param       objs - 配列が十分な大きさを持つ場合は、Vector の要素が格納される配列。
    873         *                      そうでない場合は、要素を格納するために同じ実行時の型の新しい配列が割り当てられる
    874         * @return      ｵﾌﾞｼﾞｪｸﾄ配列
    875         */
    876        public static Object[] enume2Array( final Enumeration<?> enume,final Object[] objs ) {  // 4.3.3.6 (2008/11/15) Generics警告対応
    877                if( enume == null || ! enume.hasMoreElements() ) { return objs ; }
    878
    879//              final ArrayList<Object> list = new ArrayList<>();
    880                final List<Object> list = new ArrayList<>();            // 8.5.0.0 (2023/04/21)
    881
    882                while( enume.hasMoreElements() ) {
    883                        list.add( enume.nextElement() );
    884                }
    885                return list.toArray( objs );
    886        }
    887
    888        /**
    889         * Iteratorから、ｾﾊﾟﾚｰﾀｰで連結されたString を作成します。
    890         * これは、Enumerationを表示用に変換する為のものです。
    891         *
    892         * @param       ite                     元のIterator
    893         * @param       separator       区切り記号
    894         *
    895         * @return      一列に変換した文字列
    896         * @og.rtnNotNull
    897         */
    898        public static String iterator2line( final Iterator<?> ite,final String separator ) {
    899                if( ite == null || ! ite.hasNext() ) { return ""; }
    900
    901                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    902
    903                rtn.append( valueOf( ite.next() ) );
    904                while( ite.hasNext() ) {
    905                        rtn.append( separator );
    906                        rtn.append( valueOf( ite.next() ) );
    907                }
    908                return rtn.toString();
    909        }
    910
    911        /**
    912         * ｶﾝﾏ(,)で連結された String を、配列に分解して、その値を返します。
    913         * たとえば、AAA,BBB,CCC などのﾘｿｰｽﾃﾞｰﾀを受けてから配列に入れ直して、
    914         * ﾒﾆｭｰなりﾘｽﾄを作成するのに便利です。
    915         * 要素が空の場合は、必ずｶﾝﾏの間にｽﾍﾟｰｽを入れて記述してください。
    916         * 分割後の文字列の前後のｽﾍﾟｰｽは、削除されます。
    917         *
    918         * @param       csvData 元のﾃﾞｰﾀ
    919         *
    920         * @return      文字列配列(引数がnull、ｾﾞﾛ文字列の場合は、ｻｲｽﾞ0の配列を返す)
    921         * @og.rtnNotNull
    922         */
    923        public static String[] csv2Array( final String csvData ) {
    924                return csv2Array( csvData, ',', 0 );
    925        }
    926
    927        /**
    928         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    929         * たとえば、AAA,BBB,CCC などのﾘｿｰｽﾃﾞｰﾀを受けてから配列に入れ直して、
    930         * ﾒﾆｭｰなりﾘｽﾄを作成するのに便利です。
    931         * 連続した区切り文字は、1文字に分割します。
    932         * 分割後の文字列の前後のｽﾍﾟｰｽは、削除されます。
    933         *
    934         * @param       csvData         元のﾃﾞｰﾀ
    935         * @param       separator       区切り文字
    936         *
    937         * @return      文字列配列(引数がnull、ｾﾞﾛ文字列の場合は、ｻｲｽﾞ0の配列を返す)
    938         * @og.rtnNotNull
    939         */
    940        public static String[] csv2Array( final String csvData,final char separator ) {
    941                return csv2Array( csvData,separator,0 );
    942        }
    943
    944        /**
    945         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    946         * たとえば、AAA,BBB,CCC などのﾘｿｰｽﾃﾞｰﾀを受けてから配列に入れ直して、
    947         * ﾒﾆｭｰなりﾘｽﾄを作成するのに便利です。
    948         * 連続した区切り文字は、1文字に分割します。
    949         * 分割後の文字列の前後のｽﾍﾟｰｽは、削除されます。(区切り文字がTABの場合を除く：7.0.4.0 (2019/05/31) )
    950         * 第3の引数は、ﾘﾀｰﾝする配列の個数を指定します。
    951         * len=0 だけは特別で、分解したﾃﾞｰﾀの個数分の配列を作成します。指定の長さが短い場合は、
    952         * そこまで分のみ取り込みます。指定の長さが長い場合は、余分に配列を作成します。
    953         * ﾃﾞｰﾀがNULLや、ｾﾞﾛ文字列の場合は、長さｾﾞﾛの配列を返します。
    954         * ｾｯﾄされる値は、"" です。
    955         *
    956         * @og.rev 3.8.5.1 (2006/05/08) 設定配列の数を指定できるように変更
    957         * @og.rev 3.8.8.2 (2007/01/26) 分割後の値の前後のｽﾍﾟｰｽは削除します。
    958         * @og.rev 6.4.5.1 (2016/04/28) CSVTokenizer のｲﾝﾀｰﾌｪｰｽを、Iterator に変更。
    959         * @og.rev 6.8.5.0 (2018/01/09) 引数lenを最大配列長として処理します。
    960         * @og.rev 7.0.4.0 (2019/05/31) separatorがﾀﾌﾞの場合は、trim() しないように変更
    961         *
    962         * @param       csvData         元のﾃﾞｰﾀ
    963         * @param       separator       区切り文字
    964         * @param       len                     指定の最大長さの配列で返します(0の場合は、ｵﾘｼﾞﾅﾙの長さの配列か、長さｾﾞﾛの配列)。
    965         *
    966         * @return      文字列配列(引数がnull、ｾﾞﾛ文字列の場合は、ｻｲｽﾞ(len)の配列を返す)
    967         * @og.rtnNotNull
    968         */
    969        public static String[] csv2Array( final String csvData,final char separator, final int len ) {
    970//              if( csvData == null || csvData.isEmpty() ) {
    971                if( isEmpty( csvData ) ) {                                              // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    972                        final String[] rtn = new String[len] ;
    973                        Arrays.fill( rtn,"" );
    974                        return rtn;
    975                }
    976
    977                // 7.0.4.0 (2019/05/31) separatorがﾀﾌﾞの場合は、trim() しないように変更
    978                final boolean useTrim = separator != '\t' ;
    979
    980                final CSVTokenizer token = new CSVTokenizer( csvData,separator );
    981                final int count = len > 0 ? len : token.countTokens() ;
    982                final String[] rtn = new String[count];
    983                int i = 0;
    984                for( ; i<count && token.hasNext() ; i++ ) {
    985//                      rtn[i] = token.next().trim();                           // 3.8.8.2 (2007/01/26)
    986                        rtn[i] = token.next();                                          // 3.8.8.2 (2007/01/26)
    987                        if( useTrim ) { rtn[i] = rtn[i].trim(); }       // 7.0.4.0 (2019/05/31)
    988                }
    989                for( ; i<count; i++ ) {
    990                        rtn[i] = "" ;
    991                }
    992
    993                return rtn;
    994        }
    995
    996        /**
    997         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    998         * これは、#csv2Array( String,char,int ) ﾒｿｯﾄﾞで、分割時のﾃﾞｰﾀが
    999         * ｾﾞﾛ文字列の場合に、ｾｯﾄする初期値です。
    1000         * 元のﾃﾞｰﾀがnull、ｾﾞﾛ文字列の場合は、defVal がｾｯﾄされた ｻｲｽﾞlenの配列を返します。
    1001         *
    1002         * ﾃﾞｰﾀ数が、指定の len より少ない場合、先のﾒｿｯﾄﾞでは、ｾﾞﾛ文字列を追加していましたが、
    1003         * ここでは、初期値の defVal をｾｯﾄします。
    1004         * また、分解後、trim() されたﾃﾞｰﾀが、ｾﾞﾛ文字列の場合も、defVal をｾｯﾄします。
    1005         *
    1006         * @og.rev 6.8.5.0 (2018/01/09) CSVTokenizer のｲﾝﾀｰﾌｪｰｽを、Iterator に変更。
    1007         *
    1008         * @param       csvData         元のﾃﾞｰﾀ
    1009         * @param       separator       区切り文字
    1010         * @param       len                     指定の長さの配列で返します。
    1011         * @param       defVal          分割したﾃﾞｰﾀが、ｾﾞﾛ文字列の場合の初期値
    1012         *
    1013         * @return      文字列配列(引数がnull、ｾﾞﾛ文字列の場合は、ｻｲｽﾞ0の配列を返す)
    1014         * @og.rtnNotNull
    1015         */
    1016        public static String[] csv2Array( final String csvData,final char separator, final int len , final String defVal ) {
    1017                // 処理の中で対応しても良いが、ｵﾘｼﾞﾅﾙを尊重しておきます。
    1018                final String[] rtn = csv2Array( csvData,separator,len );
    1019
    1020                for( int i=0; i<rtn.length; i++ ) {
    1021                        if( rtn[i].isEmpty() ) { rtn[i] = defVal ; }
    1022                }
    1023
    1024                return rtn;
    1025        }
    1026
    1027        /**
    1028         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    1029         * たとえば、AAA,BBB,CCC などのﾘｿｰｽﾃﾞｰﾀを受けてから配列に入れ直して、
    1030         * ﾒﾆｭｰなりﾘｽﾄを作成するのに便利です。
    1031         * csv2Array と異なり、連続した区切り文字は、分割せずにﾄｰｸﾝのみ切り出します。
    1032         * 区切り文字は、","(ｶﾝﾏ)です。
    1033         * 前後のｽﾍﾟｰｽを削除します。
    1034         *
    1035         * @og.rev 8.5.0.0 (2023/04/21) StringTokenizer をやめて、CSVTokenizer に統一
    1036         *
    1037         * @param       csvData 元のﾃﾞｰﾀ
    1038         *
    1039         * @return      文字列配列
    1040         * @og.rtnNotNull
    1041         */
    1042        public static String[] csv2ArrayOnly( final String csvData ) {
    1043                return csv2ArrayOnly( csvData, ',' );
    1044        }
    1045
    1046        /**
    1047         * 区切り文字で連結された String を、配列に分解して、その値を返します。
    1048         * たとえば、AAA,BBB,CCC などのﾘｿｰｽﾃﾞｰﾀを受けてから配列に入れ直して、
    1049         * ﾒﾆｭｰなりﾘｽﾄを作成するのに便利です。
    1050         * csv2Array と異なり、連続した区切り文字は、分割せずにﾄｰｸﾝのみ切り出します。
    1051         * 前後のｽﾍﾟｰｽを削除します。
    1052         *
    1053         * @og.rev 8.5.0.0 (2023/04/21) StringTokenizer をやめて、CSVTokenizer に統一
    1054         *
    1055         * @param       csvData         元のﾃﾞｰﾀ(Emptyﾃﾞｰﾀは考えません)
    1056         * @param       separator       区切り文字
    1057         *
    1058         * @return      文字列配列
    1059         * @og.rtnNotNull
    1060         */
    1061//      public static String[] csv2ArrayOnly( final String csvData ) {
    1062        public static String[] csv2ArrayOnly( final String csvData ,final char separator ) {
    1063                // 7.0.4.0 (2019/05/31) separatorがﾀﾌﾞの場合は、trim() しないように変更
    1064                final boolean useTrim = separator != '\t' ;
    1065
    1066                final CSVTokenizer token = new CSVTokenizer( csvData,separator );
    1067
    1068                final List<String> list = new ArrayList<>();
    1069                while( token.hasNext() ) {
    1070                        String tkn = token.next();
    1071                        if( useTrim ) { tkn = tkn.trim(); }
    1072                        if( !tkn.isEmpty() ) {
    1073                                list.add( tkn );
    1074                        }
    1075                }
    1076
    1077                return list.toArray( new String[list.size()] ) ;
    1078
    1079                // 8.5.0.0 (2023/04/21) StringTokenizer をやめて、CSVTokenizer に統一
    1080
    1081////            if( csvData == null || csvData.isEmpty() ) { return new String[0] ; }
    1082//              if( isEmpty( csvData ) ) { return new String[0]; }                                              // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1083//
    1084//              final StringTokenizer token = new StringTokenizer( csvData,"," );
    1085//
    1086//              final ArrayList<String> list = new ArrayList<>();
    1087//              while( token.hasMoreTokens() ) {
    1088//                      final String temp = token.nextToken().trim();
    1089//                      if( temp.length() > 0 ) { list.add( temp ); }
    1090//              }
    1091//
    1092//              return list.toArray( new String[list.size()] );
    1093        }
    1094
    1095        /**
    1096         * ｶﾝﾏ(,)、ﾊｲﾌﾝ(-)で連結された String を、配列に分解して、その値を返す処理のｽﾍﾟｼｬﾙ版です。
    1097         * 0,1,3,5-8,10-* などの数字文字列から、必要な数字をﾋﾟｯｸｱｯﾌﾟした数字配列を返します。
    1098         * 引数の maxNo は、"*" が指定された場合の、最大の数値です。
    1099         * よって、"*" は、単独(1文字)では、0-maxNo を表し、N-* では、N-maxNo を意味します。
    1100         * CSV形式で指定される値は、基本的に数字で、重複(1,1,2,2)、逆転(3,2,1)で指定できます。
    1101         * 5-3 と指定した場合は、5,4,3 に分解されます。逆順に登録されます。
    1102         * 重複削除、昇順並べ替え等が、必要な場合は、取得後の配列を操作してください。
    1103         *
    1104         * @og.rev 5.5.7.2 (2012/10/09) 新規追加
    1105         * @og.rev 6.2.6.0 (2015/06/19) ｱﾙﾌｧﾍﾞｯﾄの対応を廃止し、数字配列のみｻﾎﾟｰﾄします。
    1106         *
    1107         * @param       csvData 0,1,3,5-8,10-* などのCSV-ﾊｲﾌﾝ文字列
    1108         * @param       maxNo   "*" が指定された場合の、最大数
    1109         * @return      数字配列(引数がnull、ｾﾞﾛ文字列の場合は、ｻｲｽﾞ0の配列を返す)
    1110         * @og.rtnNotNull
    1111         */
    1112        public static Integer[] csv2ArrayExt( final String csvData , final int maxNo ) {
    1113//              if( csvData == null || csvData.isEmpty() ) { return new Integer[0] ; }
    1114                if( isEmpty( csvData ) ) { return new Integer[0]; }                                             // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1115
    1116                String strData = csvData.replace( "-*" , "-"  + maxNo );                                // まず、N-* 形式を、N-maxNo に変換します。
    1117                strData        = strData.replace( "*"  , "0-" + maxNo );                                // その後、"*" 単独(1文字)を、0-maxNo に変換します。
    1118
    1119//              final ArrayList<Integer> noList = new ArrayList<>();
    1120                final List<Integer> noList = new ArrayList<>();                                                 // 8.5.0.0 (2023/04/21)
    1121
    1122//              final String[] nos = strData.split( "," );                                                              // ｶﾝﾏで分解。N , N-M , N-* のどれか
    1123//              for( int i=0; i<nos.length; i++ ) {
    1124//                      final String sno = nos[i] ;
    1125                for( final String sno : strData.split( "," ) ) {                                                // ｶﾝﾏで分解。N , N-M , N-* のどれか
    1126                        final int hai = sno.indexOf( '-' );
    1127                        // ハイフンが含まれているときは前後に分解して、間を埋める
    1128                        if( hai > 0 ) {
    1129                                int       ch1 = Integer.parseInt( sno.substring( 0,hai ) );             // 先頭からﾊｲﾌﾝまで
    1130                                final int ch2 = Integer.parseInt( sno.substring( hai+1 ) );             // ﾊｲﾌﾝから最後まで
    1131                                if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( ch1++ ); } }
    1132                                else                    { while( ch1 >= ch2 ) { noList.add( ch1-- ); } }
    1133
    1134                        // また、一文字だけの場合は、ｱﾙﾌｧﾍﾞｯﾄ(a-z,A-Zなど)も指定する事が可能です。
    1135                        // ｱﾙﾌｧﾍﾞｯﾄの場合は、"*" は指定できません。
    1136                        //      final String st1 = sno.substring( 0,hai );                      // 先頭からﾊｲﾌﾝまで
    1137                        //      final String st2 = sno.substring( hai+1 );                      // ﾊｲﾌﾝから最後まで
    1138                        //      if( st1.length() == 1 && st2.length() == 1 ) {          // ともに1文字の場合は、char化して処理。(英数字処理)
    1139                        //              char ch1 = st1.charAt(0);
    1140                        //              final char ch2 = st2.charAt(0);
    1141                        //              if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( String.valueOf(ch1++ ) ); } }
    1142                        //              else                    { while( ch1 >= ch2 ) { noList.add( String.valueOf(ch1--) ); } }
    1143                        //      }
    1144                        //      else {
    1145                        //              int ch1 = Integer.parseInt( st1 );
    1146                        //              final int ch2 = Integer.parseInt( st2 );
    1147                        //              if( ch1 < ch2 ) { while( ch1 <= ch2 ) { noList.add( String.valueOf(ch1++ ) ); } }
    1148                        //              else                    { while( ch1 >= ch2 ) { noList.add( String.valueOf(ch1--) ); } }
    1149                        //      }
    1150                        }
    1151                        else {
    1152                                noList.add( Integer.valueOf( sno ) );
    1153                        }
    1154                }
    1155                return noList.toArray( new Integer[noList.size()] ) ;
    1156        }
    1157
    1158        /**
    1159         * Object 引数の文字列表現を返します。
    1160         * String.valueOf とほぼ同じ動作をしますが、引数が null の場合に、
    1161         * "null" という文字列を返すのではなく、なにもない文字列 "" を返します。
    1162         *
    1163         * @param       obj     文字列表現すべき元のｵﾌﾞｼﾞｪｸﾄ
    1164         *
    1165         * @return      引数が null の場合は、"" に等しい文字列。そうでない場合は、obj.toString() の値
    1166         * @og.rtnNotNull
    1167         */
    1168        public static String valueOf( final Object obj ) {
    1169                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    1170                return obj == null ? "" : obj.toString();
    1171        }
    1172
    1173        /**
    1174         * HTML上のｴｽｹｰﾌﾟ文字を変換します。
    1175         *
    1176         * HTMLで表示する場合にきちんとｴｽｹｰﾌﾟ文字に変換しておかないと
    1177         * Script を実行されたり、不要なHTMLｺﾏﾝﾄﾞを潜り込まされたりするため、
    1178         * ｾｷｭﾘﾃｨｰﾎｰﾙになる可能性があるので、注意してください。
    1179         *
    1180         * @og.rev 5.8.2.2 (2014/12/19) ｱﾎﾟｽﾄﾛﾌｨの対応
    1181         * @og.rev 6.2.2.3 (2015/04/10) htmlﾌｨﾙﾀｰに、BR→改行処理機能を追加。互換性の為のﾒｿｯﾄﾞ。
    1182         *
    1183         * @param       input   HTMLｴｽｹｰﾌﾟ前の文字列
    1184         *
    1185         * @return      ｴｽｹｰﾌﾟ文字に変換後の文字列
    1186         * @og.rtnNotNull
    1187         */
    1188        public static String htmlFilter( final String input ) {
    1189                return htmlFilter( input , false );
    1190        }
    1191
    1192        /**
    1193         * HTML上のｴｽｹｰﾌﾟ文字を変換します。
    1194         *
    1195         * HTMLで表示する場合にきちんとｴｽｹｰﾌﾟ文字に変換しておかないと
    1196         * Script を実行されたり、不要なHTMLｺﾏﾝﾄﾞを潜り込まされたりするため、
    1197         * ｾｷｭﾘﾃｨｰﾎｰﾙになる可能性があるので、注意してください。
    1198         *
    1199         * 引数のﾌﾗｸﾞは、BR→改行ｺｰﾄﾞ の変換処理を行うかどうかを指定します。
    1200         * true が、変換処理を行うです。
    1201         * titleなどのTips表示する場合、改行は、｢\n(改行ｺｰﾄﾞ)｣で行います。
    1202         * (HTMLで取り扱うので、&amp;#13;&amp;#10; の方が良いかもしれない。
    1203         * その場合は、ｴｽｹｰﾌﾟ処理と順番を入れ替えないと、そのまま表示されてしまう。)
    1204         * 一方、ﾀｸﾞ等で改行を行うには、&lt;BR/&gt; で改行を指定します。
    1205         * 改行については、｢\n｣文字列を指定する事で統一します。
    1206         *
    1207         * @og.rev 5.8.2.2 (2014/12/19) ｱﾎﾟｽﾄﾛﾌｨの対応
    1208         * @og.rev 6.2.2.3 (2015/04/10) htmlﾌｨﾙﾀｰに、BR→改行処理機能を追加。
    1209         * @og.rev 6.2.5.0 (2015/06/05) htmlﾌｨﾙﾀｰで、BR→改行処理が、引数間違いの為うまくできていなかった。
    1210         *
    1211         * @param       input   HTMLｴｽｹｰﾌﾟ前の文字列
    1212         * @param       flag    [true:BR変換する/false:BR変換しない]
    1213         *
    1214         * @return      ｴｽｹｰﾌﾟ文字に変換後の文字列
    1215         * @og.rtnNotNull
    1216         */
    1217        public static String htmlFilter( final String input , final boolean flag ) {
    1218//              if( input == null || input.isEmpty() ) { return ""; }
    1219                if( isEmpty( input ) ) { return ""; }                                                   // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1220
    1221                String temp = input ;
    1222                if( flag ) {
    1223                        temp = temp.replaceAll( "<[bB][rR][\\s/]*>" , "\n" );           // <br> を置き換える。
    1224                        temp = temp.replaceAll( "\\\\n"             , "\n" );           //「\n」という文字列を置き換える。
    1225                }
    1226
    1227                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1228                char ch;
    1229                for( int i=0; i<temp.length(); i++ ) {
    1230                        ch = temp.charAt(i);            // 6.2.5.0 (2015/06/05) ﾊﾞｸﾞ
    1231                        switch( ch ) {
    1232                                case '<'  : rtn.append( "&lt;"   );     break;
    1233                                case '>'  : rtn.append( "&gt;"   );     break;
    1234                                case '"'  : rtn.append( "&quot;" );     break;
    1235                                case '\'' : rtn.append( "&apos;" );     break;          // 5.8.2.2 (2014/12/19) ｱﾎﾟｽﾄﾛﾌｨの対応
    1236                                case '&'  : rtn.append( "&amp;"  );     break;
    1237                                default   : rtn.append( ch );           break;          // 6.0.2.5 (2014/10/31) break追記
    1238                        }
    1239                }
    1240                return rtn.toString() ;
    1241        }
    1242
    1243        /**
    1244         * ｢\n｣という文字列を、BRﾀｸﾞに変換します。
    1245         *
    1246         * titleなどのTips表示する場合、改行は、｢\n｣で行います。
    1247         * 一方、ﾀｸﾞ等で改行を行うには、&lt;BR/&gt; で改行を指定します。
    1248         * BRﾀｸﾞは、ﾘｿｰｽﾃｰﾌﾞﾙ等に書き込みにくい為、また、本当の改行ｺｰﾄﾞも
    1249         * 書き込みにくい為、改行については、｢\n｣文字列を指定する事で対応できるように
    1250         * 統一します。
    1251         *
    1252         * @og.rev 6.2.2.3 (2015/04/10) ｢\n｣という文字列を、BRﾀｸﾞに変換する処理を追加
    1253         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    1254         *
    1255         * @param       input   BR,\n変換前の文字列
    1256         *
    1257         * @return      変換後の文字列
    1258         * @og.rtnNotNull
    1259         */
    1260        public static String yenN2br( final String input ) {
    1261                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    1262//              return input == null || input.isEmpty() ? "" : input.replaceAll( "\\\\n" , "<br/>" );   // \n ではなく、「\n」という文字列と変換
    1263//              return isEmpty( input ) ? "" : input.replaceAll( "\\\\n" , "<br/>" );                                   // \n ではなく、「\n」という文字列と変換        // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1264                return isEmpty( input ) ? "" : input.replaceAll( "\\\\n" , "<br>" );                                    // \n ではなく、「\n」という文字列と変換        // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1265        }
    1266
    1267        /**
    1268         * JavaScript 等の引数でのｸｵｰﾄ文字をASCII変換します。
    1269         *
    1270         * JavaScript の引数の値に、ﾀﾞﾌﾞﾙｸｵｰﾄ(")、ｼﾝｸﾞﾙｸｵｰﾄ(')が
    1271         * 含まれると、文字列を表す為に前後に指定しているｸｵｰﾄと混乱し、
    1272         * ﾃﾞｰﾀを表現できないｹｰｽがあります。その場合には、ｸｵｰﾄ文字を
    1273         * ASCII文字に置き換える事で、指定の文字を渡すことが可能になります。
    1274         * ここでは、引数文字列に、ﾀﾞﾌﾞﾙｸｵｰﾄ(")、ｼﾝｸﾞﾙｸｵｰﾄ(')が、
    1275         * 含まれると、それぞれ、ASCII ｺｰﾄﾞ(￥ｘ２２、￥ｘ２７)に置き換えます。
    1276         * なお、null は、ｾﾞﾛ文字列に変換して返します。
    1277         *
    1278         * @param       input   入力文字列
    1279         *
    1280         * @return      ｸｵｰﾄ文字をASCII文字に置き換えた文字列
    1281         * @og.rtnNotNull
    1282         */
    1283        public static String quoteFilter( final String input ) {
    1284//              if( input == null || input.isEmpty() ) { return ""; }
    1285                if( isEmpty( input ) ) { return ""; }                                                   // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1286                if( input.indexOf( '\'' ) < 0 && input.indexOf( '"' ) < 0 ) { return input; }
    1287
    1288                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1289                char ch;
    1290                for( int i=0; i<input.length(); i++ ) {
    1291                        ch = input.charAt(i);
    1292                        switch( ch ) {
    1293                                case '"'  : rtn.append( "\\x22" );      break;
    1294                                case '\'' : rtn.append( "\\x27" );      break;
    1295                                default   : rtn.append( ch );           break;          // 6.0.2.5 (2014/10/31) break追記
    1296                        }
    1297                }
    1298                return rtn.toString() ;
    1299        }
    1300
    1301        /**
    1302         * JSON形式で出力する場合のためのｴｽｹｰﾌﾟ処理です。
    1303         *
    1304         * @og.rev 5.9.6.4 (2016/03/25) 新規作成
    1305         *
    1306         * @param       input   XMLｴｽｹｰﾌﾟ前の文字列
    1307         *
    1308         * @return      ｴｽｹｰﾌﾟ文字に変換後の文字列
    1309         */
    1310        public static String jsonFilter( final String input ) {
    1311//              if( input == null || input.length() == 0 ) { return ""; }
    1312                if( isEmpty( input ) ) { return ""; }                                                   // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1313
    1314                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1315                for(int i=0; i<input.length(); i++) {
    1316                        final char ch = input.charAt(i);
    1317                        switch( ch ) {
    1318                                case '"'        : rtn.append( "\\\"" ); break;
    1319                                case '\\'       : rtn.append( "\\\\" ); break;
    1320                                case '/'        : rtn.append( "\\/"  ); break;
    1321                                case '\b'       : rtn.append( "\\b"  ); break;
    1322                                case '\f'       : rtn.append( "\\f"  ); break;
    1323                                case '\n'       : rtn.append( "\\n"  ); break;
    1324                                case '\r'       : rtn.append( "\\r"  ); break;
    1325                                case '\t'       : rtn.append( "\\t"  ); break;
    1326                                default         : rtn.append( ch );             break;
    1327                        }
    1328                }
    1329                return rtn.toString() ;
    1330        }
    1331
    1332        /**
    1333         * 特殊文字のｴｽｹｰﾌﾟを元に戻す処理です。
    1334         * 元に戻すことで、htmlとして、使用します。
    1335         * scriptﾀｸﾞは動作しないようにしています。
    1336         * またignoreで指定したﾀｸﾞを除いて&lt;にします。
    1337         *
    1338         * @og.rev 5.9.33.0 (2018/06/01) 新規作成
    1339         *
    1340         * @param       input   特殊文字がｴｽｹｰﾌﾟされた文字列
    1341         * @param       ignore  指定したﾀｸﾞを除いて&lt;にします
    1342         *
    1343         * @return      ｴｽｹｰﾌﾟ前の文字列
    1344         */
    1345//      public static String escapeFilter( String input, String ignore ) {
    1346        public static String escapeFilter( final String input, final String ignore ) {
    1347//              if( input == null || input.length() == 0 ) { return ""; }
    1348                if( isEmpty( input ) ) { return ""; }                   // 6.9.8.1 (2018/06/11) isEmpty 置き換え
    1349
    1350                // 6.9.8.1 (2018/06/11) static 変数 ESC_ARY として、定義
    1351//              final String[][] list = new String[][] {
    1352//                       { "&lt;", "<" }
    1353//                      ,{ "&LT;", "<" }
    1354//                      ,{ "&gt;", ">" }
    1355//                      ,{ "&GT;", ">" }
    1356//              };
    1357
    1358//              for( final String[] trg : list ) {
    1359//                      input = replace( input, trg[0], trg[1] );
    1360//              }
    1361
    1362                String output = input;
    1363                for( final String[] trg : ESC_ARY ) {
    1364                        output = replace( input, trg[0], trg[1] );
    1365                }
    1366
    1367                // XSS対策
    1368                // jquery.cleditor.jsと同様の対応。
    1369                // ｽｸﾘﾌﾟﾄは実行させない
    1370//              input = input.replaceAll( "<(?=/?(?i)script)", "&lt;" );
    1371                output = output.replaceAll( "<(?=/?(?i)script)", "&lt;" );
    1372
    1373                // <と>の表示対応
    1374                // jquery.cleditor.custom.jsのupdateFrame(TextRich用)に同様処理を実装。(ｴｽｹｰﾌﾟ文字の\有無が異なります)
    1375                //strong|font|a|br|p|span|div
    1376                // 指定のﾀｸﾞ前方の<以外の<は、&lt;に変換する。
    1377//              input = input.replaceAll( "<(?!/?(?i)("+ignore+")( |>|/))", "&lt;" );
    1378                // 6.9.8.1 (2018/06/11) ignore の isEmpty 判定を追加
    1379                if( !isEmpty( ignore ) ) {
    1380                        output = output.replaceAll( "<(?!/?(?i)("+ignore+")( |>|/))", "&lt;" );
    1381                }
    1382
    1383//              return input;
    1384                return output;
    1385        }
    1386
    1387        /**
    1388         * 所定のｷｬﾗｸﾀｺｰﾄﾞを取り除いた文字列を作成します。
    1389         *
    1390         * 実現したい機能は、String#replace( 'x','' ) 的な表現です。
    1391         * つまり、指定のｷｬﾗｸﾀを取り除きたいのですが、上記ｺﾏﾝﾄﾞでは、
    1392         * ｺﾝﾊﾟｲﾙ時にｴﾗｰが発生します。
    1393         * 取り除きたいｷｬﾗｸﾀｺｰﾄﾞが存在しない場合は、指定の文字列を
    1394         * そのまま返します。
    1395         *
    1396         * @param       value   処理対象の文字列
    1397         * @param       ch              取り除きたいｷｬﾗｸﾀ
    1398         *
    1399         * @return      処理後の文字列
    1400         */
    1401        public static String deleteChar( final String value,final char ch ) {
    1402                if( value == null || value.indexOf( ch ) < 0 ) { return value; }
    1403                char[] chs = value.toCharArray() ;
    1404                int j=0;
    1405                for( int i=0;i<chs.length; i++ ) {
    1406                        // 6.3.9.0 (2015/11/06) true/false を変更します。
    1407                        if( chs[i] != ch ) { chs[j++] = chs[i]; }
    1408                }
    1409                return String.valueOf( chs,0,j );
    1410        }
    1411
    1412        /**
    1413         * 文字列に含まれる、特定の文字の個数をｶｳﾝﾄして返します。
    1414         *
    1415         * @og.rev 5.2.0.0 (2010/09/01)
    1416         *
    1417         * @param       value   処理対象の文字列
    1418         * @param       ch              ｶｳﾝﾄする文字
    1419         *
    1420         * @return      ｶｳﾝﾄ数
    1421         */
    1422        public static int countChar( final String value,final char ch ) {
    1423                if( value == null || value.indexOf( ch ) < 0 ) { return 0; }
    1424//              final char[] chs = value.toCharArray() ;
    1425                int cnt=0;
    1426//              for( int i=0;i<chs.length; i++ ) {
    1427//                      if( chs[i] == ch ) { cnt++; }
    1428//              }
    1429                for( final char tmp : value.toCharArray() ) {
    1430                        if( tmp == ch ) { cnt++; }
    1431                }
    1432                return cnt;
    1433        }
    1434
    1435        /**
    1436         * CODE39 の 文字列を作成します。
    1437         *
    1438         * CODE39 は、『0～9, A～Z,-,･,　,$,/,+,%』のｺｰﾄﾞが使用できる
    1439         * ﾊﾞｰｺｰﾄﾞの体系です。通常 * で始まり * で終了します。
    1440         * また、ﾁｪｯｸﾃﾞｼﾞｯﾄ に、ﾓｼﾞｭﾗｽ43 が使われます。
    1441         * ここでは、指定の文字列の前後に、* を付与し、必要であれば
    1442         * ﾁｪｯｸﾃﾞｼﾞｯﾄも付与します。
    1443         * 指定の入力文字列には、* を付けないでください。
    1444         *
    1445         * @param       value           処理対象の文字列
    1446         * @param       checkDigit      ﾁｪｯｸﾃﾞｼﾞｯﾄの付与(true:付ける/false:付けない)
    1447         *
    1448         * @return      処理後の文字列
    1449         * @og.rtnNotNull
    1450         */
    1451        public static String code39( final String value,final boolean checkDigit ) {
    1452                final String rtn = ( value == null ) ? "" : value ;
    1453                if( ! checkDigit ) { return "*" + rtn + "*"; }
    1454
    1455                int kei = 0;
    1456                int cd;
    1457                for( int i=0; i<rtn.length(); i++ ) {
    1458                        cd = MODULUS_43.indexOf( rtn.charAt(i) );
    1459                        if( cd < 0 ) {
    1460                                final String errMsg = "指定の文字中に、CODE39 規定外文字が使用されています。[" + rtn.charAt(i) + "]" ;
    1461                                throw new OgRuntimeException( errMsg );
    1462                        }
    1463                        kei += cd ;
    1464                }
    1465                final char digit = MODULUS_43.charAt( kei % 43 );
    1466
    1467                return "*" + rtn + digit + "*" ;
    1468        }
    1469
    1470        /**
    1471         * 引数 inStr が、null または、ｾﾞﾛ文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1472         * もちろん、inStr も def も null の場合は、null を返します。
    1473         *
    1474         * ※ 影響範囲が大きいので、空白文字の判定は入れません。
    1475         *
    1476         * @param       inStr   基準となる文字列
    1477         * @param       def             ﾃﾞﾌｫﾙﾄ文字列
    1478         *
    1479         * @return      引数 inStr が、null または、ｾﾞﾛ文字列の場合は、ﾃﾞﾌｫﾙﾄ値を返す。
    1480         */
    1481        public static String nval( final String inStr,final String def ) {
    1482//              return inStr == null || inStr.isEmpty() ? def : inStr ;
    1483                return isEmpty( inStr ) ? def : inStr ;                                                 // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1484        }
    1485
    1486        /**
    1487         * 引数 inStr が、null または、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1488         *
    1489         * 数値変換なので、空白文字列の場合も、ﾃﾞﾌｫﾙﾄ値を使用します。
    1490         *
    1491         * @param       inStr   基準となる文字列
    1492         * @param       def             ﾃﾞﾌｫﾙﾄ数字
    1493         *
    1494         * @return      引数 inStr を変換した数字(int)。変換できない場合は ﾃﾞﾌｫﾙﾄ値 def
    1495         */
    1496        public static int nval( final String inStr,final int def ) {
    1497//              return inStr == null || inStr.isEmpty() ? def : Integer.parseInt( inStr ) ;
    1498                return isNull( inStr ) ? def : Integer.parseInt( inStr ) ;              // 6.9.2.1 (2018/03/12) isNull 置き換え
    1499        }
    1500
    1501        /**
    1502         * 引数 inStr が、null または、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1503         *
    1504         * @param       inStr 基準となる文字列
    1505         * @param       def ﾃﾞﾌｫﾙﾄ数字
    1506         *
    1507         * @return      引数 inStr を変換した数字(long)。変換できない場合は ﾃﾞﾌｫﾙﾄ値 def
    1508         */
    1509        public static long nval( final String inStr,final long def ) {
    1510//              return inStr == null || inStr.isEmpty() ? def : Long.parseLong( inStr ) ;
    1511                return isNull( inStr ) ? def : Long.parseLong( inStr ) ;                        // 6.9.2.1 (2018/03/12) isNull 置き換え
    1512        }
    1513
    1514        /**
    1515         * 引数 inStr が、null または、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1516         *
    1517         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    1518         *
    1519         * @param       inStr 基準となる文字列
    1520         * @param       def ﾃﾞﾌｫﾙﾄ数字
    1521         *
    1522         * @return      引数 inStr を変換した数字(double)。変換できない場合は ﾃﾞﾌｫﾙﾄ値 def
    1523         */
    1524        public static double nval( final String inStr,final double def ) {
    1525                return isNull( inStr ) ? def : Double.parseDouble( inStr ) ;            // 6.9.2.1 (2018/03/12) isNull 置き換え
    1526        }
    1527
    1528        /**
    1529         * 引数 inStr が、null または、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1530         * 通常は、"true" または、 "TRUE" 文字列を、論理値の true に変換します。
    1531         * ただし、文字列長が 1文字の場合のみ、"0" 以外を true に変換します。
    1532         *
    1533         * @og.rev 6.8.0.1 (2017/06/30) つづり間違いに対応するため、厳密にﾁｪｯｸします。
    1534         *
    1535         * @param       inStr   基準となる文字列
    1536         * @param       def             ﾃﾞﾌｫﾙﾄ論理値
    1537         *
    1538         * @return      引数 inStr を変換した論理値。変換できない場合は ﾃﾞﾌｫﾙﾄ値 def
    1539         */
    1540        public static boolean nval( final String inStr,final boolean def ) {
    1541                // 6.8.0.1 (2017/06/30) つづり間違いに対応するため、厳密にﾁｪｯｸします。
    1542                if( inStr != null && inStr.length() > 1 && !"true".equalsIgnoreCase( inStr ) && !"false".equalsIgnoreCase( inStr ) ) {
    1543                        final String errMsg = "指定の文字列には、true か、false を指定してください。[" + inStr + "]" ;
    1544                        throw new OgRuntimeException( errMsg );
    1545                }
    1546
    1547                // 6.4.1.1 (2016/01/16) PMD refactoring.
    1548//              return inStr == null || inStr.isEmpty()
    1549                return isNull( inStr )                                                                                  // 6.9.2.1 (2018/03/12) isNull 置き換え
    1550                                        ? def
    1551                                        : inStr.length() == 1
    1552                                                ? ! "0".equals( inStr )
    1553                                                : "true".equalsIgnoreCase( inStr ) ;
    1554        }
    1555
    1556        /**
    1557         * 引数配列 inStrs の各文字列が 、null または、ｾﾞﾛ文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def をｾｯﾄします。
    1558         * 引数配列 inStrs がnullの場合は、そのままを返します。
    1559         *
    1560         * @og.rev 8.4.1.0 (2023/02/10) 基準となる文字列配列のnval新規作成
    1561         *
    1562         * @param       inStrs  基準となる文字列配列
    1563         * @param       def             ﾃﾞﾌｫﾙﾄ文字列
    1564         *
    1565         * @return      引数配列 inStrs(nullの場合は、nullを返す)
    1566         */
    1567        public static String[] nval( final String[] inStrs,final String def ) {
    1568                if( inStrs != null ) {
    1569                        for( int i=0; i<inStrs.length; i++ ) {
    1570                                inStrs[i] = nval( inStrs[i],def );
    1571                        }
    1572                }
    1573                return inStrs ;
    1574        }
    1575
    1576        /**
    1577         * 引数 inStr が、null、"_"、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1578         *
    1579         * さらに、ﾒﾓﾘ領域を節約する為、intern() の結果を返します。
    1580         * ※ #nval(String) との整合性を取るため、空白文字の判定は入れません。
    1581         *
    1582         * @og.rev 5.2.2.0 (2010/11/01) "_" の取り扱い変更
    1583         *
    1584         * @param       inStr 基準となる文字列
    1585         * @param       def ﾃﾞﾌｫﾙﾄ文字列
    1586         *
    1587         * @return      null、ｾﾞﾛ文字列、"_"の場合は、ﾃﾞﾌｫﾙﾄ文字列を、そうでなければ、入力文字を返す。
    1588         */
    1589        public static String nval2( final String inStr,final String def ) {
    1590//              return inStr == null || inStr.isEmpty() || "_".equals( inStr ) ? def : inStr.intern() ;
    1591                return isEmpty( inStr ) || "_".equals( inStr ) ? def : inStr.intern() ;         // 6.9.2.1 (2018/03/12) isNull 置き換え
    1592        }
    1593
    1594        /**
    1595         * 引数 inStr が、null または、ｾﾞﾛ文字列、空白文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1596         * ただし、NULL代替文字(_)は ﾃﾞﾌｫﾙﾄ値 def2 に置き換えます。
    1597         *
    1598         * さらに、ﾒﾓﾘ領域を節約する為、intern() の結果を返します。
    1599         * ※ #nval(String) との整合性を取るため、空白文字の判定は入れません。
    1600         *
    1601         * @og.rev 5.2.2.0 (2010/11/01) "_" の取り扱い変更
    1602         *
    1603         * @param       inStr   基準となる文字列
    1604         * @param       def             ﾃﾞﾌｫﾙﾄ文字列
    1605         * @param       def2    NULL代替文字(_)の場合のﾃﾞﾌｫﾙﾄ文字列
    1606         *
    1607         * @return      null、ｾﾞﾛ文字列の場合は、def1文字列を、"_"の場合は、def2文字列を、そうでなければ、入力文字を返す。
    1608         */
    1609        public static String nval2( final String inStr,final String def,final String def2 ) {
    1610//              return inStr == null || inStr.isEmpty() ? def : "_".equals( inStr ) ? def2 : inStr.intern() ;
    1611                return isEmpty( inStr ) ? def : "_".equals( inStr ) ? def2 : inStr.intern() ;           // 6.9.2.1 (2018/03/12) isNull 置き換え
    1612        }
    1613
    1614        /**
    1615         * 引数の CSV形式文字列 が、null または、ｾﾞﾛ文字列の場合は、ﾃﾞﾌｫﾙﾄ値 def を返します。
    1616         * それ以外の場合は、CSV形式の文字列を正規化します。
    1617         *
    1618         * 正規化とは、ｶﾝﾏで区切った後、trim() して、ｾﾞﾛ文字列でない場合のみｶﾝﾏで再結合します。
    1619         *
    1620         * @og.rev 7.0.5.0 (2019/09/09) 新規追加
    1621         *
    1622         * @param       strCsv  基準となるCSV形式文字列
    1623         * @param       def             ﾃﾞﾌｫﾙﾄ文字列
    1624         *
    1625         * @return      引数の CSV形式文字列 が、null または、ｾﾞﾛ文字列の場合は、ﾃﾞﾌｫﾙﾄ値を返す。
    1626         */
    1627        public static String nvalCsv( final String strCsv,final String def ) {
    1628                return isNull( strCsv ) ? def : join( "," , csv2Array( strCsv ) );
    1629        }
    1630
    1631        /**
    1632         * 指定のCharSequence同士を連結させます。
    1633         * CharSequenceが、 null の場合は、連結しません。
    1634         * すべてが null の場合は、ｾﾞﾛ文字列が返されます。
    1635         *
    1636         * ここでは、空白文字やﾀﾌﾞ、改行ｺｰﾄﾞも、指定されていれば、連結されます。
    1637         *
    1638         * @og.rev 6.0.2.4 (2014/10/17) 新規追加
    1639         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    1640         *
    1641         * @param       strs... 可変長CharSequence
    1642         *
    1643         * @return      null以外の文字列が連結された状態
    1644         * @see         #join( String,CharSequence... )
    1645         * @og.rtnNotNull
    1646         */
    1647        public static String nvalAdd( final CharSequence... strs ) {
    1648                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    1649
    1650                for( final CharSequence str : strs ) {
    1651                        if( str != null ) { buf.append( str ); }
    1652                }
    1653
    1654                return buf.toString();
    1655        }
    1656
    1657        /**
    1658         * 最初の null(または、ｾﾞﾛ文字列、空白文字、ﾀﾌﾞや改行ｺｰﾄﾞ) 以外の値を返します。
    1659         * nval の 変数が、無制限版です。
    1660         * すべてが null(または、ｾﾞﾛ文字列) の場合は、null が返されます。
    1661//       * 空白文字、ﾀﾌﾞや改行ｺｰﾄﾞが来ても、返されます。
    1662         *
    1663         * @og.rev 6.0.2.4 (2014/10/17) 新規追加
    1664         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    1665         * @og.rev 6.9.7.0 (2018/05/14) ﾀﾌﾞや空白文字も null系と判断。
    1666         *
    1667         * @param       strs... 可変長CharSequence
    1668         *
    1669         * @return      最初に現れた、null以外のCharSequenceを、Stringに変換したもの
    1670         */
    1671//      public static CharSequence coalesce( final CharSequence... strs ) {
    1672        public static String coalesce( final CharSequence... strs ) {
    1673                for( final CharSequence str : strs ) {
    1674//                      if( str != null && str.length() > 0 ) { return str.toString(); }
    1675//                      if( ! isEmpty( str ) ) { return str.toString(); }                               // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1676                        if( ! isNull( str ) ) { return str.toString(); }                                // 6.9.7.0 (2018/05/14) ﾀﾌﾞや空白文字も null系と判断。
    1677                }
    1678
    1679                return null;
    1680        }
    1681
    1682        /**
    1683         * ｷｰﾜｰﾄﾞに対して、可変長引数の文字列が、含まれているかどうかを判定します。
    1684         * ｷｰﾜｰﾄﾞが、null でなく、比較先の文字列が、ひとつでも含まれると、true が返ります。
    1685         * 大文字小文字は、厳密に判定されます。
    1686         *
    1687         * key != null &amp;&amp; ( key.contains( val1 ) || key.contains( val2 ) ･･･ )
    1688         * の結果と同じです。
    1689         *
    1690         * @og.rev 6.4.4.2 (2016/04/01) contains 判定を行う新しいﾒｿｯﾄﾞを新規追加します。
    1691         *
    1692         * @param       key             ｷｰﾜｰﾄﾞ
    1693         * @param       vals... 比較先の可変長文字列(OR判定)
    1694         *
    1695         * @return      ｷｰﾜｰﾄﾞ文字列の中に、比較先文字列がひとつでも含まれると、true
    1696         */
    1697        public static boolean contains( final String key , final String... vals ) {
    1698                if( key != null && vals != null ) {
    1699                        for( final String val : vals ) {
    1700                                if( val != null && key.contains( val ) ) { return true; }       // ひとつでも、contains があれば、true
    1701                        }
    1702                }
    1703                return false;
    1704        }
    1705
    1706        /**
    1707         * 連結文字列を使用して、可変長引数のCharSequenceを連結して返します。
    1708         * 連結文字列(delimiter)が、null の場合は、CharSequenceをそのまま連結(nvalAdd)していきます。
    1709         * 連結する文字列が null の場合は、連結しません。
    1710         * 連結文字列は、一番最後は出力されません。
    1711         * 処理できない場合は、長さｾﾞﾛの文字列を返します。
    1712         *
    1713         * @og.rev 6.4.4.2 (2016/04/01) join 処理を行う新しいﾒｿｯﾄﾞを新規追加します。
    1714         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    1715         *
    1716         * @param       delimiter       連結文字列
    1717         * @param       vals...         連結するCharSequence
    1718         *
    1719         * @return      連結された結果の文字列
    1720         * @see         #nvalAdd( CharSequence... )
    1721         * @og.rtnNotNull
    1722         */
    1723        public static String join( final String delimiter , final CharSequence... vals ) {
    1724                if( delimiter == null ) { return nvalAdd( vals ); }
    1725
    1726                final StringJoiner sjo = new StringJoiner( delimiter );
    1727                for( final CharSequence val : vals ) {
    1728//                      if( val != null && val.length() > 0 ) { sjo.add( val ); }
    1729                        if( ! isEmpty( val ) ) { sjo.add( val ); }                                              // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    1730                }
    1731
    1732                return sjo.toString();
    1733        }
    1734
    1735        /**
    1736         * 引数 vals が、一つでも、null または、ｾﾞﾛ文字列の場合は、true を返します。
    1737         * それ以外は false を返します。
    1738         *
    1739         * isNull との違いは、ｽﾍﾟｰｽやﾀﾌﾞ、改行だけの文字列は、null と判定しません。
    1740         * 文字列置換などで、ｽﾍﾟｰｽやﾀﾌﾞなどと置換する場合、null やｾﾞﾛ文字列では困る場合などの
    1741         * 判定で使用します。
    1742         *
    1743         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    1744         *
    1745         * @param       vals    判定するCharSequence(可変長引数)
    1746         *
    1747         * @return      NULL文字列関係の場合は、true を、そうでなければ、false を返す。
    1748         * @see         #isNull( CharSequence... )
    1749         */
    1750        public static boolean isEmpty( final CharSequence... vals ) {
    1751                if( vals != null && vals.length > 0 ) {
    1752                        for( final CharSequence val : vals ) {
    1753                                if( val == null || val.length()==0 ) { return true; }   // val の nullﾁｪｯｸ 必要？
    1754                        }
    1755                        return false;
    1756                }
    1757                return true;
    1758        }
    1759
    1760        /**
    1761         * 引数 vals が、一つでも、null または、ｾﾞﾛ文字列、またはすべて空白文字(ｽﾍﾟｰｽ、ﾀﾌﾞ、改行)の場合は、true を返します。
    1762         * それ以外は false を返します。
    1763         *
    1764         * isEmpty との違いは、判定前に、trim() 処理を行っているため、ｽﾍﾟｰｽやﾀﾌﾞ、改行だけの文字列も、null と判定します。
    1765         * ｷｰﾜｰﾄﾞとして使用できないｹｰｽで、この判定を利用します。
    1766         * また、引数は可変長になっており、指定の｢どれか｣が、成立すれば、true と判定します。
    1767         * 処理的には、 val1 == null || val1.trim().length()==0 || val2 == null || val2.trim().length()==0 ･･･
    1768         *
    1769         * CharSequence 系の配列自体の null ﾁｪｯｸも兼ねています。
    1770         *
    1771         * 注意は、ｵｰﾙｽﾍﾟｰｽやﾀﾌﾞ文字、改行文字も true になります。
    1772         *
    1773         * @og.rev 6.4.5.0 (2016/04/08) 引数をCharSequenceに変更
    1774         * @og.rev 6.9.0.0 (2018/01/31) 引数を可変長引数に変更
    1775         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    1776         *
    1777         * @param       vals    判定するCharSequence(可変長引数)
    1778         *
    1779         * @return      NULL文字列関係の場合は、true を、そうでなければ、false を返す。
    1780         * @see         #isNotNull( CharSequence... )
    1781         */
    1782        public static boolean isNull( final CharSequence... vals ) {
    1783                // 6.9.0.0 (2018/01/31) 引数を可変長引数に変更
    1784                if( vals != null && vals.length > 0 ) {
    1785                        for( final CharSequence val : vals ) {
    1786                                if( val == null || val.length()==0 ) { return true; }   // val の nullﾁｪｯｸ 必要？
    1787
    1788                                boolean flag = true;
    1789                                // String.trim().isEmpty() の高速版
    1790                                for( int i=0; i<val.length(); i++ ) {
    1791                                        if( !Character.isWhitespace( val.charAt(i) ) ) {        // 空白文字でなければ
    1792                                                flag = false;                                                                   // 小ﾙｰﾌﾟを抜ける。
    1793                                                break;
    1794                                        }
    1795                                }
    1796                                if( flag ) { return true; }                                                             // すべてが空白文字なら、true
    1797                        }
    1798                        return false;
    1799                }
    1800                return true;
    1801        }
    1802
    1803        /**
    1804         * 引数 vals が、すべて、null または、ｾﾞﾛ文字列、またはすべて空白文字(ｽﾍﾟｰｽ、ﾀﾌﾞ、改行)でない場合は、true を返します。
    1805         *
    1806         * #isNull( CharSequence... ) の反転です。
    1807         * そのため、｢すべて｣の文字列が、null か、ｾﾞﾛ文字、空白文字でない場合のみ、true になります。
    1808         * isNull の表示上、'!' ﾏｰｸのあるなしは、判別しにくいため、ﾒｿｯﾄﾞを用意しています。
    1809         *
    1810         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    1811         *
    1812         * @param       vals 判定するCharSequence(可変長引数)
    1813         *
    1814         * @return      NULL文字列関係でない場合は、true を、｢どれか｣が、NULL文字列関係の場合は、false を返す。
    1815         * @see         #isNull( CharSequence... )
    1816         */
    1817        public static boolean isNotNull( final CharSequence... vals ) {
    1818                return !isNull( vals );
    1819        }
    1820
    1821        /**
    1822         * 浮動小数点数について、ｶﾝﾏ編集を行います。
    1823         *
    1824         * このﾒｿｯﾄﾞでは、1.23 E12 などの数字は扱いません。通常の
    1825         * 数字とﾋﾟﾘｵﾄﾞで構成された文字列のみ、変換対象になります。
    1826         * (ただし、不正な文字列を与えてもｴﾗｰﾁｪｯｸはしていません。)
    1827         * minFraction には、小数点部に与える固定値を指定します。入力文字列が
    1828         * その桁数より少ない場合は、０埋めします。
    1829         * 多い場合は、四捨五入します。
    1830         * minFraction が 0 の場合は、小数点は付きません。
    1831         * ".12" などの小数点は、必ず先頭に 0 が付きます。
    1832         * 入力文字列が null か、ｾﾞﾛ文字列時は、そのまま入力ﾃﾞｰﾀを返します。
    1833         *
    1834         * <pre>
    1835         *      DecimalFormat format = new DecimalFormat( "#,##0.00########" );
    1836         *      double dd = Double.parseDouble( val );
    1837         *      return format.format( dd );
    1838         * </pre>
    1839         * に対して、minFraction分の小数以下のｾﾞﾛの指定と、inに ',' が
    1840         * 含まれた処理を追加した感じになります。
    1841         *
    1842         * @og.rev 4.0.0.0 (2007/10/26) 空白のﾄﾘﾑ処理を追加
    1843         * @og.rev 6.0.4.0 (2014/11/28) 小数点指定が、0 の場合、小数点以下は表示しない
    1844         * @og.rev 6.2.0.0 (2015/02/27) 小数点指定の精度に合わせるのと、内部ﾛｼﾞｯｸ完全置換
    1845         * @og.rev 6.2.0.1 (2015/03/06) 互換性の関係で、nullかｾﾞﾛ文字列の時は、そのまま、in を返す。
    1846         * @og.rev 6.3.6.1 (2015/08/28) throw new OgRuntimeException するのではなく、System.err.println する。
    1847         * @og.rev 6.3.8.5 (2015/10/16) ogErrMsgPrint 使用。
    1848         * @og.rev 6.4.2.0 (2016/01/29) ogErrMsgPrint ﾒｿｯﾄﾞを、ThrowUtil ｸﾗｽに移動のため、修正
    1849         *
    1850         * @param       inStr           変換元の文字列
    1851         * @param       minFraction     変換時の小数点以下の固定桁数
    1852         *
    1853         * @return      ｶﾝﾏ編集後の数字型文字列
    1854         */
    1855        public static String numberFormat( final String inStr, final int minFraction ) {
    1856//              if( inStr == null || inStr.isEmpty() ) { return inStr ; }               // 6.2.0.1 (2015/03/06) 互換性の関係
    1857                if( isNull( inStr ) ) { return inStr ; }                                                // 6.9.2.1 (2018/03/12) isNull 置き換え
    1858
    1859                String rtn = inStr;
    1860
    1861                try {
    1862                        final double dd = StringUtil.parseDouble( rtn );
    1863
    1864                        if( FMT1.length > minFraction ) {
    1865                                synchronized( FMT1[minFraction] ) {
    1866                                        rtn = FMT1[minFraction].format( dd );
    1867                                }
    1868                        }
    1869                        else {
    1870                                final String fmt = "#,##0." + ZERO.substring( 0,minFraction );
    1871                                rtn = new DecimalFormat( fmt ).format( dd );
    1872                        }
    1873                }
    1874                catch( final Throwable th ) {
    1875                        final String errMsg = "ERROR:" + th.getLocalizedMessage() + CR
    1876                                                        + " in=[" + inStr + "] , minFraction=[" + minFraction + "]" ;
    1877                        // 6.3.8.5 (2015/10/16) ogErrMsgPrint 使用。
    1878                        System.err.println( ThrowUtil.ogThrowMsg( errMsg,th ) );                                // 6.4.2.0 (2016/01/29)
    1879                }
    1880
    1881                return rtn;
    1882        }
    1883
    1884//      /**
    1885//       * 識別id に応じた ｵﾌﾞｼﾞｪｸﾄを作成します。
    1886//       * 作成するには、ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰが必要です。
    1887//       *
    1888//       * @og.rev 7.2.5.0 (2020/06/01) ClassLoaderを引数にするnewInstanceﾒｿｯﾄﾞを廃止します。
    1889//       *
    1890//       * @param       cls 作成するｸﾗｽのﾌﾙﾈｰﾑ
    1891//       *
    1892//       * @return      ｵﾌﾞｼﾞｪｸﾄ
    1893//       * @og.rtnNotNull
    1894//       * @throws      RuntimeException 何らかのｴﾗｰが発生した場合
    1895//       */
    1896//      public static Object newInstance( final String cls ) {
    1897//              return newInstance( cls,Thread.currentThread().getContextClassLoader() );
    1898//      }
    1899
    1900        /**
    1901         * 指定されたｸﾗｽﾛｰﾀﾞを使って、識別id に応じた ｵﾌﾞｼﾞｪｸﾄを作成します。
    1902         * 作成するには、ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰが必要です。
    1903         * initialize ﾊﾟﾗﾒｰﾀは true 相当(それまでに初期化されていない場合だけ初期化)です。
    1904         *
    1905         * @og.rev 6.4.3.3 (2016/03/04) ﾘﾌﾚｸｼｮﾝ系の例外の共通ｸﾗｽに置き換えます。
    1906         * @og.rev 6.8.2.3 (2017/11/10) java9対応(cls.newInstance() → cls.getDeclaredConstructor().newInstance())
    1907         * @og.rev 7.2.5.0 (2020/06/01) ClassLoaderを引数にするnewInstanceﾒｿｯﾄﾞを廃止します。
    1908         *
    1909         * @param       cls     作成するｸﾗｽのﾌﾙﾈｰﾑ
    1910         *
    1911         * @return      ｵﾌﾞｼﾞｪｸﾄ
    1912         * @og.rtnNotNull
    1913         * @throws      RuntimeException 何らかのｴﾗｰが発生した場合
    1914         */
    1915//      public static Object newInstance( final String cls,final ClassLoader loader ) {
    1916        public static Object newInstance( final String cls ) {
    1917                try {
    1918//                      return Class.forName( cls,true,loader ).getDeclaredConstructor().newInstance();                 // 6.8.2.3 (2017/11/10)
    1919                        return Class.forName( cls ).getDeclaredConstructor().newInstance();                                             // 7.2.5.0 (2020/06/01)
    1920                }
    1921                catch( final NoSuchMethodException | InvocationTargetException ex ) {                                           // 6.8.2.3 (2017/11/10)
    1922                        final String errMsg = "指定のメソッド(コンストラクタ)が見つかりませんでした。class=[" + cls + "]" + CR
    1923                                                + ex.getMessage();
    1924                        throw new OgRuntimeException( errMsg,ex );
    1925                }
    1926                catch( final ReflectiveOperationException ex ) {
    1927                        final String errMsg = "Class.forName( String,boolean,ClassLoader ).newInstance() 処理に失敗しました class=[" + cls + "]" + CR
    1928                                                + ex.getMessage() ;
    1929                        throw new OgRuntimeException( errMsg,ex );
    1930                }
    1931        }
    1932
    1933        /**
    1934         * 指定のURL文字列同士を連結させます。
    1935         * そのとき、後方URLが、絶対ﾊﾟｽの場合は、連結せず 後方URLを返します。
    1936         * 第２引数以降は、絶対ﾊﾟｽ判定をせず直前のURLの末尾判定のみで連結します。
    1937         *
    1938         * 絶対ﾊﾟｽかどうかは、通常のﾌｧｲﾙ属性と同様に、先頭が、'/' (UNIX)または、
    1939         * ２文字目が、":" (Windows)の場合、または、先頭が "\" (ﾈｯﾄﾜｰｸﾊﾟｽ)で
    1940         * 始まる場合で判断します。
    1941         * 連結時に、前方URLの末尾に "/" を付加します。
    1942         *
    1943         * 処理の互換性確保のため、第３引数の可変長引数を追加しています。
    1944         *
    1945         * @og.rev 5.0.0.1 (2009/08/15) 不要なｵﾌﾞｼﾞｪｸﾄの生成を抑制する。
    1946         * @og.rev 5.6.5.2 (2013/06/21) 第３引数を可変長引数に変更
    1947         * @og.rev 6.4.5.0 (2016/04/08) 引数をCharSequenceに変更
    1948         * @og.rev 6.4.7.2 (2016/06/20) 絶対ﾊﾟｽの判定を、可変長URLにも適用する。
    1949         *
    1950         * @param       url1    先頭URLCharSequence
    1951         * @param       urls    後方URL可変長CharSequence(絶対ﾊﾟｽの場合は、返り値)
    1952         *
    1953         * @return      URL文字列同士の連結結果 url1 + url2(url2が絶対ﾊﾟｽの場合は、url2から連結開始)
    1954         * @og.rtnNotNull
    1955         */
    1956        public static String urlAppend( final CharSequence url1,final CharSequence... urls ) {
    1957                final StringBuilder rtnUrl = new StringBuilder( BUFFER_MIDDLE );
    1958
    1959//              if( url1 != null && url1.length() > 0 ) { rtnUrl.append( url1 ) ; }
    1960                if( isNotNull( url1 ) ) { rtnUrl.append( url1 ) ; }                                     // 6.9.2.1 (2018/03/12) isNotNull 置き換え
    1961
    1962                // ここからが、追加分
    1963                for( final CharSequence url : urls ) {
    1964//                      if( url != null && url.length() > 0 ) {
    1965                        if( isNotNull( url ) ) {                                                                                // 6.9.2.1 (2018/03/12) isNotNull 置き換え
    1966                                if( rtnUrl.length() == 0                                                                        // 戻り値が未設定の場合。
    1967                                        ||      url.charAt(0) == '/'                                                            // 実ﾃﾞｨﾚｸﾄﾘが UNIX
    1968                                        ||      url.length() > 1 && url.charAt(1) == ':'                        // 実ﾃﾞｨﾚｸﾄﾘが Windows
    1969                                        ||      url.charAt(0) == '\\' ) {                                                       // 実ﾃﾞｨﾚｸﾄﾘが ﾈｯﾄﾜｰｸﾊﾟｽ
    1970                                                rtnUrl.setLength( 0 );                                                          // ｸﾘｱ
    1971                                                rtnUrl.append( url ) ;
    1972                                }
    1973                                else {
    1974                                        final char ch = rtnUrl.charAt( rtnUrl.length()-1 ) ;    // 必ず、何らかのURLがappend済みのはず。
    1975                                        if( ch == '/' || ch == '\\' ) {
    1976                                                rtnUrl.append( url ) ;
    1977                                        }
    1978                                        else {
    1979                                                rtnUrl.append( '/' ).append( url ) ;                            // 6.0.2.5 (2014/10/31) char を append する。
    1980                                        }
    1981                                }
    1982                        }
    1983                }
    1984
    1985                return rtnUrl.toString() ;
    1986        }
    1987
    1988        /**
    1989         * Unicode文字列の値を HTML のｴｽｹｰﾌﾟ記号(&amp;#xZZZZ;)に変換します。
    1990         *
    1991         * SJIS(JA16SJIS) で作成されたﾃﾞｰﾀﾍﾞｰｽに、(NVARCHAR2)を使用して中国語等を登録するのは
    1992         * 非常に複雑でかつ、ﾘｽｸが大きい処理になります。
    1993         * ORACLE殿でも、自信を持っては勧められない機能とのｺﾒﾝﾄを頂いています。
    1994         * そこで、HTMLでのｴｽｹｰﾌﾟ文字を使用して、Unicodeを文字列化して登録する為の
    1995         * DBType として、新規に作成します。
    1996         * ここでは、入力文字を、ｷｬﾗｸﾀ(char)型に分解し、(&amp;#xZZZZ;)に変換していきます。
    1997         * よって、通常に1文字(Shift-JISで２Byte,UTF-8で３Byte)が、８Byteになります。
    1998         * この変換された文字列を、HTML上でそのまま取り出すと、元のUnicode文字に戻る為、
    1999         * 通常のShift-JISでは、扱えない文字(中国語など)でも表示可能になります。
    2000         * ここでは、2ﾊﾞｲﾄ文字のみ、変換しています。
    2001         *
    2002         * @og.rev 6.4.5.0 (2016/04/08) 引数をCharSequenceに変更
    2003         *
    2004         * @param       value   変換前のCharSequence
    2005         *
    2006         * @return      HTMLのｴｽｹｰﾌﾟ記号(&amp;#xZZZZ;)
    2007         * @og.rtnNotNull
    2008         */
    2009        public static String getUnicodeEscape( final CharSequence value ) {
    2010//              if( value == null || value.length() == 0 ) { return ""; }
    2011                if( isEmpty( value ) ) { return ""; }                                   // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    2012
    2013                final StringBuilder rtn = new StringBuilder( value.length() * 4 );
    2014
    2015                for( int i=0; i<value.length(); i++ ) {
    2016                        final char ch = value.charAt(i);
    2017
    2018                        if( ch > 0xff ) {
    2019                                final String hex = Integer.toHexString( (int)ch ) ;
    2020                                rtn.append( UTF_STR[hex.length()] ).append( hex ).append( ';' );        // 6.0.2.5 (2014/10/31) char を append する。
    2021                        }
    2022                        else {
    2023                                rtn.append( ch );
    2024                        }
    2025                }
    2026
    2027                return rtn.toString();
    2028        }
    2029
    2030        /**
    2031         * HTML のｴｽｹｰﾌﾟ記号(&amp;#xZZZZ;)をUnicode文字列に戻します。
    2032         *
    2033         * HTMLでのｴｽｹｰﾌﾟ文字を使用して登録された文字を、Unicodeに戻します。
    2034         * (&amp;#xZZZZ;)の８Byteを、もとのｷｬﾗｸﾀｺｰﾄﾞに戻し、合成します。
    2035         * ここでは、通常の文字列に混在したｴｽｹｰﾌﾟ文字も戻せるようにします。
    2036         *
    2037         * @og.rev 5.9.5.3 (2016/02/26) 無限ﾙｰﾌﾟ対応
    2038         *
    2039         * @param       value   HTMLのｴｽｹｰﾌﾟ記号(&amp;#xZZZZ;)を含む文字列
    2040         *
    2041         * @return      通常のUnicode文字列
    2042         * @og.rtnNotNull
    2043         */
    2044        public static String getReplaceEscape( final String value ) {
    2045//              if( value == null || value.isEmpty() ) { return ""; }
    2046                if( isEmpty( value ) ) { return ""; }                                   // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    2047
    2048                final StringBuilder rtn = new StringBuilder( value );
    2049
    2050                int st = rtn.indexOf( "&#" );
    2051                while( st >= 0 ) {
    2052                        if( st+7 < rtn.length() && rtn.charAt( st+7 ) == ';' ) {
    2053                                final int ch = Integer.parseInt( rtn.substring( st+3,st+7 ),16 );
    2054                                rtn.replace( st,st+8, Character.toString( (char)ch ) );
    2055                        }
    2056                        st = rtn.indexOf( "&#",st + 1 );                                        // 5.9.5.3 (2016/02/26) 無限ﾙｰﾌﾟ対応
    2057                }
    2058
    2059                return rtn.toString();
    2060        }
    2061
    2062        /**
    2063         * 文字列をdoubleに変換します。
    2064         *
    2065         * これは、Double.parseDouble( value ) と、ほぼ同じ動作を行います。
    2066         * 内部的には、引数の ｶﾝﾏ(,) を削除した文字列を、Double.parseDouble( value )
    2067         * に渡します。
    2068         * また、引数が、null,ｾﾞﾛ文字列,'_' の時には、0.0 を返します。
    2069         *
    2070         * @og.rev 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。)
    2071         *
    2072         * @param       value   doubleに変換する元の文字列
    2073         *
    2074         * @return      変換後のdouble数値
    2075         */
    2076        public static double parseDouble( final String value ) {
    2077                double rtn ;
    2078
    2079//              if( value == null || value.isEmpty() || value.equals( "_" ) ) {
    2080                if( isNull( value ) || "_".equals( value ) ) {                                  // 6.9.2.1 (2018/03/12) isNull 置き換え
    2081                        rtn = 0.0d;
    2082                }
    2083                else if( value.indexOf( ',' ) < 0 ) {
    2084                        rtn = Double.parseDouble( value );
    2085                }
    2086                else {
    2087                        // 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。)
    2088                        rtn = Double.parseDouble( value.replaceAll( ",","" ) );
    2089                }
    2090
    2091                return rtn ;
    2092        }
    2093
    2094        /**
    2095         * 引数からspanﾀｸﾞを取り除いて返します。
    2096         *
    2097         * 引数が、&lt;span ･･･&gt;YYYY&lt;/span&gt;形式の場合、YYYY のみ出力します。
    2098         * この処理では、先頭にspan が一つだけある場合、削除します。
    2099         * 複数の span や、div などを削除する場合は、#tagCut(String) ﾒｿｯﾄﾞで処理します。
    2100         *
    2101         * @og.rev 4.3.4.3 (2008/12/22) TableWriterで利用していたものを移動
    2102         *
    2103         * @param       data    元のString文字列
    2104         *
    2105         * @return      spanﾀｸﾞが取り除かれた文字列(引数が null の場合は、そのまま null が返ります)
    2106         * @see         #tagCut(String)
    2107         */
    2108        public static String spanCut( final String data ) {
    2109                String rtn = data;
    2110                if( data != null && data.startsWith( "<span" ) ) {
    2111                        final int st = data.indexOf( '>' );
    2112                        final int ed = data.indexOf( "</span>",st );
    2113                        rtn = data.substring( st+1,ed );
    2114                }
    2115
    2116                return rtn ;
    2117        }
    2118
    2119        /**
    2120         * 引数からﾀｸﾞを取り除いて返します。
    2121         *
    2122         * 引数が、&lt;xxxx ･･･&gt;YYYY&lt;/xxxx&gt;形式の場合、YYYY のみ出力します。
    2123         * この処理では、すべてのﾀｸﾞを削除し、BODY部をつなげます。
    2124         * &lt;xxxx/&gt; の様な、BODY要素を持たない場合は、ｾﾞﾛ文字列になります。
    2125         *
    2126         * @og.rev 6.2.0.0 (2015/02/27) 引数からﾀｸﾞを削除し、BODY文字列を切り出します。
    2127         *
    2128         * @param       data    元のString文字列
    2129         *
    2130         * @return      ﾀｸﾞが取り除かれた文字列(引数が null の場合は、そのまま null が返ります)
    2131         */
    2132        public static String tagCut( final String data ) {
    2133//              if( data == null || data.isEmpty() || data.indexOf( '<' ) < 0 ) { return data; }
    2134                if( isEmpty( data ) || data.indexOf( '<' ) < 0 ) { return data; }                       // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    2135
    2136                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    2137
    2138                boolean tagOut = true;
    2139                for( int i=0; i<data.length(); i++ ) {
    2140                        final char ch =data.charAt( i );
    2141                        if(      ch == '<' ) { tagOut = false; continue; }      // ﾀｸﾞの開始
    2142                        else if( ch == '>' ) { tagOut = true;  continue; }      // ﾀｸﾞの終了
    2143
    2144                        if( tagOut ) { rtn.append( ch ); }
    2145                }
    2146
    2147                return rtn.toString() ;
    2148        }
    2149
    2150        /**
    2151         * 簡易CSS形式のﾌｫｰﾏｯﾄを、Mapにｾｯﾄします。
    2152         *
    2153         * 簡易CSS形式とは、ｾﾚｸﾀのない、{ ﾌﾟﾛﾊﾟﾃｨ1 : 値1 ; ･･･ } 形式とします。
    2154         * これを、ﾌﾟﾛﾊﾟﾃｨ1 と 値1 のMap にｾｯﾄする処理を行います。
    2155         * ﾌﾞﾛｯｸｺﾒﾝﾄは、削除されます。ﾗｲﾝｺﾒﾝﾄは使えません。
    2156         * また、同一ﾌﾟﾛﾊﾟﾃｨが記述されている場合は、後処理を採用します。
    2157         *
    2158         * なお、入力ﾃｷｽﾄが、null か、{…} が存在しない場合は、空のMapを返します。
    2159         *
    2160         * @og.rev 5.6.5.2 (2013/06/21) 新規追加
    2161         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
    2162         * @og.rev 6.4.3.3 (2016/03/04) 戻すMapが、not null制限つきであることを示すため、ConcurrentMap に置き換えます。
    2163         * @og.rev 8.0.0.0 (2021/09/30) CSS形式の整合性ﾁｪｯｸを行います。
    2164         *
    2165         * @param       cssText 簡易CSS形式のﾌｫｰﾏｯﾄ文字列
    2166         *
    2167         * @return      ﾊﾟｰｽ結果のMap(ConcurrentMap)
    2168         * @throws      OgRuntimeException 簡易CSS形式のﾌｫｰﾏｯﾄの整合性不良の時
    2169         * @og.rtnNotNull
    2170         */
    2171        public static ConcurrentMap<String,String> cssParse( final String cssText ) {
    2172                final ConcurrentMap<String,String> cssMap = new ConcurrentHashMap<>();
    2173
    2174                if( cssText != null ) {
    2175                        // まずｺﾒﾝﾄを削除します。
    2176                        final StringBuilder buf = new StringBuilder( cssText );
    2177
    2178                        int ad1 = buf.indexOf( "/*" );
    2179                        while( ad1 >= 0 ) {
    2180                                final int ad2 = buf.indexOf( "*/" , ad1 );
    2181                                if( ad2 < 0 ) { buf.delete( ad1,buf.length() ); break; }                // 閉じてなければ以降を全削除
    2182                                buf.delete( ad1,ad2+2 );
    2183                                ad1 = buf.indexOf( "/*" );                              // ｺﾒﾝﾄは削除されたので、初めから検索する。
    2184                        }
    2185
    2186                        // 処理対象は、{ ～ } の間の文字列
    2187                        ad1 = buf.indexOf( "{" ) ;                                      // なければ、0:先頭から
    2188                        final int ad2 = buf.lastIndexOf( "}" );         // 後ろから検索(複数存在する場合の中間は無視する)
    2189
    2190                        if( ad1 >= 0 && ad2 > 0 ) {
    2191                                final String tempText = buf.substring( ad1+1,ad2 ).trim();              // これが処理対象の文字列
    2192                                if( tempText.isEmpty() ) { return cssMap ; }                                    // 空文字列の場合は抜ける
    2193
    2194                                if( tempText.contains( "//" ) ) {
    2195                                        final String errMsg = "ラインコメント『//』は使えません。"+ CR
    2196                                                                        + " cssText=[" + cssText + "]" ;
    2197                                        throw new OgRuntimeException( errMsg );
    2198                                }
    2199
    2200                                // 8.0.0.0 (2021/09/30) CSS形式の整合性ﾁｪｯｸを行います。
    2201                                // KEY:VAL; なので、':' と ';' の個数は一致するはず
    2202                                int cnt1 = 0;
    2203                                int cnt2 = 0;
    2204                                boolean errFlag = false;
    2205                                for( int i=0; i<tempText.length(); i++ ) {
    2206                                        final char ch = tempText.charAt(i);
    2207                                        if( ch == ':' ) { cnt1++; }                                     // 必ず最初に見つかる
    2208                                        else if( ch == ';' ) { cnt2++; }                        // 次に見つかる
    2209
    2210                                        if( cnt1 != cnt2 && cnt1 != cnt2+1 || ch == '{' || ch == '}' ) {        // ：と;の数と前後関係のﾁｪｯｸ
    2211                                                errFlag = true;
    2212                                                break;
    2213                                        }
    2214                                }
    2215                                if( errFlag || cnt1 == 0 || cnt2 == 0 ) {                                                               // ':' と ';' の個数が不一致か存在しない場合
    2216                                        final String errMsg = "':' と ';' の個数が不一致か存在しないか、{} が不整合です。"+ CR
    2217                                                                        + " cssText=[" + cssText + "]" ;
    2218                                        throw new OgRuntimeException( errMsg );
    2219                                }
    2220
    2221                                // 6.4.3.3 (2016/03/04) ちょっとした変更
    2222                                for( final String recode : tempText.split( ";" ) ) {    // KEY1 : VAL1; の ; で分割する。
    2223                                        final int ad = recode.indexOf( ':' );
    2224                                        if( ad > 0 ) {
    2225                                                final String key = recode.substring( 0,ad ).trim();
    2226                                                final String val = recode.substring( ad+1 ).trim();
    2227                                                if( key.isEmpty() || val.isEmpty() ) { continue; }              // どちらかが空文字列の場合は、設定しない。
    2228
    2229                                                cssMap.put( key,val );
    2230                                        }
    2231                                }
    2232                        }
    2233                }
    2234
    2235                return cssMap ;
    2236        }
    2237
    2238//      /**
    2239//       * 引数から空白文字を削除して返します。
    2240//       *
    2241//       * @og.rev 5.6.9.4 (2013/10/31) TableWriterで利用していたものを移動
    2242//       * @og.rev 6.9.2.1 (2018/03/12) 使用箇所が、1箇所だけなので、StringUtilから移動する。
    2243//       *
    2244//       * @param       data    元のString文字列
    2245//       *
    2246//       * @return      空白文字が取り除かれた文字列
    2247//       */
    2248//      public static String deleteWhitespace( final String data ) {
    2249//              // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    2250//              return data == null || data.isEmpty() ? data : data.replaceAll( "\\s", "" ) ;           // isNull 判定は使えない。
    2251//      }
    2252
    2253        /**
    2254         * 引数の文字列が、引数の char で始まるかどうか判定します[始まる場合は、true]。
    2255         *
    2256         * これは、PMDで言う所の、String.startsWith can be rewritten using String.charAt(0)
    2257         * の書き換え処理に相当します。
    2258         * boolean flag = data != null &amp;&amp; data.startsWith( chStr ); 的な処理を、
    2259         * boolean flag = data != null &amp;&amp; data.length() &gt; 0 &amp;&amp; data.charAt(0) == ch;
    2260         * に書き換える代わりに、このﾒｿｯﾄﾞを使用します。
    2261         *
    2262         * 内部ﾛｼﾞｯｸは、上記の相当します。
    2263         *
    2264         * @og.rev 6.2.0.0 (2015/02/27) 1文字 String.startsWith の String.charAt(0) 変換
    2265         * @og.rev 6.4.5.0 (2016/04/08) 引数をCharSequenceに変更
    2266         *
    2267         * @param       data    引数のCharSequence
    2268         * @param       ch              ﾁｪｯｸするchar
    2269         *
    2270         * @return      引数文字列が、nullでなく、ｾﾞﾛ文字列でなく、引数char で始まる場合は、true
    2271         * @see         java.lang.String#startsWith(String)
    2272         */
    2273        public static boolean startsChar( final CharSequence data , final char ch ) {
    2274                return data != null && data.length() > 0 && data.charAt(0) == ch;                       // ｽﾍﾟｰｽも判定対象にするため、isNull は使わない。
    2275        }
    2276
    2277        /**
    2278         * 引数から指定文字の分のﾊﾞｲﾄ数で切った文字列を返します。
    2279         * 文字列のﾊﾞｲﾄ数は指定のｴﾝｺｰﾄﾞでｶｳﾝﾄします。
    2280         * （文字の途中で切れる事はありません）
    2281         *
    2282         * @og.rev 5.9.1.3 (2015/10/30) 新規作成
    2283         * @og.rev 6.4.2.0 (2016/01/29) StringUtil#ogStackTrace(Throwable) を、ThrowUtil##ogStackTrace(Throwable) に変更。
    2284         *
    2285         * @param       org                     元のString文字列
    2286         * @param       cutBytes        切るﾊﾞｲﾄ数
    2287         * @param       enc                     文字列のｴﾝｺｰﾄﾞ
    2288         *
    2289         * @return      ﾊﾞｲﾄ数で切った文字列
    2290         */
    2291        public static String cut( final String org, final int cutBytes, final String enc ) {
    2292                try {
    2293//                      if( org == null || org.length() == 0 || cutBytes <= 0 || org.getBytes(enc).length <= cutBytes ) {       // isNul 判定は使いません。
    2294//                              return org;
    2295//                      }
    2296                        if( isEmpty( org,enc ) || cutBytes <= 0 || org.getBytes(enc).length <= cutBytes ) { return org; }       // 6.9.2.1 (2018/03/12) isEmpty 置き換え
    2297
    2298                        final StringBuilder cutSb = new StringBuilder( BUFFER_MIDDLE );
    2299                        final StringBuilder tmpSb = new StringBuilder( BUFFER_MIDDLE );
    2300
    2301                        for( int i=0; i<org.length(); i++ ) {
    2302                                final String cut = org.substring(i, i + 1);
    2303                                if( cutBytes < tmpSb.toString().getBytes(enc).length + cut.getBytes(enc).length ) {
    2304                                        cutSb.append( tmpSb.toString() );
    2305                                        break;
    2306                                }
    2307                                tmpSb.append(cut);
    2308                        }
    2309                        return cutSb.toString();
    2310                }
    2311                catch( final UnsupportedEncodingException ex ) {
    2312                        // 6.4.1.1 (2016/01/16) PMD refactoring.        Avoid printStackTrace(); use a logger call instead.
    2313                        // 6.4.2.0 (2016/01/29) StringUtil#ogStackTrace(Throwable) を、ThrowUtil##ogStackTrace(Throwable) に変更。
    2314                        final String errMsg = "エンコードが不正のため、バイトカットできません。"
    2315                                                                                + " org=[" + org + "] , byteSize=[" + cutBytes + "] , encode=[" + enc + "]" ;
    2316
    2317                        System.err.println( ThrowUtil.ogThrowMsg( errMsg,ex ) );
    2318                        return org;
    2319                }
    2320        }
    2321
    2322        /**
    2323         * 引数から指定文字の分のﾊﾞｲﾄ数で切った文字列を返します。
    2324         * ﾊﾞｲﾄ数のｶｳﾝﾄはUTF-8として行います。
    2325         *
    2326         * @og.rev 5.9.1.3 (2015/10/30) 新規作成
    2327         *
    2328         * @param       org                     元のString文字列
    2329         * @param       cutBytes        切るﾊﾞｲﾄ数
    2330         *
    2331         * @return      ﾊﾞｲﾄ数で切った文字列
    2332         */
    2333        public static String cut( final String org, final int cutBytes ) {
    2334                return cut( org, cutBytes, "UTF-8");
    2335        }
    2336
    2337        /**
    2338         * 元の引数から開始文字列と終了文字列の間の文字列と、残りを連結した文字列を生成します。
    2339         * 戻り値は、連結した文字列で、切り取った間の文字列は、関数型ｲﾝﾀﾌｪｰｽの引数に設定されます。
    2340         * なお、文字列の切り出しは、1度だけです。最初に見つかった、開始文字列と、その次に見つかった
    2341         * 終了文字列の間を切り取って、前後を連結するだけです。
    2342         *
    2343         * 元の文字列が、nullの場合は、return null で、関数I/Fは call されません。
    2344         * 元の文字列に、stStr(開始文字列)が含まれない/またはnullの場合は、return 元の文字列で、関数I/Fは call されません。
    2345         * 元の文字列に、stStr(開始文字列)が含まれ、edStr(終了文字列)が含まれない場合は、return 開始文字列以前と、(v) -> 開始文字列以降 をcallします。
    2346         * 元の文字列に、stStrもedStrも含む場合は、それらの間の文字列を削除(stStr,edStr含む)と、その間の文字列を引数に、
    2347         *   return 連結した文字列と、(v) -> 切り取った間の文字列 をcallします。
    2348         * 上記の場合、間の文字列が存在しない場合は、空文字列になります。
    2349         *
    2350         * stStr(開始文字列)とed(終了文字列)に関しては、trim() して、前後の空欄は削除します。
    2351         *
    2352         * 例） splitStartEnd( "abc class= XYZ ; efg" , "class=" , ";" , v -> call(v) );
    2353         * return "abc  efg"
    2354         * call   "XYZ"
    2355         *
    2356         * 例） splitStartEnd( "abc class= XYZ efg" , "class=" , ";" , v -> call(v) );
    2357         * return "abc "
    2358         * call   "XYZ efg"
    2359         *
    2360         * 例） splitStartEnd( "abc style= XYZ ; efg" , "class=" , ";" , v -> call(v) );
    2361         * return "abc style= XYZ ; efg"
    2362         * call   実行されない(nullだから)
    2363         *
    2364         * @og.rev 8.0.0.2 (2021/10/15) 新規作成
    2365         *
    2366         * @param       org             元のString文字列(nullも可)
    2367         * @param       stStr   開始文字列
    2368         * @param       edStr   終了文字列
    2369         * @param       cons    関数型ｲﾝﾀﾌｪｰｽで、切り取った文字列を引数に呼び出されます。
    2370         *
    2371         * @return 削除後連結文字列と切り出した文字列の配列(必ず 2個の配列を返す)
    2372         */
    2373        public static String splitStartEnd( final String org, final String stStr, final String edStr , final Consumer<String> cons ) {
    2374                String val1 = org ;             // 切り取られた、前後の文字列を連結
    2375
    2376                if( org != null && stStr != null ) {
    2377                        final int st = org.indexOf( stStr );
    2378                        if( st >= 0 ) {
    2379                                final int cutSt = st + stStr.length();                          // 見つけた開始文字列＋開始文字列の長さ
    2380                                // edStr の nullﾁｪｯｸと、indexOf 判定を兼ねる。
    2381                                final int ed = edStr == null ? -1 : org.indexOf( edStr , cutSt );
    2382                                // stStr と、edStr の間の文字列を切り取る
    2383                                final String val2 ;             // 間の文字列
    2384                                if( ed >= 0 ) {
    2385                                        val1 = org.substring( 0,st ) + org.substring( ed+edStr.length() );      // edStr は含まない
    2386                                        // "abc class= XYZ ; efg" の場合、"XYZ" を取得
    2387                                        val2 = org.substring( cutSt , ed ).trim();              // 前後の空白は除去
    2388                                }
    2389                                else {
    2390                                        val1 = org.substring( 0,st );
    2391                                        // "abc class= XYZ efg" の場合、"XYZ efg" を取得
    2392                                        val2 = org.substring( cutSt ).trim();                   // 前後の空白は除去
    2393                                }
    2394                                cons.accept( val2 );    // 関数型ｲﾝﾀﾌｪｰｽの呼び出し。
    2395                        }
    2396                }
    2397                return val1 ;
    2398        }
    2399
    2400        /**
    2401         * Unicode文字列から元の文字列に変換します。(例："￥u3042" → "あ")
    2402         *
    2403         * @og.rev 8.0.2.0 (2021/11/30) 新規作成
    2404         *
    2405         * @param       unicode Unicode文字列("\u3042")
    2406         * @return      通常の文字列
    2407         */
    2408        public static String convertToOiginal( final String unicode ) {
    2409                final StringBuilder rtn = new StringBuilder( unicode );
    2410
    2411                int st = rtn.indexOf( "\\u" );
    2412                while( st >= 0 ) {
    2413                        final int ch = Integer.parseInt( rtn.substring( st+2,st+6 ),16 );
    2414                        rtn.replace( st,st+6, Character.toString( (char)ch ) );
    2415
    2416                        st = rtn.indexOf( "\\u",st + 1 );
    2417                }
    2418                return rtn.toString();
    2419        }
    2420}