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