    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.system;
    017
    018import java.util.function.Function;
    019import java.util.function.IntFunction;                                          // 6.4.4.2 (2016/04/01)
    020import java.util.function.Supplier;                                                     // 6.4.4.2 (2016/04/01)
    021
    022/**
    023 * 内部にStringBuilderを持った、文字列連結クラスです。
    024 *
    025 * 文字列連結時に、取り込む／取り込まないの判断を行う、boolean 付きの
    026 * appendIf メソッドや、null値を無視する append など、用意しています。
    027 *
    028 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    029 * @og.rev 6.4.5.0 (2016/04/08) CharSequenceインタフェースの追加
    030 *
    031 * @og.group その他
    032 *
    033 * @version  6.0
    034 * @author       Kazuhiko Hasegawa
    035 * @since    JDK8.0,
    036 */
    037public final class OgBuilder implements CharSequence {
    038        private final StringBuilder buf = new StringBuilder( HybsConst.BUFFER_MIDDLE );
    039
    040        /**
    041         * デフォルトコンストラクター
    042         *
    043         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    044         */
    045        public OgBuilder() { super(); }         // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    046
    047        /**
    048         * 引数の可変長文字列を追加する appendです。
    049         *
    050         * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
    051         *
    052         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    053         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    054         *
    055         * @param arys  追加する可変長CharSequence
    056         * @return      自分自身
    057         * @og.rtnNotNull
    058         */
    059        public OgBuilder append( final CharSequence... arys ) {
    060                if( arys != null ) {
    061                        for( final CharSequence str : arys ) {
    062                                if( str != null ) { buf.append( str ); }
    063                        }
    064                }
    065
    066                return this;
    067        }
    068
    069        /**
    070         * 連結文字列を、使用して、可変長引数のCharSequenceを連結して返します。
    071         * 連結文字列が、null の場合は、CharSequenceをそのまま連結していきます。
    072         * 連結するCharSequenceが null の場合は、連結しません。
    073         * 連結文字列は、一番最後は出力されません。
    074         *
    075         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
    076         *
    077         * @param       delimiter       連結文字列
    078         * @param       arys    連結する可変長CharSequence
    079         *
    080         * @return      自分自身
    081         * @og.rtnNotNull
    082         */
    083        public OgBuilder join( final String delimiter , final CharSequence... arys ) {
    084                if( delimiter == null ) { return append( arys ); }
    085
    086                if( arys != null ) {
    087                        boolean isAdd = false;
    088                        for( final CharSequence str : arys ) {
    089                                if( str != null && str.length() > 0 ) {
    090                                        buf.append( str ).append( delimiter );
    091                                        isAdd = true;
    092                                }
    093                        }
    094                        if( isAdd ) { buf.setLength( buf.length()-delimiter.length() ); }       // 最後に追加した delimiter を削除。
    095                }
    096
    097                return this;
    098        }
    099
    100        /**
    101         * 引数の可変長文字列を内部バッファーから削除します。
    102         *
    103         * 引数の可変長文字列の個々の文字列が null の場合は、なにもしません。
    104         * また、内部バッファーに存在しない場合も、何もしません。
    105         *
    106         * ※ 削除の指定は、CharSequenceではなく文字列です。
    107         *
    108         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
    109         *
    110         * @param arys  削除する可変長文字列
    111         * @return      自分自身
    112         * @og.rtnNotNull
    113         */
    114        public OgBuilder delete( final String... arys ) {
    115                if( arys != null ) {
    116                        for( final String str : arys ) {
    117                                if( str != null ) {
    118                                        final int len = str.length();           // 終了の位置を求めるのに使う。
    119                                        int st;
    120                                        while( ( st = buf.indexOf( str ) ) >= 0 ) {
    121                                                buf.delete( st , st+len );
    122                                        }
    123                                }
    124                        }
    125                }
    126
    127                return this;
    128        }
    129
    130        /**
    131         * 引数の可変長CharSequenceを追加し、最後に改行コードを追加する appendです。
    132         *
    133         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
    134         * 引数がnull値の場合は、改行コードのみ追加されます。
    135         *
    136         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    137         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    138         *
    139         * @param arys  追加する文字列可変長(nullは追加しません)
    140         * @return      自分自身
    141         * @see         #append( CharSequence... )
    142         * @og.rtnNotNull
    143         */
    144        public OgBuilder appendCR( final CharSequence... arys ) {
    145                return append( arys ).append( HybsConst.CR );
    146        }
    147
    148        /**
    149         * 引数の可変長CharSequenceを追加する appendです。
    150         *
    151         * 引数の可変長CharSequenceの個々のCharSequenceの中に、一つでも null の場合は、
    152         * すべて追加しません。
    153         * 例えば、key="AAAA" のような文字列を構築したい場合、AAAA 部分が、nullの
    154         * 場合は、key= の箇所も出しません。
    155         *
    156         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    157         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    158         * @og.rev 6.9.0.2 (2018/02/13) not null の対象に、ゼロ文字列も含むようにします。
    159         *
    160         * @param arys  追加する可変長CharSequence
    161         * @return      自分自身
    162         * @og.rtnNotNull
    163         */
    164        public OgBuilder appendNN( final CharSequence... arys ) {
    165                if( arys != null && arys.length > 0 ) {
    166                        final StringBuilder tmp = new StringBuilder( HybsConst.BUFFER_MIDDLE );
    167                        for( final CharSequence str : arys ) {
    168//                              if( str == null ) { return this; }              // 一つでも null があれば、すぐに抜ける。
    169                                // 6.9.0.2 (2018/02/13) 一つでも nullか、ゼロ文字列 があれば、すぐに抜ける。
    170                                if( str == null || str.length() == 0 ) { return this; }
    171                                else { tmp.append( str ); }
    172                        }
    173                        buf.append( tmp );
    174                }
    175                return this;
    176        }
    177
    178        /**
    179         * 文字列を追加するかどうか判定するフラグ付きのappendメソッドです。
    180         *
    181         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
    182         *
    183         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    184         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    185         *
    186         * @param flag  文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
    187         * @param arys  追加する可変長CharSequence
    188         * @return      自分自身
    189         * @og.rtnNotNull
    190         */
    191        public OgBuilder appendIf( final boolean flag , final CharSequence... arys ) {
    192                if( flag && arys != null ) {
    193                        for( final CharSequence str : arys ) {
    194                                if( str != null ) { buf.append( str ); }
    195                        }
    196                }
    197
    198                return this;
    199        }
    200
    201        /**
    202         * 引数の可変長CharSequenceを追加し、最後に改行コードを追加する appendです。
    203         *
    204         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
    205         * 引数がnull値の場合は、改行コードのみ追加されます。
    206         *
    207         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    208         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    209         *
    210         * @param flag  文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
    211         * @param arys  追加する可変長CharSequence
    212         * @return      自分自身
    213         * @see         #appendIf( boolean,CharSequence... )
    214         * @og.rtnNotNull
    215         */
    216        public OgBuilder appendIfCR( final boolean flag , final CharSequence... arys ) {
    217                return appendIf( flag,arys ).append( HybsConst.CR );
    218        }
    219
    220        /**
    221         * 関数を実行した結果を追加するかどうか判定するフラグ付きのappendメソッドです。
    222         * 実行した結果が、null値の場合は、無視します。
    223         * 引数が関数型インタフェースなので、遅延実行することが可能です。
    224         *
    225         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    226         *
    227         * @param <T>   関数型インタフェース(Function)の引数(総称型)
    228         * @param <R>   関数型インタフェース(Function)の戻り値(総称型)
    229         * @param flag  追加するかどうか判定するフラグ(trueの時のみ追加)
    230         * @param key   関数の引数(総称型)
    231         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
    232         * @return      自分自身
    233         * @og.rtnNotNull
    234         */
    235        public <T,R> OgBuilder appendIf( final boolean flag , final T key , final Function<? super T, ? extends R> func ) {
    236                if( flag && func != null ) {
    237                        final R obj = func.apply( key );
    238                        if( obj != null ) { buf.append( obj ); }
    239                }
    240                return this;
    241        }
    242
    243        /**
    244         * 開始から終了までの引数を有する関数を実行した結果を追加するときのappendメソッドです。
    245         * 実行した結果が、null値の場合は、無視します。
    246         * 引数が関数型インタフェースなので、遅延実行することが可能です。
    247         * 関数の結果は、オブジェクトを返します。それを、内部でappendループします。
    248         *
    249         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    250         * @og.rev 6.4.4.2 (2016/04/01) IntFunction に変更。配列ではなく、オブジェクトに変更。
    251         *
    252         * @param <R>   IntFunctionの戻り値の仮想型
    253         * @param st    ループカウンタの初期値(この値を含む)
    254         * @param ed    ループカウンタの終了値(この値を含まない)
    255         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
    256         * @return      自分自身
    257         * @og.rtnNotNull
    258         */
    259        public <R> OgBuilder appendRoop( final int st , final int ed , final IntFunction<R> func ) {
    260                for( int i=st; i<ed; i++ ) {
    261                        final R obj = func.apply( i );
    262                        if( obj != null ) {
    263                                buf.append( obj );
    264                        }
    265                }
    266                return this;
    267        }
    268
    269        /**
    270         * 開始から終了までの引数を有する関数を実行した結果を追加するときのappendメソッドです。
    271         * 連結文字列に null は指定できません。
    272         * 連結文字列は、一番最後には使用しません。
    273         *
    274         * @og.rev 6.4.4.2 (2016/04/01) 連結文字列を指定。
    275         *
    276         * @param <R>   IntFunctionの戻り値の仮想型
    277         * @param st    ループカウンタの初期値(この値を含む)
    278         * @param ed    ループカウンタの終了値(この値を含まない)
    279         * @param delimiter     文字列連結する場合の文字列。nullは指定できません。
    280         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
    281         * @return      自分自身
    282         * @og.rtnNotNull
    283         */
    284        public <R> OgBuilder appendRoop( final int st , final int ed , final String delimiter , final IntFunction<R> func ) {
    285                boolean fstFlg = true;
    286                for( int i=st; i<ed; i++ ) {
    287                        final R obj = func.apply( i );
    288                        if( obj != null ) {
    289                                if( fstFlg ) {
    290                                        buf.append( obj );
    291                                        fstFlg = false;
    292                                }
    293                                else {
    294                                        buf.append( delimiter ).append( obj );
    295                                }
    296                        }
    297                }
    298                return this;
    299        }
    300
    301        /**
    302         * CharSequenceを追加するかどうか判定するフラグ付きのappendメソッドです。
    303         * trueの場合は、第一引数を、falseの場合は、第二引数を追加します。
    304         * 第二引数は、可変長CharSequenceです。
    305         * ともに、CharSequenceがnullの場合は、無視します。
    306         *
    307         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    308         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    309         *
    310         * @param flag  CharSequenceを追加するかどうか判定するフラグ
    311         * @param trueStr       flagがtrueの場合に追加するCharSequence(一つだけ)
    312         * @param falseStr      flagがfalseの場合に追加する可変長CharSequence
    313         * @return      自分自身
    314         * @og.rtnNotNull
    315         */
    316        public OgBuilder appendCase( final boolean flag , final CharSequence trueStr , final CharSequence... falseStr ) {
    317                if( flag ) {
    318                        if( trueStr != null ) { buf.append( trueStr ); }
    319                }
    320                else {
    321                        if( falseStr != null ) {
    322                                for( final CharSequence str : falseStr ) {
    323                                        if( str != null ) { buf.append( str ); }
    324                                }
    325                        }
    326                }
    327
    328                return this;
    329        }
    330
    331        /**
    332         * CharSequenceを追加するかどうか判定するフラグ付きのappendメソッドです。
    333         * trueの場合は、第一引数を、falseの場合は、第二引数を追加します。
    334         * 第一引数、第二引数ともに、配列を返すSupplierクラスです。
    335         * ともに、個々のCharSequenceがnullの場合は、無視します。
    336         *
    337         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    338         * @og.rev 6.4.4.2 (2016/04/01) 引数を、Supplierクラスに変更して、結果を複数指定できるようにします。
    339         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
    340         *
    341         * @param flag  CharSequenceを追加するかどうか判定するフラグ
    342         * @param trueFunc      flagがtrueの場合に実行するFunctionオブジェクト
    343         * @param falseFunc     flagがfalseの場合に追加するFunctionオブジェクト
    344         * @return      自分自身
    345         * @og.rtnNotNull
    346         */
    347        public OgBuilder appendCase( final boolean flag
    348                                                                                , final Supplier<CharSequence[]> trueFunc
    349                                                                                , final Supplier<CharSequence[]> falseFunc ) {
    350                if( flag ) {
    351                        final CharSequence[] tStrs = trueFunc.get();
    352                        if( tStrs != null ) {
    353                                for( final CharSequence tStr : tStrs ) {
    354                                        if( tStr != null ) { buf.append( tStr ); }
    355                                }
    356                        }
    357                }
    358                else {
    359                        final CharSequence[] fStrs = falseFunc.get();
    360                        if( fStrs != null ) {
    361                                for( final CharSequence fStr : fStrs ) {
    362                                        if( fStr != null ) { buf.append( fStr ); }
    363                                }
    364                        }
    365                }
    366
    367                return this;
    368        }
    369
    370        /**
    371         * 内部のStringBuilderそのものを返します。
    372         *
    373         * StringBuilderを関数等に渡して追加処理する場合に、
    374         * 内部のStringBuilderを渡して、処理させることが出来ます。
    375         *
    376         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    377         *
    378         * @return      内部のStringBuilder
    379         * @og.rtnNotNull
    380         */
    381        public StringBuilder getBuilder() {
    382                return buf;
    383        }
    384
    385        /**
    386         * 内部のStringBuilderをクリアします。
    387         *
    388         * 具体的には、StringBuilder#setLength(0) を実行します。
    389         *
    390         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    391         *
    392         * @return      内部のStringBuilder
    393         */
    394        public OgBuilder clear() {
    395                buf.setLength(0);
    396                return this;
    397        }
    398
    399        // ********************************** 以下は、CharSequence インタフェース の実装 **********************************
    400
    401        /**
    402         * 指定されたインデックスのchar値を返します。
    403         *
    404         * インデックスは、0からlength() - 1の範囲になります。配列のインデックス付けの場合と同じように、
    405         * シーケンスの最初のcharのインデックスは0、次の文字のインデックスは1と続きます。
    406         *
    407         * インデックスで指定されたchar値がサロゲートの場合、サロゲート値が返されます。
    408         *
    409         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
    410         *
    411         * @param index 返されるchar値のインデックス
    412         * @return 指定されたchar値
    413         * @see         java.lang.CharSequence#charAt(int)
    414         */
    415        @Override       // CharSequence
    416        public char charAt( final int index ) {
    417                return buf.charAt( index );
    418        }
    419
    420        /**
    421         * この文字シーケンスの長さを返します。
    422         *
    423         * 長さはシーケンス内の16ビットcharの数に等しくなります。
    424         *
    425         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
    426         *
    427         * @return このシーケンスのcharの数
    428         * @see         java.lang.CharSequence#length()
    429         */
    430        @Override       // CharSequence
    431        public int length() {
    432                return buf.length();
    433        }
    434
    435        /**
    436         * この文字シーケンスの長さを返します。
    437         *
    438         * 長さはシーケンス内の16ビットcharの数に等しくなります。
    439         *
    440         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
    441         *
    442         * @param start 開始インデックス(この値を含む)
    443         * @param end   終了インデックス(この値を含まない)
    444         * @return 指定されたサブシーケンス
    445         * @see         java.lang.CharSequence#subSequence(int,int)
    446         */
    447        @Override       // CharSequence
    448        public CharSequence subSequence( final int start , final int end ) {
    449                return buf.subSequence( start , end );
    450        }
    451
    452        /**
    453         * このシーケンス内のデータを表す文字列を返します。
    454         *
    455         * 新しいStringオブジェクトが割り当てられ、現在このオブジェクトで表されている
    456         * 文字シーケンスを含むように初期化されます。
    457         * その後、このStringが返されます。その後このシーケンスが変更されても、Stringの内容には影響ありません。
    458         *
    459         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
    460         *
    461         * @return この文字シーケンスの文字列表現。
    462         * @see         java.lang.CharSequence#toString()
    463         * @og.rtnNotNull
    464         */
    465        @Override       // CharSequence
    466        public String toString() {
    467                return buf.toString();
    468        }
    469}