001package Torello.Java; 002 003import Torello.Java.Function.*; 004 005import java.util.*; 006import java.util.function.*; 007import java.util.stream.*; 008 009/** 010 * A utility that builds Comma Separated Value String's (and can parse them as well). 011 * 012 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=STR_CSV> 013 */ 014@Torello.JavaDoc.StaticFunctional 015public class StrCSV 016{ 017 private StrCSV() { } 018 019 private static void throwNPE(int i, Object o) 020 { 021 throw new NullPointerException( 022 "The toString Lambda provided to this method returned null for array-index " + 023 "[" + i + "]. At this index, the array contents were [" + o.toString() + "]" 024 ); 025 } 026 027 private static final String IAE_MESSAGE_MAXLENINNER = 028 "The value passed to parameter 'maxLengthInner' was [TOK]. " + 029 "However, BECAUSE this value represents a minimum String length for a subarray, " + 030 "AND BECAUSE an ellipsis, space and brackets are appended, this parameter may not " + 031 "have a positive value less than 7."; 032 033 034 // ******************************************************************************************** 035 // ******************************************************************************************** 036 // From CSV to Array 037 // ******************************************************************************************** 038 // ******************************************************************************************** 039 040 041 /** 042 * Convenience Method. 043 * <BR />Invokes: {@link #CSV(String, boolean, boolean)}. 044 */ 045 public static String[] CSV(String s) { return CSV(s, true, true); } 046 047 /** 048 * This will return a list of {@code String} that are in-between each-and-every comma that is 049 * found inside the parameter-{@code String} {@code 's'} 050 * 051 * <BR /><BR /><B CLASS=JDDescLabel>Java Stream API:</B> 052 * 053 * <BR />This method uses Java 8 or 9's {@code package java.util.stream.*}. If this package is 054 * not familiar, it is usually just a way (after some practice), of (sort-of) converting 055 * for-loops into more readable method-calls. Java-Streams instead substitute words such as: 056 * {@code 'filter', 'map', 'forEach'} and {@code 'toArray'}. This method's code is nothing more 057 * than that. 058 * 059 * @param s This accepts any java-{@code String}, but it is expecting one that contains commas. 060 * 061 * @param performTrim If this parameter is set to {@code TRUE}, then all {@code String's} will 062 * be trimmed of white-space before being placed in the returned {@code String}-array, by 063 * calling Java's {@code String.trim()} method. 064 * 065 * @param eliminateZeroLengthStrings If this parameter is set to {@code TRUE}, then all 066 * {@code String's} that have zero-length will be eliminated from the returned {@code String[]} 067 * array. 068 * 069 * <BR /><BR /><B><SPAN STYLE="color: red;">NOTE:</B></SPAN> Regardless of whether or not a 070 * {@code trim()} operation was performed, all {@code String's} that are trimmed of 071 * white-space, would have the {@code 'trim'} done <B><I>before</B></I> the {@code 'eliminate'} 072 * operation. 073 * 074 * @return This will return the individual {@code String's} from a larger-{@code String} that 075 * contained comma-separated values. 076 */ 077 public static String[] CSV(String s, boolean performTrim, boolean eliminateZeroLengthStrings) 078 { 079 Stream<String> stream = 080 StringParse.COMMA_REGEX.splitAsStream(s).filter((String csv) -> csv != null); 081 082 if (performTrim) 083 stream = stream.map((String csv) -> csv.trim()); 084 085 if (eliminateZeroLengthStrings) 086 stream = stream.filter((String csv) -> csv.length() > 0); 087 088 return stream.toArray(String[]::new); 089 } 090 091 092 // ******************************************************************************************** 093 // ******************************************************************************************** 094 // To CSV, Object Arrays, Iterables 095 // ******************************************************************************************** 096 // ******************************************************************************************** 097 098 099 /** 100 * Convenience Method. 101 * <BR />Invokes: {@link #toCSV(Iterable, boolean, boolean, Integer)} 102 * <BR />Converts: {@code String[] Array} to {@code List<String>}. 103 */ 104 public static String toCSV(String[] sArr, boolean trim, boolean printNulls, Integer maxLength) 105 { return toCSV(Arrays.asList(sArr), trim, printNulls, maxLength); } 106 107 /** 108 * This method will turn the elements of any java {@code Iterable} type into a 109 * {@code java.lang.String}. The returned {@code String} shall have the individual elements 110 * of parameter {@code 'i'} converted to {@code String's}, each separated by a comma. 111 * 112 * @param i Any Java {@code Iterable}. The Java {@code Object.toString()} will be invoked on 113 * each of the elements produced by the {@code Iterable}, and commas shall be inserted between 114 * each element. 115 * 116 * <EMBED CLASS='external-html' DATA-FILE-ID=RAWTYPES> 117 * 118 * @param trim This is a boolean, and when set {@code TRUE}, the {@code String.trim()} shall be 119 * invoked on each {@code String} inserted into the CSV list before insertion. 120 * 121 * @param printNulls This is a boolean, and when set {@code TRUE}, each object returned by the 122 * iterator shall be checked for a 'null' value before insertion into the output-{@code String} 123 * - <I>to avoid null-pointer exceptions</I>. Instead the four-character {@code String} 'null' 124 * will be inserted instead of throwing this exception. 125 * 126 * <BR /><BR />When this parameter receives {@code FALSE}, if the input parameter 127 * {@code Iterable<?> i} contains a null value, then this method will simply throw a 128 * {@code NullPointerException}. 129 * 130 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 131 * 132 * @return This will return a CSV {@code String} containing the individual elements of the 133 * input {@code Iterable} parameter {@code 'i'}, where each element has been converted to a 134 * {@code String} and is separated by a comma. 135 * 136 * @throws NullPointerException If the {@code Iterable} returns a null value, and the 137 * {@code 'printNulls'} parameter were set to {@code FALSE}, then this method would throw 138 * an exception. 139 */ 140 public static String toCSV(Iterable<?> i, boolean trim, boolean printNulls, Integer maxLength) 141 { 142 StringBuilder sb = new StringBuilder(); 143 boolean first = true; 144 145 if (trim && printNulls) 146 147 for (Object o : i) 148 { 149 if (o == null) o = "null"; 150 151 sb.append((first ? "" : ", ") + o.toString().trim()); 152 first = false; 153 } 154 155 else if (trim && (! printNulls)) 156 157 for (Object o : i) 158 { 159 sb.append((first ? "" : ", ") + o.toString().trim()); 160 first = false; 161 } 162 163 else if ((! trim) && printNulls) 164 165 for (Object o : i) 166 { 167 if (o == null) o = "null"; 168 169 sb.append((first ? "" : ", ") + o.toString()); 170 first = false; 171 } 172 173 else // !trim !printNulls 174 175 for (Object o : i) 176 { 177 sb.append((first ? "" : ", ") + o.toString()); 178 first = false; 179 } 180 181 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 182 { 183 sb.setLength(maxLength - 4); 184 sb.append(" ..."); 185 186 return sb.toString(); 187 } 188 189 return sb.toString(); 190 } 191 192 /** 193 * This method will turn the elements of any java {@code Iterable} type into a 194 * {@code java.lang.String}. The returned {@code String} shall have the individual elements 195 * of parameter {@code 'i'} converted to {@code String's}, each separated by a comma. 196 * 197 * @param <T> The type used by the {@code java.lang.Iterable}. The {@code 'toString'} 198 * parameter / function-pointer also must accept this type, or a super-type. 199 * 200 * @param i Any Java {@code Iterable}. The functional-interface parameter {@code 'toString'} 201 * will be invoked on each of the elements produced by the {@code Iterable}, and commas shall 202 * be inserted between each element. 203 * 204 * @param toString This instance of {@code java.util.function.Function<A, B>} must have a 205 * method that accepts a parameter having type {@code 'T'}, and returns a {@code String}. This 206 * is simply an "over-riding" of Java's basic {@code 'toString()'} method. In fact, if the 207 * class that is being used for variable-type parameter {@code 'T'} has a {@code 'toString'} 208 * method that is sufficient or "good enough", then this method should not be used, but 209 * rather the simpler method: {@link #toCSV(Iterable, boolean, boolean, Integer)}. 210 * 211 * @param printNulls When this parameter is {@code TRUE}, the {@code 'toString.apply(T)'} 212 * method shall receive a null value, and the {@code String} results returned by this method 213 * shall be inserted into the output {@code String} when the input {@code Iterable 'i'} 214 * contains a null value. Thusly, the behavior of this method for 'nulls' in the input 215 * {@code 'i'} parameter should be <I>no different than any other value found within the input 216 * {@code Iterable 'i'}.</I> 217 * 218 * <BR /><BR />When this parameter receives {@code FALSE}, any time a null value is encountered 219 * from the input {@code Iterable<T> 'i'}, that value shall be skipped and the output 220 * {@code String} that is returned will have one fewer element in it's CSV list. 221 * 222 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 223 * 224 * @return This will return a CSV {@code String} containing the individual elements of the 225 * input {@code Iterable} parameter {@code 'i'}, where each element has been converted to a 226 * {@code String} - <I>using the provided {@code 'toString'}</I> function - and is separated by 227 * a comma. 228 */ 229 public static <T> String toCSV 230 (Iterable<T> i, Function<? super T, String> toString, boolean printNulls, Integer maxLength) 231 { 232 StringBuilder sb = new StringBuilder(); 233 boolean first = true; 234 235 if (printNulls) 236 237 for (T t : i) 238 { 239 sb.append((first ? "" : ", ") + toString.apply(t)); 240 first = false; 241 } 242 243 else 244 245 for (T t : i) 246 if (t != null) 247 { 248 sb.append((first ? "" : ", ") + toString.apply(t)); 249 first = false; 250 } 251 252 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 253 { 254 sb.setLength(maxLength - 4); 255 sb.append(" ..."); 256 257 return sb.toString(); 258 } 259 260 return sb.toString(); 261 } 262 263 /** 264 * Convenience Method. 265 * <BR />Invokes: {@link #toCSV(Object[], int, int, boolean, boolean, Integer)} 266 */ 267 public static <T> String toCSV 268 (T[] tArr, boolean trim, boolean printNulls, Integer maxLength) 269 { return toCSV(tArr, 0, -1, trim, printNulls, maxLength); } 270 271 /** 272 * This method will turn the elements of any java {@code Iterable} type into a 273 * {@code java.lang.String}. The returned {@code String} shall have the individual elements 274 * of parameter {@code 'i'} converted to {@code String's}, each separated by a comma. 275 * 276 * @param tArr Any array type {@code 'T'}. Java's {@code 'toString'} method will be invoked 277 * on each of these elements, and returned in a {@code String} where each element has been 278 * separated by a comma. 279 * 280 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 281 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 282 * 283 * @param trim This is a boolean, and when set {@code TRUE}, the {@code String.trim()} shall be 284 * invoked on each {@code String} inserted into the CSV list before insertion. 285 * 286 * @param printNulls This is a boolean, and when set {@code TRUE}, each instance of {@code 'T'} 287 * contained by {@code 'tArr'} shall be checked for a 'null' value before insertion into the 288 * output-{@code String} - <I>to avoid null-pointer exceptions</I>. If a null is found, the 289 * four-character {@code String} 'null' will be inserted instead of throwing this exception. 290 * 291 * <BR /><BR />When this parameter receives {@code FALSE}, if a null value is encountered within 292 * the input-parameter array {@code T[] tArr}, then this method will, in fact, throw a 293 * NullPointerException. 294 * 295 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 296 * 297 * @return This will return a CSV {@code String} containing the individual elements of the 298 * input array {@code T[] tArr} parameter, where each element shall have been converted to a 299 * {@code String} and separated by a comma. 300 * 301 * @throws NullPointerException If the {@code Iterable} returns a null value, and the 302 * {@code 'printNulls'} parameter were set to {@code FALSE}, then this method would throw 303 * an exception. 304 * 305 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 306 */ 307 public static <T> String toCSV 308 (T[] tArr, int sPos, int ePos, boolean trim, boolean printNulls, Integer maxLength) 309 { 310 LV l = new LV(tArr, sPos, ePos); 311 StringBuilder sb = new StringBuilder(); 312 boolean first = true; 313 314 if (trim && printNulls) 315 316 for (int i=l.start; i < l.end; i++) 317 { 318 if (tArr[i] == null) 319 sb.append((first ? "" : ", ") + "null"); 320 else 321 sb.append((first ? "" : ", ") + tArr[i].toString().trim()); 322 first = false; 323 } 324 325 else if (trim && (! printNulls)) 326 327 for (int i=l.start; i < l.end; i++) 328 { 329 sb.append((first ? "" : ", ") + tArr[i].toString().trim()); 330 first = false; 331 } 332 333 else if ((! trim) && printNulls) 334 335 for (int i=l.start; i < l.end; i++) 336 { 337 if (tArr[i] == null) 338 sb.append((first ? "" : ", ") + "null"); 339 else 340 sb.append((first ? "" : ", ") + tArr[i].toString()); 341 first = false; 342 } 343 344 else // !trim !printNulls 345 346 for (int i=l.start; i < l.end; i++) 347 { 348 sb.append((first ? "" : ", ") + tArr[i].toString()); 349 first = false; 350 } 351 352 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 353 { 354 sb.setLength(maxLength - 4); 355 sb.append(" ..."); 356 357 return sb.toString(); 358 } 359 360 return sb.toString(); 361 } 362 363 /** 364 * Convenience Method. 365 * <BR />Invokes: {@link #toCSV(Object[], int, int, IntTFunction, boolean, Integer)} 366 */ 367 public static <T> String toCSV 368 (T[] tArr, IntTFunction<? super T, String> toString, boolean printNulls, Integer maxLength) 369 { return toCSV(tArr, 0, -1, toString, printNulls, maxLength); } 370 371 /** 372 * Converts an array of a variable-type parameter {@code T[]} to a CSV {@code String} 373 * 374 * <BR /><BR />This version of {@code 'toCSV'} allows a programmer to define the exact 375 * {@code 'toString()'} that is used on each object-instance in the provided array. There 376 * is a simpler version of this method where the invokation {@code T.toString()} is 377 * used instead. 378 * 379 * @param <T> The type used by the {@code T[]}-Array. The {@code 'toString'} 380 * parameter / function-pointer also must accept this type. 381 * 382 * @param tArr An array of {@code Object's} of a given variable-type {@code 'T'} 383 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 384 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 385 * 386 * @param toString A method that will convert {@code Object's} of type {@code 'T'} to a 387 * {@code String}. This parameter <I><B>may not</I></B> be null, because in such cases it 388 * would be appropriate to use: {@link #toCSV(Object[], int, int, boolean, boolean, Integer)} 389 * 390 * <BR /><BR /><B STYLE="color: red;">NOTE:</B> This functional-interface is used 391 * instead of simply calling {@code Object.toString()} in order to allow a programmer to 392 * provide arbitrarily defined {@code toString()} methods. If the standard {@code toString()} 393 * method for a given {@code Object} is not sufficient, then provide a different one here using 394 * this parameter. 395 * 396 * <BR /><BR />This {@code 'toString'} functional-interface is expected to accept both an 397 * instance of a type {@code 'T'} variable, <B><I>AND</I></B> an integer. The integer that is 398 * accepted is simply the array-index where the {@code 'T'} variable parameter is located 399 * within the array. 400 * 401 * <BR /><BR /><B STYLE="color: red;">NOTE:</B> This function may return a zero-length 402 * {@code String}, and when/if it does, the {@code Object} located at that array-index shall 403 * not be printed to the output-{@code String}. Also, if this function ever returns null, then 404 * a {@code NullPointerException} shall throw immediately. 405 * 406 * @param printNulls When this parameter is {@code TRUE}, if a null is encountered within the 407 * input-parameter array {@code T[] tArr}, then null shall be passed to the Functional 408 * Interface input-parameter method {@code toString.apply(T)}, and the {@code String} result 409 * from that method shall be inserted into the {@code String} that is returned. 410 * 411 * <BR /><BR />When this parameter receives {@code FALSE}, then anytime a null value is found 412 * within the input-parameter array {@code T[] tArr}, it will be skipped completely, and the 413 * output {@code String} will simply contain one fewer output-{@code String}. 414 * 415 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 416 * 417 * @return a CSV version of the input parameter {@code 'tArr'} where each instance of 418 * {@code 'T'} shall have been converted to a {@code String} using the provided 419 * {@code 'toString(...)'} method. 420 * 421 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 422 * @throws NullPointerException if parameter {@code 'toString'} is null, or if any of the 423 * return values produced by {@code 'toString'} are null 424 */ 425 public static <T> String toCSV( 426 T[] tArr, int sPos, int ePos, IntTFunction<? super T, String> toString, 427 boolean printNulls, Integer maxLength 428 ) 429 { 430 LV l = new LV(tArr, sPos, ePos); 431 StringBuilder sb = new StringBuilder(); 432 int i = l.start; 433 String s; 434 435 if (printNulls) 436 { 437 for (; i < l.end; i++) 438 if ((s = toString.apply(i, tArr[i])).length() > 0) 439 { sb.append(s); break; } 440 441 for (i++; i < l.end; i++) 442 if ((s = toString.apply(i, tArr[i])) == null) throwNPE(i, tArr[i]); 443 else sb.append(", " + s); 444 } 445 446 else 447 { 448 for (; i < l.end; i++) 449 if ((tArr[i] != null) && ((s = toString.apply(i, tArr[i])).length() > 0)) 450 { sb.append(s); break; } 451 452 for (i++; i < l.end; i++) 453 if (tArr[i] != null) 454 if ((s = toString.apply(i, tArr[i])) == null) throwNPE(i, tArr[i]); 455 else sb.append(", " + s); 456 } 457 458 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 459 { 460 sb.setLength(maxLength - 4); 461 sb.append(" ..."); 462 463 return sb.toString(); 464 } 465 466 return sb.toString(); 467 } 468 469 /** 470 * <EMBED CLASS=defs DATA-Type="<T>"> 471 * This class prints a two dimensional {@code <T>}-array to a {@code String}. 472 * 473 * @param <T> The type used by the {@code T[][]}-Array. The {@code 'toString'} 474 * parameter / function-pointer also must accept this type. 475 * 476 * @param tArr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 477 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 478 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 479 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 480 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 481 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 482 * @return A printed version of this two-dimensional array. 483 * 484 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 485 * null value. 486 * 487 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 488 */ 489 public static <T> String toCSV( 490 T[][] tArr, IntIntTFunc<? super T, String> toString, IntPredicate keepRow, 491 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 492 ) 493 { 494 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 495 // A value of 0 to 6 must throw an exception. 496 // A negative value is treated the same as 'null' 497 498 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 499 500 throw new IllegalArgumentException 501 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 502 503 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 504 505 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 506 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 507 String s = null; // temp variable 508 int i = 0; // outer-loop loop-counter 509 int numRows = 0; // Count sub-arrays 510 511 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 512 // SPECIFICALLY: No Max Length. 513 514 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 515 516 sbOuter.append('['); 517 518 for (i=0; i < tArr.length; i++) 519 { 520 // The "Keep Row" Predicate is used to check whether a sub-array should even be 521 // included at all. If "Keep Row" exists, and it rejects the outer array index, 522 // then the entire row itself should be skipped. 523 524 if ((keepRow != null) && (! keepRow.test(i))) continue; 525 526 numRows++; 527 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 528 529 int j = 0; 530 531 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 532 // The purpose to this sub-loop is such that there is a "provided user option" where 533 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 534 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 535 // completely. 536 537 if (toString != null) 538 539 while ( (j < tArr[i].length) 540 && ((s = toString.apply(i, j, tArr[i][j])).length() == 0) 541 ) 542 j++; 543 544 else s = "" + tArr[i][j].toString(); 545 546 // If "separateLines" be sure to add a newline. 547 if (separateLines) sbOuter.append('\n'); 548 549 // Add the opening brackets to this new sub-array that was just computed. 550 sbInner.append(" [" + s); 551 j++; 552 553 // Main Printing Loop 554 while (j < tArr[i].length) 555 { 556 if (toString != null) 557 { 558 if ((s = toString.apply(i, j, tArr[i][j++])).length() > 0) 559 sbInner.append(", " + s); 560 } 561 562 else sbInner.append(", " + tArr[i][j++].toString()); 563 564 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 565 } 566 567 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 568 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 569 { 570 int pos = sbInner.length() - 4; 571 char c = sbInner.charAt(pos); 572 573 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 574 575 sbInner.setLength(pos+1); 576 sbInner.append((c == '[') ? "..." : " ..."); 577 } 578 579 sbInner.append(']'); 580 sbOuter.append(sbInner.toString()); 581 sbInner.setLength(0); 582 } 583 584 // This shall only execute if the 585 if (i < tArr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 586 587 sbOuter.append(separateLines ? "\n]" : " ]"); 588 589 return sbOuter.toString(); 590 } 591 592 // ******************************************************************************************** 593 // ******************************************************************************************** 594 // One Dimensional Primitive Arrays 595 // ******************************************************************************************** 596 // ******************************************************************************************** 597 598 599 /** 600 * Convenience Method. 601 * <BR />Invokes: {@link #toCSV(byte[], int, int, IntByteFunction, Integer)} 602 */ 603 public static String toCSV 604 (byte[] arr, IntByteFunction<String> toString, Integer maxLength) 605 { return toCSV(arr, 0, -1, toString, maxLength); } 606 607 /** 608 * <EMBED CLASS=defs DATA-ArrType=byte DATA-Lambda=IntByteFunction DATA-VarName=b> 609 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 610 * 611 * @param arr Any array of {@code byte}. 612 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 613 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 614 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 615 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 616 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 617 * 618 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 619 * @throws NullPointerException If {@code 'toString'} returns a null value. 620 */ 621 public static String toCSV 622 (byte[] arr, int sPos, int ePos, IntByteFunction<String> toString, Integer maxLength) 623 { 624 LV l = new LV(sPos, ePos, arr); 625 StringBuilder sb = new StringBuilder(); 626 int i = l.start; 627 String s; 628 629 if (toString == null) 630 { 631 sb.append(arr[i++]); 632 while (i < l.end) sb.append(", " + arr[i++]); 633 } 634 635 else 636 { 637 for (; i < l.end; i++) 638 if ((s = toString.apply(i, arr[i])).length() > 0) 639 { sb.append(s); break; } 640 641 for (i++; i < l.end; i++) 642 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 643 else sb.append(", " + s); 644 } 645 646 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 647 { 648 sb.setLength(maxLength - 4); 649 sb.append(" ..."); 650 651 return sb.toString(); 652 } 653 654 return sb.toString(); 655 } 656 657 /** 658 * Convenience Method. 659 * <BR />Invokes: {@link #toCSV(short[], int, int, IntShortFunction, Integer)} 660 */ 661 public static String toCSV 662 (short[] arr, IntShortFunction<String> toString, Integer maxLength) 663 { return toCSV(arr, 0, -1, toString, maxLength); } 664 665 /** 666 * <EMBED CLASS=defs DATA-ArrType=short DATA-Lambda=IntShortFunction DATA-VarName=s> 667 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 668 * 669 * @param arr Any array of {@code short}-integers. 670 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 671 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 672 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 673 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 674 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 675 * 676 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 677 * @throws NullPointerException If {@code 'toString'} returns a null value. 678 */ 679 public static String toCSV 680 (short[] arr, int sPos, int ePos, IntShortFunction<String> toString, Integer maxLength) 681 { 682 LV l = new LV(sPos, ePos, arr); 683 StringBuilder sb = new StringBuilder(); 684 int i = l.start; 685 String s; 686 687 if (toString == null) 688 { 689 sb.append(arr[i++]); 690 while (i < l.end) sb.append(", " + arr[i++]); 691 } 692 693 else 694 { 695 for (; i < l.end; i++) 696 if ((s = toString.apply(i, arr[i])).length() > 0) 697 { sb.append(s); break; } 698 699 for (i++; i < l.end; i++) 700 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 701 else sb.append(", " + s); 702 } 703 704 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 705 { 706 sb.setLength(maxLength - 4); 707 sb.append(" ..."); 708 709 return sb.toString(); 710 } 711 712 return sb.toString(); 713 } 714 715 /** 716 * Convenience Method. 717 * <BR />Invokes: {@link #toCSV(int[], int, int, BiIntFunction, Integer)} 718 */ 719 public static String toCSV 720 (int[] arr, BiIntFunction<String> toString, Integer maxLength) 721 { return toCSV(arr, 0, -1, toString, maxLength); } 722 723 /** 724 * <EMBED CLASS=defs DATA-ArrType=int DATA-Lambda=BiIntFunction DATA-VarName=j> 725 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 726 * 727 * @param arr Any array of integers. 728 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 729 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 730 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 731 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 732 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 733 * 734 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 735 * @throws NullPointerException If {@code 'toString'} returns a null value. 736 */ 737 public static String toCSV 738 (int[] arr, int sPos, int ePos, BiIntFunction<String> toString, Integer maxLength) 739 { 740 LV l = new LV(sPos, ePos, arr); 741 StringBuilder sb = new StringBuilder(); 742 int i = l.start; 743 String s; 744 745 if (toString == null) 746 { 747 sb.append(arr[i++]); 748 while (i < l.end) sb.append(", " + arr[i++]); 749 } 750 751 else 752 { 753 for (; i < l.end; i++) 754 if ((s = toString.apply(i, arr[i])).length() > 0) 755 { sb.append(s); break; } 756 757 for (i++; i < l.end; i++) 758 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 759 else sb.append(", " + s); 760 } 761 762 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 763 { 764 sb.setLength(maxLength - 4); 765 sb.append(" ..."); 766 767 return sb.toString(); 768 } 769 770 return sb.toString(); 771 } 772 773 /** 774 * Convenience Method. 775 * <BR />Invokes: {@link #toCSV(long[], int, int, IntLongFunction, Integer)} 776 */ 777 public static String toCSV 778 (long[] arr, IntLongFunction<String> toString, Integer maxLength) 779 { return toCSV(arr, 0, -1, toString, maxLength); } 780 781 /** 782 * <EMBED CLASS=defs DATA-ArrType=long DATA-Lambda=IntLongFunction DATA-VarName=l> 783 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 784 * 785 * @param arr Any array of {@code long}-integers. 786 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 787 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 788 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 789 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 790 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 791 * 792 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 793 * @throws NullPointerException If {@code 'toString'} returns a null value. 794 */ 795 public static String toCSV 796 (long[] arr, int sPos, int ePos, IntLongFunction<String> toString, Integer maxLength) 797 { 798 LV l = new LV(sPos, ePos, arr); 799 StringBuilder sb = new StringBuilder(); 800 int i = l.start; 801 String s; 802 803 if (toString == null) 804 { 805 sb.append(arr[i++]); 806 while (i < l.end) sb.append(", " + arr[i++]); 807 } 808 809 else 810 { 811 for (; i < l.end; i++) 812 if ((s = toString.apply(i, arr[i])).length() > 0) 813 { sb.append(s); break; } 814 815 for (i++; i < l.end; i++) 816 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 817 else sb.append(", " + s); 818 } 819 820 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 821 { 822 sb.setLength(maxLength - 4); 823 sb.append(" ..."); 824 825 return sb.toString(); 826 } 827 828 return sb.toString(); 829 } 830 831 /** 832 * Convenience Method. 833 * <BR />Invokes: {@link #toCSV(float[], int, int, IntFloatFunction, Integer)} 834 */ 835 public static String toCSV 836 (float[] arr, IntFloatFunction<String> toString, Integer maxLength) 837 { return toCSV(arr, 0, -1, toString, maxLength); } 838 839 /** 840 * <EMBED CLASS=defs DATA-ArrType=float DATA-Lambda=IntFloatFunction DATA-VarName=f> 841 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 842 * 843 * @param arr Any array of {@code float}. 844 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 845 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 846 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 847 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 848 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 849 * 850 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 851 * @throws NullPointerException If {@code 'toString'} returns a null value. 852 */ 853 public static String toCSV 854 (float[] arr, int sPos, int ePos, IntFloatFunction<String> toString, Integer maxLength) 855 { 856 LV l = new LV(sPos, ePos, arr); 857 StringBuilder sb = new StringBuilder(); 858 int i = l.start; 859 String s; 860 861 if (toString == null) 862 { 863 sb.append(arr[i++]); 864 while (i < l.end) sb.append(", " + arr[i++]); 865 } 866 867 else 868 { 869 for (; i < l.end; i++) 870 if ((s = toString.apply(i, arr[i])).length() > 0) 871 { sb.append(s); break; } 872 873 for (i++; i < l.end; i++) 874 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 875 else sb.append(", " + s); 876 } 877 878 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 879 { 880 sb.setLength(maxLength - 4); 881 sb.append(" ..."); 882 883 return sb.toString(); 884 } 885 886 return sb.toString(); 887 } 888 889 /** 890 * Convenience Method. 891 * <BR />Invokes: {@link #toCSV(double[], int, int, IntDoubleFunction, Integer)} 892 */ 893 public static String toCSV 894 (double[] arr, IntDoubleFunction<String> toString, Integer maxLength) 895 { return toCSV(arr, 0, -1, toString, maxLength); } 896 897 /** 898 * <EMBED CLASS=defs DATA-ArrType=double DATA-Lambda=IntDoubleFunction DATA-VarName=d> 899 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 900 * 901 * @param arr Any array of {@code double}. 902 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 903 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 904 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=numbers> 905 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 906 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 907 * 908 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 909 * @throws NullPointerException If {@code 'toString'} returns a null value. 910 */ 911 public static String toCSV 912 (double[] arr, int sPos, int ePos, IntDoubleFunction<String> toString, Integer maxLength) 913 { 914 LV l = new LV(sPos, ePos, arr); 915 StringBuilder sb = new StringBuilder(); 916 int i = l.start; 917 String s; 918 919 if (toString == null) 920 { 921 sb.append(arr[i++]); 922 while (i < l.end) sb.append(", " + arr[i++]); 923 } 924 925 else 926 { 927 for (; i < l.end; i++) 928 if ((s = toString.apply(i, arr[i])).length() > 0) 929 { sb.append(s); break; } 930 931 for (i++; i < l.end; i++) 932 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 933 else sb.append(", " + s); 934 } 935 936 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 937 { 938 sb.setLength(maxLength - 4); 939 sb.append(" ..."); 940 941 return sb.toString(); 942 } 943 944 return sb.toString(); 945 } 946 947 /** 948 * Convenience Method. 949 * <BR />Invokes: {@link #toCSV(boolean[], int, int, IntBoolFunction, Integer)} 950 */ 951 public static String toCSV 952 (boolean[] arr, IntBoolFunction<String> toString, Integer maxLength) 953 { return toCSV(arr, 0, -1, toString, maxLength); } 954 955 /** 956 * <EMBED CLASS=defs DATA-ArrType=boolean DATA-Lambda=IntBoolFunction DATA-VarName=b> 957 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 958 * 959 * @param arr Any array of {@code boolean}. 960 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 961 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 962 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=booleans> 963 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 964 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 965 * 966 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 967 * @throws NullPointerException If {@code 'toString'} returns a null value. 968 */ 969 public static String toCSV 970 (boolean[] arr, int sPos, int ePos, IntBoolFunction<String> toString, Integer maxLength) 971 { 972 LV l = new LV(sPos, ePos, arr); 973 StringBuilder sb = new StringBuilder(); 974 int i = l.start; 975 String s; 976 977 if (toString == null) 978 { 979 sb.append(arr[i++]); 980 while (i < l.end) sb.append(", " + arr[i++]); 981 } 982 983 else 984 { 985 for (; i < l.end; i++) 986 if ((s = toString.apply(i, arr[i])).length() > 0) 987 { sb.append(s); break; } 988 989 for (i++; i < l.end; i++) 990 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 991 else sb.append(", " + s); 992 } 993 994 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 995 { 996 sb.setLength(maxLength - 4); 997 sb.append(" ..."); 998 999 return sb.toString(); 1000 } 1001 1002 return sb.toString(); 1003 } 1004 1005 /** 1006 * Convenience Method. 1007 * <BR />Invokes: {@link #toCSV(char[], int, int, IntCharFunction, Integer)} 1008 */ 1009 public static String toCSV 1010 (char[] arr, IntCharFunction<String> toString, Integer maxLength) 1011 { return toCSV(arr, 0, -1, toString, maxLength); } 1012 1013 /** 1014 * <EMBED CLASS=defs DATA-ArrType=char DATA-Lambda=IntCharFunction DATA-VarName=c> 1015 * <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAIN_DESC> 1016 * 1017 * @param arr Any array of {@code boolean}. 1018 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSARRAY> 1019 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSARRAY> 1020 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TO_STRING DATA-word=characters> 1021 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN> 1022 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_RETURN> 1023 * 1024 * @throws ArrayIndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=AIOOB_EX> 1025 * @throws NullPointerException If {@code 'toString'} returns a null value. 1026 */ 1027 public static String toCSV 1028 (char[] arr, int sPos, int ePos, IntCharFunction<String> toString, Integer maxLength) 1029 { 1030 LV l = new LV(sPos, ePos, arr); 1031 StringBuilder sb = new StringBuilder(); 1032 int i = l.start; 1033 String s; 1034 1035 if (toString == null) 1036 { 1037 sb.append(arr[i++]); 1038 while (i < l.end) sb.append(", " + arr[i++]); 1039 } 1040 1041 else 1042 { 1043 for (i=l.start; i < l.end; i++) 1044 if ((s = toString.apply(i, arr[i])).length() > 0) 1045 { sb.append(s); break; } 1046 1047 for (i++; i < l.end; i++) 1048 if ((s = toString.apply(i, arr[i])) == null) throwNPE(i, arr[i]); 1049 else sb.append(", " + s); 1050 } 1051 1052 if ((maxLength != null) && (sb.length() > maxLength.intValue())) 1053 { 1054 sb.setLength(maxLength - 4); 1055 sb.append(" ..."); 1056 1057 return sb.toString(); 1058 } 1059 1060 return sb.toString(); 1061 } 1062 1063 1064 // ******************************************************************************************** 1065 // ******************************************************************************************** 1066 // Two Dimensional Primitive Arrays 1067 // ******************************************************************************************** 1068 // ******************************************************************************************** 1069 1070 1071 /** 1072 * <EMBED CLASS=defs DATA-Type=byte> 1073 * This class prints a two dimensional {@code byte}-array to a {@code String}. 1074 * 1075 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1076 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1077 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1078 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1079 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1080 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1081 * @return A printed version of this two-dimensional array. 1082 * 1083 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1084 * null value. 1085 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1086 */ 1087 public static String toCSV( 1088 byte[][] arr, IntIntByteFunc<String> toString, IntPredicate keepRow, 1089 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1090 ) 1091 { 1092 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1093 // A value of 0 to 6 must throw an exception. 1094 // A negative value is treated the same as 'null' 1095 1096 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1097 1098 throw new IllegalArgumentException 1099 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1100 1101 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1102 1103 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1104 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1105 String s = null; // temp variable 1106 int i = 0; // outer-loop loop-counter 1107 int numRows = 0; // Count sub-arrays 1108 1109 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1110 // SPECIFICALLY: No Max Length. 1111 1112 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1113 1114 sbOuter.append('['); 1115 1116 for (i=0; i < arr.length; i++) 1117 { 1118 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1119 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1120 // then the entire row itself should be skipped. 1121 1122 if ((keepRow != null) && (! keepRow.test(i))) continue; 1123 1124 numRows++; 1125 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1126 1127 int j = 0; 1128 1129 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1130 // The purpose to this sub-loop is such that there is a "provided user option" where 1131 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1132 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1133 // completely. 1134 1135 if (toString != null) 1136 1137 while ( (j < arr[i].length) 1138 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1139 ) 1140 j++; 1141 1142 else s = "" + arr[i][j]; 1143 1144 // If "separateLines" be sure to add a newline. 1145 if (separateLines) sbOuter.append('\n'); 1146 1147 // Add the opening brackets to this new sub-array that was just computed. 1148 sbInner.append(" [" + s); 1149 j++; 1150 1151 // Main Printing Loop 1152 while (j < arr[i].length) 1153 { 1154 if (toString != null) 1155 { 1156 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1157 sbInner.append(", " + s); 1158 } 1159 1160 else sbInner.append(", " + arr[i][j++]); 1161 1162 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1163 } 1164 1165 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1166 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1167 { 1168 int pos = sbInner.length() - 4; 1169 char c = sbInner.charAt(pos); 1170 1171 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1172 1173 sbInner.setLength(pos+1); 1174 sbInner.append((c == '[') ? "..." : " ..."); 1175 } 1176 1177 sbInner.append(']'); 1178 sbOuter.append(sbInner.toString()); 1179 sbInner.setLength(0); 1180 } 1181 1182 // This shall only execute if the 1183 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1184 1185 sbOuter.append(separateLines ? "\n]" : " ]"); 1186 1187 return sbOuter.toString(); 1188 } 1189 1190 /** 1191 * <EMBED CLASS=defs DATA-Type=short> 1192 * This class prints a two dimensional {@code short}-array to a {@code String}. 1193 * 1194 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1195 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1196 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1197 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1198 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1199 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1200 * @return A printed version of this two-dimensional array. 1201 * 1202 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1203 * null value. 1204 * 1205 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1206 */ 1207 public static String toCSV( 1208 short[][] arr, IntIntShortFunc<String> toString, IntPredicate keepRow, 1209 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1210 ) 1211 { 1212 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1213 // A value of 0 to 6 must throw an exception. 1214 // A negative value is treated the same as 'null' 1215 1216 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1217 1218 throw new IllegalArgumentException 1219 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1220 1221 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1222 1223 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1224 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1225 String s = null; // temp variable 1226 int i = 0; // outer-loop loop-counter 1227 int numRows = 0; // Count sub-arrays 1228 1229 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1230 // SPECIFICALLY: No Max Length. 1231 1232 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1233 1234 sbOuter.append('['); 1235 1236 for (i=0; i < arr.length; i++) 1237 { 1238 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1239 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1240 // then the entire row itself should be skipped. 1241 1242 if ((keepRow != null) && (! keepRow.test(i))) continue; 1243 1244 numRows++; 1245 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1246 1247 int j = 0; 1248 1249 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1250 // The purpose to this sub-loop is such that there is a "provided user option" where 1251 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1252 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1253 // completely. 1254 1255 if (toString != null) 1256 1257 while ( (j < arr[i].length) 1258 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1259 ) 1260 j++; 1261 1262 else s = "" + arr[i][j]; 1263 1264 // If "separateLines" be sure to add a newline. 1265 if (separateLines) sbOuter.append('\n'); 1266 1267 // Add the opening brackets to this new sub-array that was just computed. 1268 sbInner.append(" [" + s); 1269 j++; 1270 1271 // Main Printing Loop 1272 while (j < arr[i].length) 1273 { 1274 if (toString != null) 1275 { 1276 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1277 sbInner.append(", " + s); 1278 } 1279 1280 else sbInner.append(", " + arr[i][j++]); 1281 1282 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1283 } 1284 1285 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1286 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1287 { 1288 int pos = sbInner.length() - 4; 1289 char c = sbInner.charAt(pos); 1290 1291 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1292 1293 sbInner.setLength(pos+1); 1294 sbInner.append((c == '[') ? "..." : " ..."); 1295 } 1296 1297 sbInner.append(']'); 1298 sbOuter.append(sbInner.toString()); 1299 sbInner.setLength(0); 1300 } 1301 1302 // This shall only execute if the 1303 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1304 1305 sbOuter.append(separateLines ? "\n]" : " ]"); 1306 1307 return sbOuter.toString(); 1308 } 1309 1310 /** 1311 * <EMBED CLASS=defs DATA-Type=int> 1312 * This class prints a two dimensional {@code int}-array to a {@code String}. 1313 * 1314 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1315 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1316 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1317 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1318 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1319 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1320 * @return A printed version of this two-dimensional array. 1321 * 1322 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1323 * null value. 1324 * 1325 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1326 */ 1327 public static String toCSV( 1328 int[][] arr, TriIntFunc<String> toString, IntPredicate keepRow, 1329 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1330 ) 1331 { 1332 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1333 // A value of 0 to 6 must throw an exception. 1334 // A negative value is treated the same as 'null' 1335 1336 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1337 1338 throw new IllegalArgumentException 1339 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1340 1341 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1342 1343 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1344 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1345 String s = null; // temp variable 1346 int i = 0; // outer-loop loop-counter 1347 int numRows = 0; // Count sub-arrays 1348 1349 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1350 // SPECIFICALLY: No Max Length. 1351 1352 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1353 1354 sbOuter.append('['); 1355 1356 for (i=0; i < arr.length; i++) 1357 { 1358 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1359 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1360 // then the entire row itself should be skipped. 1361 1362 if ((keepRow != null) && (! keepRow.test(i))) continue; 1363 1364 numRows++; 1365 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1366 1367 int j = 0; 1368 1369 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1370 // The purpose to this sub-loop is such that there is a "provided user option" where 1371 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1372 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1373 // completely. 1374 1375 if (toString != null) 1376 1377 while ( (j < arr[i].length) 1378 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1379 ) 1380 j++; 1381 1382 else s = "" + arr[i][j]; 1383 1384 // If "separateLines" be sure to add a newline. 1385 if (separateLines) sbOuter.append('\n'); 1386 1387 // Add the opening brackets to this new sub-array that was just computed. 1388 sbInner.append(" [" + s); 1389 j++; 1390 1391 // Main Printing Loop 1392 while (j < arr[i].length) 1393 { 1394 if (toString != null) 1395 { 1396 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1397 sbInner.append(", " + s); 1398 } 1399 1400 else sbInner.append(", " + arr[i][j++]); 1401 1402 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1403 } 1404 1405 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1406 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1407 { 1408 int pos = sbInner.length() - 4; 1409 char c = sbInner.charAt(pos); 1410 1411 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1412 1413 sbInner.setLength(pos+1); 1414 sbInner.append((c == '[') ? "..." : " ..."); 1415 } 1416 1417 sbInner.append(']'); 1418 sbOuter.append(sbInner.toString()); 1419 sbInner.setLength(0); 1420 } 1421 1422 // This shall only execute if the 1423 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1424 1425 sbOuter.append(separateLines ? "\n]" : " ]"); 1426 1427 return sbOuter.toString(); 1428 } 1429 1430 /** 1431 * <EMBED CLASS=defs DATA-Type=long> 1432 * This class prints a two dimensional {@code long}-array to a {@code String}. 1433 * 1434 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1435 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1436 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1437 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1438 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1439 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1440 * @return A printed version of this two-dimensional array. 1441 * 1442 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1443 * null value. 1444 * 1445 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1446 */ 1447 public static String toCSV( 1448 long[][] arr, IntIntLongFunc<String> toString, IntPredicate keepRow, 1449 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1450 ) 1451 { 1452 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1453 // A value of 0 to 6 must throw an exception. 1454 // A negative value is treated the same as 'null' 1455 1456 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1457 1458 throw new IllegalArgumentException 1459 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1460 1461 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1462 1463 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1464 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1465 String s = null; // temp variable 1466 int i = 0; // outer-loop loop-counter 1467 int numRows = 0; // Count sub-arrays 1468 1469 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1470 // SPECIFICALLY: No Max Length. 1471 1472 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1473 1474 sbOuter.append('['); 1475 1476 for (i=0; i < arr.length; i++) 1477 { 1478 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1479 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1480 // then the entire row itself should be skipped. 1481 1482 if ((keepRow != null) && (! keepRow.test(i))) continue; 1483 1484 numRows++; 1485 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1486 1487 int j = 0; 1488 1489 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1490 // The purpose to this sub-loop is such that there is a "provided user option" where 1491 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1492 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1493 // completely. 1494 1495 if (toString != null) 1496 1497 while ( (j < arr[i].length) 1498 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1499 ) 1500 j++; 1501 1502 else s = "" + arr[i][j]; 1503 1504 // If "separateLines" be sure to add a newline. 1505 if (separateLines) sbOuter.append('\n'); 1506 1507 // Add the opening brackets to this new sub-array that was just computed. 1508 sbInner.append(" [" + s); 1509 j++; 1510 1511 // Main Printing Loop 1512 while (j < arr[i].length) 1513 { 1514 if (toString != null) 1515 { 1516 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1517 sbInner.append(", " + s); 1518 } 1519 1520 else sbInner.append(", " + arr[i][j++]); 1521 1522 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1523 } 1524 1525 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1526 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1527 { 1528 int pos = sbInner.length() - 4; 1529 char c = sbInner.charAt(pos); 1530 1531 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1532 1533 sbInner.setLength(pos+1); 1534 sbInner.append((c == '[') ? "..." : " ..."); 1535 } 1536 1537 sbInner.append(']'); 1538 sbOuter.append(sbInner.toString()); 1539 sbInner.setLength(0); 1540 } 1541 1542 // This shall only execute if the 1543 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1544 1545 sbOuter.append(separateLines ? "\n]" : " ]"); 1546 1547 return sbOuter.toString(); 1548 } 1549 1550 /** 1551 * <EMBED CLASS=defs DATA-Type=float> 1552 * This class prints a two dimensional {@code float}-array to a {@code String}. 1553 * 1554 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1555 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1556 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1557 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1558 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1559 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1560 * @return A printed version of this two-dimensional array. 1561 * 1562 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1563 * null value. 1564 * 1565 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1566 */ 1567 public static String toCSV( 1568 float[][] arr, IntIntFloatFunc<String> toString, IntPredicate keepRow, 1569 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1570 ) 1571 { 1572 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1573 // A value of 0 to 6 must throw an exception. 1574 // A negative value is treated the same as 'null' 1575 1576 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1577 1578 throw new IllegalArgumentException 1579 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1580 1581 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1582 1583 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1584 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1585 String s = null; // temp variable 1586 int i = 0; // outer-loop loop-counter 1587 int numRows = 0; // Count sub-arrays 1588 1589 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1590 // SPECIFICALLY: No Max Length. 1591 1592 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1593 1594 sbOuter.append('['); 1595 1596 for (i=0; i < arr.length; i++) 1597 { 1598 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1599 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1600 // then the entire row itself should be skipped. 1601 1602 if ((keepRow != null) && (! keepRow.test(i))) continue; 1603 1604 numRows++; 1605 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1606 1607 int j = 0; 1608 1609 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1610 // The purpose to this sub-loop is such that there is a "provided user option" where 1611 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1612 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1613 // completely. 1614 1615 if (toString != null) 1616 1617 while ( (j < arr[i].length) 1618 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1619 ) 1620 j++; 1621 1622 else s = "" + arr[i][j]; 1623 1624 // If "separateLines" be sure to add a newline. 1625 if (separateLines) sbOuter.append('\n'); 1626 1627 // Add the opening brackets to this new sub-array that was just computed. 1628 sbInner.append(" [" + s); 1629 j++; 1630 1631 // Main Printing Loop 1632 while (j < arr[i].length) 1633 { 1634 if (toString != null) 1635 { 1636 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1637 sbInner.append(", " + s); 1638 } 1639 1640 else sbInner.append(", " + arr[i][j++]); 1641 1642 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1643 } 1644 1645 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1646 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1647 { 1648 int pos = sbInner.length() - 4; 1649 char c = sbInner.charAt(pos); 1650 1651 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1652 1653 sbInner.setLength(pos+1); 1654 sbInner.append((c == '[') ? "..." : " ..."); 1655 } 1656 1657 sbInner.append(']'); 1658 sbOuter.append(sbInner.toString()); 1659 sbInner.setLength(0); 1660 } 1661 1662 // This shall only execute if the 1663 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1664 1665 sbOuter.append(separateLines ? "\n]" : " ]"); 1666 1667 return sbOuter.toString(); 1668 } 1669 1670 /** 1671 * <EMBED CLASS=defs DATA-Type=double> 1672 * This class prints a two dimensional {@code double}-array to a {@code String}. 1673 * 1674 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1675 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1676 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1677 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1678 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1679 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1680 * @return A printed version of this two-dimensional array. 1681 * 1682 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1683 * null value. 1684 * 1685 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1686 */ 1687 public static String toCSV( 1688 double[][] arr, IntIntDoubleFunc<String> toString, IntPredicate keepRow, 1689 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1690 ) 1691 { 1692 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1693 // A value of 0 to 6 must throw an exception. 1694 // A negative value is treated the same as 'null' 1695 1696 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1697 1698 throw new IllegalArgumentException 1699 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1700 1701 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1702 1703 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1704 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1705 String s = null; // temp variable 1706 int i = 0; // outer-loop loop-counter 1707 int numRows = 0; // Count sub-arrays 1708 1709 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1710 // SPECIFICALLY: No Max Length. 1711 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1712 1713 sbOuter.append('['); 1714 1715 for (i=0; i < arr.length; i++) 1716 { 1717 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1718 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1719 // then the entire row itself should be skipped. 1720 1721 if ((keepRow != null) && (! keepRow.test(i))) continue; 1722 1723 numRows++; 1724 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1725 1726 int j = 0; 1727 1728 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1729 // The purpose to this sub-loop is such that there is a "provided user option" where 1730 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1731 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1732 // completely. 1733 1734 if (toString != null) 1735 1736 while ( (j < arr[i].length) 1737 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1738 ) 1739 j++; 1740 1741 else s = "" + arr[i][j]; 1742 1743 // If "separateLines" be sure to add a newline. 1744 if (separateLines) sbOuter.append('\n'); 1745 1746 // Add the opening brackets to this new sub-array that was just computed. 1747 sbInner.append(" [" + s); 1748 j++; 1749 1750 // Main Printing Loop 1751 while (j < arr[i].length) 1752 { 1753 if (toString != null) 1754 { 1755 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1756 sbInner.append(", " + s); 1757 } 1758 1759 else sbInner.append(", " + arr[i][j++]); 1760 1761 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1762 } 1763 1764 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1765 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1766 { 1767 int pos = sbInner.length() - 4; 1768 char c = sbInner.charAt(pos); 1769 1770 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1771 1772 sbInner.setLength(pos+1); 1773 sbInner.append((c == '[') ? "..." : " ..."); 1774 } 1775 1776 sbInner.append(']'); 1777 sbOuter.append(sbInner.toString()); 1778 sbInner.setLength(0); 1779 } 1780 1781 // This shall only execute if the 1782 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1783 1784 sbOuter.append(separateLines ? "\n]" : " ]"); 1785 1786 return sbOuter.toString(); 1787 } 1788 1789 /** 1790 * <EMBED CLASS=defs DATA-Type=char> 1791 * This class prints a two dimensional {@code char}-array to a {@code String}. 1792 * 1793 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1794 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1795 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1796 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1797 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1798 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1799 * @return A printed version of this two-dimensional array. 1800 * 1801 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1802 * null value. 1803 * 1804 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1805 */ 1806 public static String toCSV( 1807 char[][] arr, IntIntCharFunc<String> toString, IntPredicate keepRow, 1808 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1809 ) 1810 { 1811 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1812 // A value of 0 to 6 must throw an exception. 1813 // A negative value is treated the same as 'null' 1814 1815 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1816 1817 throw new IllegalArgumentException 1818 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1819 1820 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1821 1822 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1823 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1824 String s = null; // temp variable 1825 int i = 0; // outer-loop loop-counter 1826 int numRows = 0; // Count sub-arrays 1827 1828 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1829 // SPECIFICALLY: No Max Length. 1830 1831 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1832 1833 sbOuter.append('['); 1834 1835 for (i=0; i < arr.length; i++) 1836 { 1837 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1838 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1839 // then the entire row itself should be skipped. 1840 1841 if ((keepRow != null) && (! keepRow.test(i))) continue; 1842 1843 numRows++; 1844 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1845 1846 int j = 0; 1847 1848 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1849 // The purpose to this sub-loop is such that there is a "provided user option" where 1850 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1851 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1852 // completely. 1853 1854 if (toString != null) 1855 1856 while ( (j < arr[i].length) 1857 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1858 ) 1859 j++; 1860 1861 else s = "" + arr[i][j]; 1862 1863 // If "separateLines" be sure to add a newline. 1864 if (separateLines) sbOuter.append('\n'); 1865 1866 // Add the opening brackets to this new sub-array that was just computed. 1867 sbInner.append(" [" + s); 1868 j++; 1869 1870 // Main Printing Loop 1871 while (j < arr[i].length) 1872 { 1873 if (toString != null) 1874 { 1875 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1876 sbInner.append(", " + s); 1877 } 1878 1879 else sbInner.append(", " + arr[i][j++]); 1880 1881 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 1882 } 1883 1884 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 1885 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 1886 { 1887 int pos = sbInner.length() - 4; 1888 char c = sbInner.charAt(pos); 1889 1890 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 1891 1892 sbInner.setLength(pos+1); 1893 sbInner.append((c == '[') ? "..." : " ..."); 1894 } 1895 1896 sbInner.append(']'); 1897 sbOuter.append(sbInner.toString()); 1898 sbInner.setLength(0); 1899 } 1900 1901 // This shall only execute if the 1902 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 1903 1904 sbOuter.append(separateLines ? "\n]" : " ]"); 1905 1906 return sbOuter.toString(); 1907 } 1908 1909 /** 1910 * <EMBED CLASS=defs DATA-Type=boolean> 1911 * This class prints a two dimensional {@code boolean}-array to a {@code String}. 1912 * 1913 * @param arr <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_ARR_2D> 1914 * @param toString <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_TSTR_2DARR> 1915 * @param keepRow <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SUB_PRED> 1916 * @param separateLines <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_SEPL_LINE> 1917 * @param maxLengthInner <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAX_LEN_IN> 1918 * @param maxLengthOuter <EMBED CLASS='external-html' DATA-FILE-ID=SCSV_MAXLEN_OUT> 1919 * @return A printed version of this two-dimensional array. 1920 * 1921 * @throws NullPointerException If the {@code 'toString'} method is non-null, but returns a 1922 * null value. 1923 * 1924 * @throws IllegalArgumentException If {@code 'maxLengthInner'} is less than {@code '7'}. 1925 */ 1926 public static String toCSV( 1927 boolean[][] arr, IntIntBoolFunc<String> toString, IntPredicate keepRow, 1928 boolean separateLines, Integer maxLengthInner, Integer maxLengthOuter 1929 ) 1930 { 1931 // maxLengthInner *MUST* be >= 7, since minimum-string-length is " [...]" 1932 // A value of 0 to 6 must throw an exception. 1933 // A negative value is treated the same as 'null' 1934 1935 if ((maxLengthInner != null) && (maxLengthInner < 7) && (maxLengthInner >= 0)) 1936 1937 throw new IllegalArgumentException 1938 (IAE_MESSAGE_MAXLENINNER.replace("TOK", maxLengthInner.toString())); 1939 1940 else if ((maxLengthInner != null) && (maxLengthInner < 0)) maxLengthInner = null; 1941 1942 StringBuilder sbOuter = new StringBuilder(); // Primary StringBuilder 1943 StringBuilder sbInner = new StringBuilder(); // StrinBuilder for the sub/inner arrays 1944 String s = null; // temp variable 1945 int i = 0; // outer-loop loop-counter 1946 int numRows = 0; // Count sub-arrays 1947 1948 // If the value passed to 'maxLengthOuter' is negative, treat it the same as 'null' 1949 // SPECIFICALLY: No Max Length. 1950 1951 if ((maxLengthOuter != null) && (maxLengthOuter < 0)) maxLengthOuter = null; 1952 1953 sbOuter.append('['); 1954 1955 for (i=0; i < arr.length; i++) 1956 { 1957 // The "Keep Row" Predicate is used to check whether a sub-array should even be 1958 // included at all. If "Keep Row" exists, and it rejects the outer array index, 1959 // then the entire row itself should be skipped. 1960 1961 if ((keepRow != null) && (! keepRow.test(i))) continue; 1962 1963 numRows++; 1964 if ((maxLengthOuter != null) && (numRows > maxLengthOuter)) break; 1965 1966 int j = 0; 1967 1968 // System.out.println("end: " + end + ",\ti: " + i + ",\tj: " + j); 1969 // The purpose to this sub-loop is such that there is a "provided user option" where 1970 // the 'toString-lambda' may return a ZERO-LENGTH-STRING, and when this happens, the 1971 // array-location that resulted in a ZERO-LENGTH-STRING shall be ignored/skipped 1972 // completely. 1973 1974 if (toString != null) 1975 1976 while ( (j < arr[i].length) 1977 && ((s = toString.apply(i, j, arr[i][j])).length() == 0) 1978 ) 1979 j++; 1980 1981 else s = "" + arr[i][j]; 1982 1983 // If "separateLines" be sure to add a newline. 1984 if (separateLines) sbOuter.append('\n'); 1985 1986 // Add the opening brackets to this new sub-array that was just computed. 1987 sbInner.append(" [" + s); 1988 j++; 1989 1990 // Main Printing Loop 1991 while (j < arr[i].length) 1992 { 1993 if (toString != null) 1994 { 1995 if ((s = toString.apply(i, j, arr[i][j++])).length() > 0) 1996 sbInner.append(", " + s); 1997 } 1998 1999 else sbInner.append(", " + arr[i][j++]); 2000 2001 if ((maxLengthInner != null) && (sbInner.length() > maxLengthInner)) break; 2002 } 2003 2004 // NOTE: The '+ 1' is needed because, as of yet, the trailing ']' has not been added. 2005 if ((maxLengthInner != null) && ((sbInner.length() + 1) > maxLengthInner)) 2006 { 2007 int pos = sbInner.length() - 4; 2008 char c = sbInner.charAt(pos); 2009 2010 while ((c != ',') && (c != '[')) c = sbInner.charAt(--pos); 2011 2012 sbInner.setLength(pos+1); 2013 sbInner.append((c == '[') ? "..." : " ..."); 2014 } 2015 2016 sbInner.append(']'); 2017 sbOuter.append(sbInner.toString()); 2018 sbInner.setLength(0); 2019 } 2020 2021 // This shall only execute if the 2022 if (i < arr.length) sbOuter.append((separateLines ? "\n" : "") + " ..."); 2023 2024 sbOuter.append(separateLines ? "\n]" : " ]"); 2025 2026 return sbOuter.toString(); 2027 } 2028}