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