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