001/*
002 * Copyright (c) 2017 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.fileexec;
017
018import java.util.Locale;
019import java.util.Date;
020import java.text.DateFormat;
021import java.text.SimpleDateFormat;
022
023/**
024 * StringUtilは、共通的に使用される文字列処理に関する、ユーティリティークラスです。
025 *
026 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
027 *
028 * @version  7.0
029 * @author   Kazuhiko Hasegawa
030 * @since    JDK1.8,
031 */
032public final class StringUtil {
033
034        /**
035         * デフォルトコンストラクターをprivateにして、
036         * オブジェクトの生成をさせないようにする。
037         */
038        private StringUtil() {}
039
040        /**
041         * 指定の文字列が nullか、ゼロ文字列 の場合は、2番目以降の引数から、null でない最初の値を返します。
042         * 2番目以降の引数には、ゼロ文字列の指定も可能です。
043         *
044         * @param       val 判定する文字列
045         * @param       def 初期値の可変長引数
046         * @return      指定の値で、最初にnullでない値。最後まで、無ければ、val を返します。
047         */
048        public static String nval( final String val , final String... def ) {
049                if( val == null || val.trim().isEmpty() ) {
050                        for( final String str : def ) {
051                                if( str != null ) { return str.trim(); }                        // ゼロ文字列 の場合も、返します。
052                        }
053                }
054
055                return val;             // 最後まで null以外の値が見つからない場合なので、val が null の場合もありうる。
056        }
057
058        /**
059         * 指定の数値型文字列が nullか、ゼロ文字列 の場合は、2番目の初期値を返します。
060         *
061         * そうでない場合は、指定の文字列を、Integer.parseInt( String ) した値を返します。
062         *
063         * @param       val 判定する数値型文字列
064         * @param       def 初期値の数値
065         * @return      指定の文字列が nullか、ゼロ文字列でない場合は、数値に変換し、そうでなければ、初期値の数値を返します。
066         * @throws      NumberFormatException   文字列が解析可能な整数型を含まない場合。
067         */
068        public static int nval( final String val , final int def ) {
069                return val == null || val.trim().isEmpty() ? def : Integer.parseInt( val.trim() );
070        }
071
072        /**
073         * LOGファイルのフォーマットに対応した日付、時刻文字列を作成します。
074         *
075         * yyyyMMddHHmmss 形式のフォーマットで、返します。
076         *
077         * @return      現在の日付、時刻文字列
078         */
079        public static String getTimeFormat() {
080                return getTimeFormat( "yyyyMMddHHmmss" );
081        }
082
083        /**
084         * 指定のフォーマットに対応した日付、時刻文字列を作成します。
085         *
086         * 例えば、LOGフォーマットの場合は、yyyyMMdd HH:mm:ss 形式です。
087         *
088         * @param format        日付、時刻文字列のフォーマット
089         * @return      指定のフォーマットに対応した現在の日付、時刻文字列
090         */
091        public static String getTimeFormat( final String format ) {
092                final DateFormat formatter = new SimpleDateFormat( format , Locale.getDefault() );
093                return formatter.format( new Date() );
094        }
095
096        /**
097         * 指定のフォーマットに対応した日付、時刻文字列を作成します。
098         *
099         * 例えば、LOGフォーマットの場合は、yyyyMMdd HH:mm:ss 形式です。
100         *
101         * @param date          フォーマットする日付情報
102         * @param format        日付、時刻文字列のフォーマット
103         * @return      指定のフォーマットに対応した指定の日付、時刻文字列
104         */
105        public static String getTimeFormat( final long date , final String format ) {
106                final DateFormat formatter = new SimpleDateFormat( format , Locale.getDefault() );
107                return formatter.format( new Date( date ) );
108        }
109
110        /**
111         * EUROMAPの日付、時間文字列から、openGion系日付時刻文字列を作成します。
112         *
113         * 日付は、yyyyMMdd 形式で、時間は、HH:mm:ss 形式を標準としますが、
114         * 数字以外の文字列を削除して、連結した文字列を作成します。
115         * その場合、14桁数字文字列 になります。
116         *
117         * その形式に合わない場合は、現在時刻 を返します。
118         * ただし、日付の整合性チェックは、行っていません。
119         *
120         * @param       ymd EUROMAPの日付(yyyyMMdd形式の8桁数字)
121         * @param       hms EUROMAPの時間(HH:mm:ss形式の8桁数字)
122         * @return      openGion系日付時刻文字列(yyyyMMddHHmmss形式の14桁数字)
123         */
124        public static String getTime( final String ymd , final String hms ) {
125                if( ymd != null && hms != null ) {
126                        if( ymd.length() == 8 && hms.length() == 8 ) {
127                                return ymd + hms.substring(0,2) + hms.substring(3,5) + hms.substring(6);
128                        }
129                        else {
130                                final StringBuilder buf = new StringBuilder();
131                                for( int i=0; i<ymd.length(); i++ ) {
132                                        final char ch = ymd.charAt( i );
133                                        if( '0' <= ch && ch < '9' ) { buf.append( ch ); }       // 数字のみ許可
134                                }
135
136                                for( int i=0; i<hms.length(); i++ ) {
137                                        final char ch = hms.charAt( i );
138                                        if( '0' <= ch && ch < '9' ) { buf.append( ch ); }       // 数字のみ許可
139                                }
140
141                                if( buf.length() == 14 ) {
142                                        return buf.toString();
143                                }
144                        }
145                }
146
147                // 引数が存在しない場合は、無条件に1秒待ちます。
148                // これは、テスト用に日付無しのDATデータを用意して登録する場合に使用します。
149                try{ Thread.sleep( 1000 ); } catch( final InterruptedException ex ){}
150
151                return getTimeFormat() ;                // 現在時刻
152        }
153
154        /**
155         * すべての引数をスペースで連結してtrim()した文字列を返します。
156         *
157         * 各引数は、それぞれ、trim()した後、スペースで連結します。
158         * ただし、引数が、nullの場合は、ゼロ文字列に変換します。
159         * すべてを連結して、trim() した結果が、ゼロ文字列の場合は、defVal を返します。
160         *
161         * @param       defVal 結果が、ゼロ文字列の場合に返す文字列
162         * @param       keys 連結したいキーの可変長文字列配列
163         * @return      合成した文字列。
164         */
165        public static String keyAppend( final String defVal , final String... keys ) {
166                final StringBuilder buf = new StringBuilder();
167                for( final String key : keys ) {
168                        buf.append( nval( key , "" ).trim() ).append( ' ' );
169                }
170
171                return nval( buf.toString().trim() , defVal );
172        }
173
174        /**
175         * 指定の文字列を、引数の文字で、前後に分割します。
176         * キー=値 や、キー,値 などの文字列を分割して、キーと値の配列を返します。
177         * 1番目の配列[0] は、キー(chの左側)、2番目の配列[1] は、値(chの右側) です。
178         * キーも値も、前後のスペースを削除:trim() します。
179         * キー(1番目の配列[0])は、空文字列を許可しません。
180         *
181         * 分割文字を含まない場合や、キーが、空文字列の場合は、null を返します。
182         * nullで無い場合は、配列は、必ず2個存在しそのどちらの値も、null を含みません。
183         *
184         * @param       line    1行分の文字列
185         * @param       ch      分割する文字
186         * @return      キーと値の配列。無ければ、null
187         */
188        public static String[] split( final String line , final char ch ) {
189                final int ad = line.indexOf( ch );
190                if( ad > 0 ) {          // ch が先頭は無視
191                        final String key = line.substring( 0,ad ).trim();
192
193                        if( !key.isEmpty() ) {
194                                final String val = line.substring( ad+1 ).trim();
195                                return new String[] { key , val };
196                        }
197                }
198                return null;
199        }
200
201        /**
202         * 数字型文字列の一致をチェックします。
203         *
204         * 処理としては、数字型文字列以外を判定条件に入れても、同一文字列の場合は、
205         * true になります。
206         * ここでは、どちらかの文字列の末尾が、".0" などの場合に、同じかどうかを
207         * 数値に変換して、判定します。
208         * どちらかが、null の場合は、必ず false になります。両方とも、null でも false です。
209         *
210         * @param       val1 判定用の引数1
211         * @param       val2 判定用の引数2
212         * @return      判定結果(一致する場合は、true)
213         */
214        public static boolean numEquals( final String val1 , final String val2 ) {
215                if( val1 == null || val2 == null ) { return false; }
216
217                if( val1.equals( val2 ) ) {
218                        return true;
219                }
220                else {
221                        try {
222                                return Double.parseDouble( val1 ) == Double.parseDouble( val2 );
223                        }
224                        catch( final NumberFormatException ex ) {
225                                // 数値変換できなかった場合は、無視します。
226                        }
227                }
228
229                return false;
230        }
231}