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