001package Torello.Java; 002 003import Torello.JavaDoc.Annotations.LinkJavaSource; 004 005import Torello.Java.ReadOnly.ReadOnlyArrayList; 006import Torello.Java.ReadOnly.ReadOnlyList; 007 008import Torello.Java.Function.IntTFunction; 009import static Torello.Java.C.RESET; 010 011import java.util.Calendar; 012import java.util.Locale; 013import java.util.Arrays; 014 015import java.text.DecimalFormat; 016 017/** 018 * This class provides several {@code String} printing utilities such as abbreviation and list 019 * printing. 020 */ 021@Torello.JavaDoc.Annotations.StaticFunctional 022public class StrPrint 023{ 024 private StrPrint() { } 025 026 /** A Java-String containing four consecutive space chars ({@code ' '} ASCII #32 / #20h) */ 027 public static final String I4 = StringParse.nChars(' ', 4); 028 029 /** A Java-String containing eight consecutive space chars ({@code ' '} ASCII #32 / #20h) */ 030 public static final String I8 = StringParse.nChars(' ', 8); 031 032 /** A Java-String containing twelve consecutive space chars ({@code ' '} ASCII #32 / #20h) */ 033 public static final String I12 = StringParse.nChars(' ', 12); 034 035 /** A Java-String containing sixteen consecutive space chars ({@code ' '} ASCII #32 / #20h) */ 036 public static final String I16 = StringParse.nChars(' ', 16); 037 038 /** A Java-String containing twenty consecutive space chars ({@code ' '} ASCII #32 / #20h) */ 039 public static final String I20 = StringParse.nChars(' ', 20); 040 041 042 // ******************************************************************************************** 043 // ******************************************************************************************** 044 // HELPER & BASIC 045 // ******************************************************************************************** 046 // ******************************************************************************************** 047 048 049 /** 050 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_NLAT_DESC> 051 * 052 * @param s Any {@code java.lang.String}, preferably one with multiple lines of text. 053 * 054 * @return A {@code String}, where each line of text has been "trimmed", and the two 055 * character sequence {@code "\\n"} inserted in-between each line. 056 * 057 * @see #abbrevStartRDSF(String, int, boolean) 058 * @see #abbrevEndRDSF(String, int, boolean) 059 */ 060 public static String newLinesAsText(String s) 061 { 062 return s 063 .replaceAll( 064 // White-Space-Except-Newline, THEN newline, THEN White-SpaceExcept-Newline 065 "[ \t\r\f\b]*\n[ \t\r\f\b]*", 066 067 // Replace Each Occurence of that with: 068 // == COMPILES-TO ==> "\\n" == REG-EX-READS ==> BackSlash and letter 'n' 069 "\\\\n" 070 ) 071 // == COMPILES-TO ==> "\s+" == REG-EX-READS ==> 'spaces' 072 .replaceAll("\\s+", " ") 073 074 // Don't forget about leading and trailing stuff... 075 .trim(); 076 } 077 078 079 // ******************************************************************************************** 080 // ******************************************************************************************** 081 // Abbreviating Text, with "newLinesAsText" - Helper 082 // ******************************************************************************************** 083 // ******************************************************************************************** 084 085 086 /** 087 * Convenience Method. 088 * <BR /><B STYLE='color: red;'>RDSF: Remove Duplicate Spaces First</B> 089 * <BR />Invokes: {@link StringParse#removeDuplicateSpaces(String)} 090 * <BR />Or Invokes: {@link #newLinesAsText(String)} 091 * <BR />Finally: {@link #abbrevStart(String, boolean, int)} 092 */ 093 public static String abbrevStartRDSF 094 (String s, int maxLength, boolean seeEscapedNewLinesAsText) 095 { 096 // false is passed to 'abbrevStart' parameter 'escapeNewLines' because in both scenarios 097 // of this conditional-statement, the new-lines have already been removed by the previous 098 // method call. 099 // 100 // both 'removeDuplicateSpaces' and 'newLinesAsText' remove the new-lines 101 102 return seeEscapedNewLinesAsText 103 ? abbrevStart(newLinesAsText(s), false, maxLength) 104 : abbrevStart(StringParse.removeDuplicateSpaces(s), false, maxLength); 105 } 106 107 /** 108 * Convenience Method. 109 * <BR /><B STYLE='color: red;'>RDSF: Remove Duplicate Spaces First</B> 110 * <BR />Invokes: {@link StringParse#removeDuplicateSpaces(String)} 111 * <BR />Or Invokes: {@link #newLinesAsText(String)} 112 * <BR />Finally: {@link #abbrevEnd(String, boolean, int)} 113 */ 114 public static String abbrevEndRDSF 115 (String s, int maxLength, boolean seeEscapedNewLinesAsText) 116 { 117 // false is passed to 'abbrevStart' parameter 'escapeNewLines' because in both scenarios 118 // of this conditional-statement, the new-lines have already been removed by the previous 119 // method call. 120 // 121 // both 'removeDuplicateSpaces' and 'newLinesAsText' remove the new-lines 122 123 return seeEscapedNewLinesAsText 124 ? abbrevEnd(newLinesAsText(s), false, maxLength) 125 : abbrevEnd(StringParse.removeDuplicateSpaces(s), false, maxLength); 126 } 127 128 /** 129 * Convenience Method. 130 * <BR />Passes: {@code '0'} to parameter {@code 'abbrevPos'}, forcing the abbreviation to 131 * occur at the <B>start</B> of the {@code String} (if long enough to be abbreviated) 132 * <BR />See Documentation: {@link #abbrev(String, int, boolean, String, int)} 133 */ 134 @LinkJavaSource(handle="Abbrev", name="print1") 135 public static String abbrevStart(String s, boolean escNewLines, int maxLength) 136 { return Abbrev.print1(s, 0, escNewLines, null, maxLength); } 137 138 /** 139 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_1_DESC> 140 * @param s This may be any Java (non-null) {@code String} 141 * 142 * @param abbrevPos This parameter is used to indicate where the abbreviation-{@code String} 143 * should occur - <I>if this {@code String 's'} is long enough to be abbreviated.</I> For 144 * instance, if {@code '0'} (zero) were passed to this parameter, and {@code 's'} were longer 145 * than parameter {@code 'maxLength'}, then an ellipsis would be appended to the beginning of 146 * the returned-{@code 'String'}. (Or, if some other {@code 'abbrevStr'} were specified, that 147 * other abbreviation would be appended to the beginning of the returned-{@code String}) 148 * 149 * @param escapeNewLines <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_ENL> 150 * @param abbrevStr <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_STR> 151 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_MXL> 152 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_1_RET> 153 * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_1_IAEX> 154 */ 155 @LinkJavaSource(handle="Abbrev", name="print1") 156 public static String abbrev( 157 String s, 158 int abbrevPos, 159 boolean escapeNewLines, 160 String abbrevStr, 161 int maxLength 162 ) 163 { return Abbrev.print1(s, abbrevPos, escapeNewLines, abbrevStr, maxLength); } 164 165 /** 166 * Convenience Method. 167 * <BR />Parameter: {@code spaceBeforeAbbrev} set to {@code FALSE} 168 * <BR />Abbreviates: Default ellipsis ({@code '...'}) are placed at the end of the 169 * {@code String} 170 * <BR />See Documentation: {@link #abbrev(String, boolean, boolean, String, int)} 171 */ 172 @LinkJavaSource(handle="Abbrev", name="print2") 173 public static String abbrevEnd(String s, boolean escapeNewLines, int maxLength) 174 { return Abbrev.print2(s, false, escapeNewLines, null, maxLength); } 175 176 /** 177 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_2_DESC> 178 * @param s This may be any Java (non-null) {@code String} 179 * 180 * @param spaceBeforeAbbrev This ensures that for whatever variant of ellipsis being used, the 181 * space-character is inserted directly before appending the ellipsis {@code "..."} or the 182 * user-provided {@code 'abbrevStr'}. 183 * 184 * @param escapeNewLines <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_ENL> 185 * @param abbrevStr <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_STR> 186 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_MXL> 187 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_2_RET> 188 * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_2_IAEX> 189 */ 190 @LinkJavaSource(handle="Abbrev", name="print2") 191 public static String abbrev( 192 String s, 193 boolean spaceBeforeAbbrev, 194 boolean escapeNewLines, 195 String abbrevStr, 196 int maxLength 197 ) 198 { return Abbrev.print2(s, spaceBeforeAbbrev, escapeNewLines, abbrevStr, maxLength); } 199 200 201 // ******************************************************************************************** 202 // ******************************************************************************************** 203 // Abbreviated List Printing 204 // ******************************************************************************************** 205 // ******************************************************************************************** 206 207 208 /** 209 * Convenience Method. 210 * <BR />Passes: {@code Object.toString()} to {@code 'listItemPrinter'} 211 * <BR />See Documentation: {@link #printListAbbrev(Iterable, IntTFunction, int, int, boolean, 212 * boolean, boolean)} 213 */ 214 @LinkJavaSource(handle="PrintListAbbrev", name="print1") 215 public static <ELEM> String printListAbbrev( 216 Iterable<ELEM> list, int lineWidth, int indentation, boolean seeEscapedNewLinesAsText, 217 boolean printNulls, boolean showLineNumbers 218 ) 219 { 220 return PrintListAbbrev.print1( 221 list, (int i, Object o) -> o.toString(), lineWidth, indentation, 222 seeEscapedNewLinesAsText, printNulls, showLineNumbers 223 ); 224 } 225 226 /** 227 * <EMBED CLASS=defs DATA-LIST_TYPE=Array> 228 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_DESCRIPTION> 229 * @param list Any iterable-list of Java Object's 230 * 231 * @param listItemPrinter 232 * <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_LIST_ITEM_PR> 233 * 234 * @param lineWidth <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_LINE_WIDTH> 235 * @param indentation <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_INDENTATION> 236 * @param seeEscapedNewLinesAsText <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_SEE_ESC_NL> 237 * @param printNulls <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_PRINT_NULLS> 238 * @param showLineNumbers <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_SHOW_LNUMS> 239 * @return <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_RETURNS> 240 * 241 * @see #zeroPad10e2(int) 242 * @see #abbrevEndRDSF(String, int, boolean) 243 * @see StringParse#nChars(char, int) 244 * @see StringParse#trimLeft(String) 245 */ 246 @LinkJavaSource(handle="PrintListAbbrev", name="print1") 247 public static <ELEM> String printListAbbrev( 248 Iterable<ELEM> list, 249 IntTFunction<? super ELEM, String> listItemPrinter, 250 int lineWidth, 251 int indentation, 252 boolean seeEscapedNewLinesAsText, 253 boolean printNulls, 254 boolean showLineNumbers 255 ) 256 { 257 return PrintListAbbrev.print1( 258 list, listItemPrinter, lineWidth, indentation, seeEscapedNewLinesAsText, 259 printNulls, showLineNumbers 260 ); 261 } 262 263 /** 264 * Convenience Method. 265 * <BR />Passes: {@code Object.toString()} to {@code 'listItemPrinter'} 266 * <BR />See Documentation: {@link #printListAbbrev(Object[], IntTFunction, int, int, boolean, 267 * boolean, boolean)} 268 */ 269 @LinkJavaSource(handle="PrintListAbbrev", name="print2") 270 public static <ELEM> String printListAbbrev( 271 ELEM[] arr, 272 int lineWidth, 273 int indentation, 274 boolean seeEscapedNewLinesAsText, 275 boolean printNulls, 276 boolean showLineNumbers 277 ) 278 { 279 return PrintListAbbrev.print2( 280 arr, (int i, Object o) -> o.toString(), lineWidth, indentation, 281 seeEscapedNewLinesAsText, printNulls, showLineNumbers 282 ); 283 } 284 285 /** 286 * <EMBED CLASS=defs DATA-LIST_TYPE=Array> 287 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_DESCRIPTION> 288 * @param list Any iterable-list of Java Object's 289 * 290 * @param listItemPrinter 291 * <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_LIST_ITEM_PR> 292 * 293 * @param lineWidth <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_LINE_WIDTH> 294 * @param indentation <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_INDENTATION> 295 * @param seeEscapedNewLinesAsText <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_SEE_ESC_NL> 296 * @param printNulls <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_PRINT_NULLS> 297 * @param showLineNumbers <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_SHOW_LNUMS> 298 * @return <EMBED CLASS=external-html DATA-FILE-ID=SP_PLA_RETURNS> 299 * 300 * @see #zeroPad10e2(int) 301 * @see #abbrevEndRDSF(String, int, boolean) 302 * @see StringParse#trimLeft(String) 303 */ 304 @LinkJavaSource(handle="PrintListAbbrev", name="print2") 305 public static <ELEM> String printListAbbrev( 306 ELEM[] list, 307 IntTFunction<? super ELEM, String> listItemPrinter, 308 int lineWidth, 309 int indentation, 310 boolean seeEscapedNewLinesAsText, 311 boolean printNulls, 312 boolean showLineNumbers 313 ) 314 { 315 return PrintListAbbrev.print2( 316 list, listItemPrinter, lineWidth, indentation, seeEscapedNewLinesAsText, 317 printNulls, showLineNumbers 318 ); 319 } 320 321 322 // ******************************************************************************************** 323 // ******************************************************************************************** 324 // Line(s) of Text 325 // ******************************************************************************************** 326 // ******************************************************************************************** 327 328 329 /** 330 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_LINE_OR_DESC> 331 * 332 * @param s This may be any valid Java {@code String}. It ought to be some variant of a 333 * text-file. It will be searched for the nearest {@code '\n'} character - <I>in both 334 * directions, left and right</I> - from parameter {@code int 'pos'} and parameter 335 * {@code int 'len'} 336 * 337 * @param pos This is a position in the input-parameter {@code String 's'}. The nearest 338 * {@code '\n'} (new-line) character, <I>to the left</I> of this position, will be found and 339 * identified. If the {@code char} at {@code s.charAt(pos)} is, itself, a {@code '\n'} 340 * (newline) character, then no left-direction search will be performed. The left-most 341 * position of the returned substring would then be {@code pos + 1}. 342 * 343 * @param len The search for the 'right-most' {@code '\n'} (newline-character) will begin at 344 * position {@code 'len'}. If the character at {@code s.charAt(pos + len)} is, itself, a 345 * new-line character, then no right-direction search will be performed. The right-most 346 * position of the returned substring would be {@code pos + len - 1}. 347 * 348 * @param unixColorCode If this {@code String} is null, it will be ignored. If this 349 * {@code String} is non-null, it will be inserted before the "Matching {@code String}" 350 * indicated by the index-boundaries {@code pos} <I>TO</I> {@code pos + len}. 351 * 352 * <BR /><BR /><DIV CLASS=JDHint> 353 * <B STYLE='color:red;'>Note:</B> No Validity Check shall be performed on this {@code String}, 354 * and the user is not obligated to provide a {@link C} valid UNIX Color-Code {@code String}. 355 * Also, a closing {@code C.RESET} is inserted after the terminus of the match. 356 * </DIV> 357 * 358 * @return The {@code String} demarcated by the first new-line character PLUS 1 359 * <I><B>BEFORE</I></B> index {@code 'pos'}, and the first new-line character MINUS 1 360 * <I><B>AFTER</I></B> index {@code pos + len}. 361 * 362 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_LINES_RET> 363 * 364 * @throws StringIndexOutOfBoundsException If either {@code 'pos'}, or {@code 'pos + len'} are 365 * not within the bounds of the input {@code String 's'} 366 * 367 * @throws IllegalArgumentException If the value passed to parameter {@code 'len'} is zero or 368 * negative. 369 */ 370 public static String lineOrLines(String s, int pos, int len, String unixColorCode) 371 { 372 if ((pos >= s.length()) || (pos < 0)) throw new StringIndexOutOfBoundsException( 373 "The integer passed to parameter 'pos' [" + pos + "], is past the bounds of the end " + 374 "of String 's', which has length [" + s.length() + "]" 375 ); 376 377 if (len <= 0) throw new IllegalArgumentException 378 ("The value passed to parameter 'len' [" + len + "], may not be negative."); 379 380 if ((pos + len) > s.length()) throw new StringIndexOutOfBoundsException( 381 "The total of parameter 'pos' [" + pos + "], and parameter 'len' [" + len + "], is: " + 382 "[" + (pos + len) + "]. Unfortunately, String parameter 's' only has length " + 383 "[" + s.length() + "]" 384 ); 385 386 int linesStart, linesEnd, temp; 387 388 if (pos == 0) linesStart = 0; 389 else if (s.charAt(pos) == '\n') linesStart = pos + 1; 390 else if ((temp = StrIndexOf.left(s, pos, '\n')) != -1) linesStart = temp + 1; 391 else linesStart = 0; 392 393 if ((pos + len) == s.length()) linesEnd = s.length(); 394 else if (s.charAt(pos + len) == '\n') linesEnd = pos + len; 395 else if ((temp = s.indexOf('\n', pos + len)) != -1) linesEnd = temp; 396 else linesEnd = s.length(); 397 398 /* 399 // VERY USEFUL FOR DEBUGGING. DO NOT DELETE... 400 // NOTE: This method is the one that GREP uses. 401 System.out.println("s.charAt(pos)\t\t= " + "[" + s.charAt(pos) + "]"); 402 System.out.println("s.charAt(pos+len)\t= " + "[" + s.charAt(pos+len) + "]"); 403 System.out.println("s.length()\t\t= " + s.length()); 404 System.out.println("pos\t\t\t= " + pos); 405 System.out.println("pos + len\t\t= " + (pos + len)); 406 System.out.println("linesStart\t\t= " + linesStart); 407 System.out.println("linesEnd\t\t= " + linesEnd); 408 */ 409 410 return (unixColorCode != null) 411 ? s.substring(linesStart, pos) + 412 unixColorCode + s.substring(pos, pos + len) + RESET + 413 s.substring(pos + len, linesEnd) 414 : s.substring(linesStart, linesEnd); 415 416 /* 417 OOPS.... For Posterity, this shall remain, here, but commented 418 s.substring(linesStart, pos) + 419 s.substring(pos, pos + len) + 420 s.substring(pos + len, linesEnd); 421 */ 422 } 423 424 /** 425 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_LINE_DESC> 426 * 427 * @param s This may be any valid Java {@code String}. It ought to be some variant of a 428 * text-file. It will be searched for the nearest {@code '\n'} character - <I>in both 429 * directions, left and right</I> - from parameter {@code int 'pos'}. 430 * 431 * @param pos This is a position in the input-parameter {@code String 's'}. The nearest 432 * new-line character both to the left of this position, and to the right, will be found and 433 * identified. If the character at {@code s.charAt(pos)} is itself a newline {@code '\n'} 434 * character, then <I>an exception shall throw</I>. 435 * 436 * @return The {@code String} identified by the first new-line character PLUS 1 437 * <I><B>BEFORE</I></B> index {@code 'pos'}, and the first new-line character MINUS 1 438 * <I><B>AFTER</I></B> index {@code 'pos + len'}. 439 * 440 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_LINES_RET> 441 * 442 * @throws StringIndexOutOfBoundsException If {@code 'pos'} is not within the bounds of the 443 * input {@code String 's'} 444 * 445 * @throws IllegalArgumentException If the character in {@code String 's'} at position 446 * {@code 'pos'} is a newline {@code '\n'}, itself. 447 */ 448 public static String line(String s, int pos) 449 { 450 if ((pos > s.length()) || (pos < 0)) throw new StringIndexOutOfBoundsException( 451 "The integer passed to parameter 'pos' [" + pos + "], is past the bounds of the end of " + 452 "String 's', which has length [" + s.length() + "]" 453 ); 454 455 if (s.charAt(pos) == '\n') throw new IllegalArgumentException( 456 "The position-index for string-parameter 's' contains, itself, a new line character " + 457 "'\\n.' This is not allowed here." 458 ); 459 460 int lineStart, lineEnd; 461 462 // Prevents StrIndexOf from throwing StringINdexOutOfBounds 463 if (pos == 0) lineStart = 0; 464 465 // Also prevent lineStart equal-to '-1' 466 else if ((lineStart = StrIndexOf.left(s, pos, '\n')) == -1) lineStart = 0; 467 468 // Prevent lineEnd equal to '-1' 469 if ((lineEnd = s.indexOf('\n', pos)) == -1) lineEnd = s.length(); 470 471 // if this is the first line, there was no initial '\n', so don't skip it! 472 return (lineStart == 0) 473 474 // This version returns the String from the position-0 (Pay Attention!) 475 ? s.substring(0, lineEnd) 476 477 // This version simply eliminates the '\n' that is in the directly-preceeding character 478 : s.substring(lineStart + 1, lineEnd); 479 } 480 481 /** 482 * This will retrieve the first {@code 'n'} lines of a {@code String} - where a line is defined 483 * as everything up to and including the next newline {@code '\n'} character. 484 * 485 * @param s Any java {@code String}. 486 * 487 * @param n This is the number of lines of text to retrieve. 488 * 489 * @return a substring of s where the last character in the {@code String} is a {@code '\n'}. 490 * The last character should be the nth {@code '\n'} character found in s. If there is no such 491 * character, then the original {@code String} shall be returned instead. 492 * 493 * @throws NException This exception shall throw if parameter {@code 'n'} is less than 1, or 494 * longer than {@code s.length()}. 495 */ 496 public static String firstNLines(String s, int n) 497 { 498 NException.check(n, s); 499 int pos = StrIndexOf.nth(s, n, '\n'); 500 501 if (pos != -1) return s.substring(0, pos + 1); 502 else return s; 503 } 504 505 /** 506 * This will retrieve the last 'n' lines of a {@code String} - where a line is defined as 507 * everything up to and including the next newline {@code '\n'} character. 508 * 509 * @param s Any java {@code String}. 510 * 511 * @param n This is the number of lines of text to retrieve. 512 * 513 * @return a substring of {@code 's'} where the last character in the {@code String} is a 514 * new-line character {@code '\n'}, and the first character is the character directly before 515 * the nth newline {@code '\n'} found in {@code 's'} - starting the count at the end of the 516 * {@code String}. If there is no such substring, then the original {@code String} shall be 517 * returned. 518 * 519 * @throws NException This exception shall throw if {@code 'n'} is less than 1, or longer 520 * {@code s.length()}. 521 */ 522 public static String lastNLines(String s, int n) 523 { 524 NException.check(n, s); 525 int pos = StrIndexOf.nthFromEnd(s, n, '\n'); 526 527 if (pos != -1) return s.substring(pos + 1); 528 else return s; 529 } 530 531 /** 532 * This is used for "trimming each line" of an input {@code String}. Generally, when dealing 533 * with HTML there may be superfluous white-space that is useful in some places, but not 534 * necessarily when HTML is copied and pasted to other sections of a page (or to another page, 535 * altogether). This will split a {@code String} by new-line characters, and then trim each 536 * line, and afterward rebuild the {@code String} and return it. 537 * 538 * <BR /><BR /><DIV CLASS=JDHint> 539 * <B STYLE='color:red;'>CRLF Issues:</B> This will only split the {@code String} using the 540 * standard {@code '\n'} character. If the {@code String} being used uses {@code '\r'} or 541 * {@code '\n\r'}, use a different trim method. 542 * </DIV> 543 * 544 * @param str This may be any {@code String}. It will be split by new-line characters 545 * {@code '\n'} 546 * 547 * @return Returns the rebuilt {@code String}, with each line having a {@code String.trim();} 548 * operation performed. 549 */ 550 public static String trimEachLine(String str) 551 { 552 StringBuilder sb = new StringBuilder(); 553 554 for (String s : str.split("\\n")) 555 556 if ((s = s.trim()).length() == 0) continue; 557 else sb.append(s + '\n'); 558 559 return sb.toString().trim(); 560 } 561 562 /** 563 * Interprets an input {@code String} as one which was read out of a Text-File. Counts the 564 * number of new-line ({@code '\n'}) characters between {@code String} indices {@code '0'} and 565 * {@code 'pos'} 566 * 567 * <BR /><BR />This is intended be the Line-Number where {@code String}-Index parameter 568 * {@code 'pos'} is located inside the {@code 'str'} (presuming {@code 'str'} was retrieved 569 * from a Text-File). 570 * 571 * @param str Any Java {@code String}, preferably one with multiple lines of text. 572 * @param pos Any valid {@code String}-Index that occurs ithin {@code 'str'} 573 * 574 * @return The Line-Number within Text-File parameter {@code 'str'} which contains 575 * {@code String}-Index parameter {@code 'pos'} 576 * 577 * @throws StringIndexOutOfBoundsException If integer-parameter {@code 'pos'} is negative or 578 * past the length of the {@code String}-Parameter {@code 'str'}. 579 * 580 * @see #lineNumberSince(String, int, int, int) 581 */ 582 public static int lineNumber(String str, int pos) 583 { 584 if (pos < 0) throw new StringIndexOutOfBoundsException 585 ("The number provided to index parameter 'pos' : [" + pos + "] is negative."); 586 587 if (pos >= str.length()) throw new StringIndexOutOfBoundsException( 588 "The number provided to index parameter 'pos' : [" + pos + "] is greater than the " + 589 "length of the input String-Parameter 'str' [" + str.length() + "]." 590 ); 591 592 int lineNum = 1; 593 594 for (int i=0; i <= pos; i++) if (str.charAt(i) == '\n') lineNum++; 595 596 return lineNum; 597 } 598 599 /** 600 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_LINE_SINCE_DESC> 601 * 602 * @param str Any Java {@code String}. This {@code String} will be interpreted as a Text-File 603 * whose newline characters ({@code '\n'} chars) represent lines of text. 604 * 605 * @param pos Any valid {@code String}-index within {@code 'str'} 606 * 607 * @param prevLineNum This should be the Line-Number that contains the {@code String}-index 608 * {@code 'prevPos'} 609 * 610 * @param prevPos This may be any index contained by {@code String} parameter {@code 'str'}. 611 * It is expected that this parameter be an index that occured on Line-Number 612 * {@code 'prevLineNum'} of the Text-File {@code 'str'} 613 * 614 * @return The Line-Number within Text-File parameter {@code 'str'} that contains 615 * {@code String}-index {@code 'pos'} 616 * 617 * @throws IllegalArgumentException If {@code 'pos'} is less than or equal to 618 * {@code 'prevPos'}, or if {@code 'prevLineNum'} is less than zero. 619 * 620 * @see #lineNumber(String, int) 621 */ 622 public static int lineNumberSince(String str, int pos, int prevLineNum, int prevPos) 623 { 624 if (pos <= prevPos) throw new IllegalArgumentException( 625 "The number provided to index parameter 'pos' : [" + pos + "] is less than or equal " + 626 "to previous-match index-parameter prevPos : [" + prevPos + "]" 627 ); 628 629 if (prevLineNum < 0) throw new IllegalArgumentException( 630 "You have provided a negative number to Line-Number parameter 'prevLineNum' : " + 631 "[" + prevLineNum + "]" 632 ); 633 634 for (int i = (prevPos + 1); i <= pos; i++) if (str.charAt(i) == '\n') prevLineNum++; 635 636 return prevLineNum; 637 } 638 639 640 // ******************************************************************************************** 641 // ******************************************************************************************** 642 // Abbreviation: Line-Length **AND** Number of Lines 643 // ******************************************************************************************** 644 // ******************************************************************************************** 645 646 647 /** 648 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WHA_DESCRIPTION> 649 * 650 * @param s Any Java {@code String} 651 * @param horizAbbrevStr <EMBED CLASS='external-html' DATA-FILE-ID=SP_WHA_H_ABBREV_STR> 652 * @param maxLineLength <EMBED CLASS='external-html' DATA-FILE-ID=SP_WHA_MAX_LINE_LEN> 653 * @param maxNumLines <EMBED CLASS='external-html' DATA-FILE-ID=SP_WHA_MAX_NM_LINES> 654 * 655 * @param compactConsecutiveBlankLines When this parameter is passed {@code TRUE}, any 656 * series of Empty-Lines, or lines only containing White-Space will be compacted to a single 657 * line of text that simply states {@code "[Compacted 10 Blank Lines]"} (or however many 658 * White-Space-Only Lines were actually compacted, if that number isn't {@code '10'}) 659 * 660 * @return The modified {@code String}. 661 * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=SP_WHA_IAEX> 662 */ 663 @LinkJavaSource(handle="VertAndHorizAbbrev") 664 public static String widthHeightAbbrev( 665 final String s, 666 final String horizAbbrevStr, 667 final Integer maxLineLength, 668 final Integer maxNumLines, 669 final boolean compactConsecutiveBlankLines 670 ) 671 { 672 return VertAndHorizAbbrev.print 673 (s, horizAbbrevStr, maxLineLength, maxNumLines, compactConsecutiveBlankLines); 674 } 675 676 677 // ******************************************************************************************** 678 // ******************************************************************************************** 679 // Wrap Text to another line 680 // ******************************************************************************************** 681 // ******************************************************************************************** 682 683 684 /** 685 * Convenience Method. 686 * <BR />See Documentation: {@link #wrap(String, int, int)} 687 * <BR />Passes same {@code 'lineLen'} value to <B><I>BOTH</I></B> Line-Length Parameters 688 */ 689 @LinkJavaSource(handle="Wrap") 690 @LinkJavaSource(handle="WrapHelpers") 691 public static String wrap(String s, int lineLen) 692 { return Wrap.wrap(s, lineLen, lineLen); } 693 694 /** 695 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_DESCRIPTION> 696 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_RIGHT_TRIM> 697 * 698 * @param s Any Java {@code String}; may not contain {@code '\t', '\f' or '\r'} 699 * @param firstLineLen <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_1ST_LN_LEN> 700 * @param lineLen The maximum allowable Line-Length for all other lines of text. 701 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_RETURNS> 702 * 703 * @throws StringFormatException <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_STR_FMT_EX> 704 * @throws IllegalArgumentException If {@code 'firstLineLen'} or {@code 'lineLen'} are 705 * zero or negative. 706 */ 707 @LinkJavaSource(handle="Wrap") 708 @LinkJavaSource(handle="WrapHelpers") 709 public static String wrap(String s, int firstLineLen, int lineLen) 710 { return Wrap.wrap(s, firstLineLen, lineLen); } 711 712 713 /** 714 * Convenience Method. 715 * <BR />See Documentation: {@link #wrapToIndentation(String, int, int)} 716 * <BR />Passes same {@code 'lineLen'} value to <B><I>BOTH</I></B> Line-Length Parameters 717 */ 718 @LinkJavaSource(handle="WrapToIndentation") 719 @LinkJavaSource(handle="WrapHelpers") 720 public static String wrapToIndentation(String s, int lineLen) 721 { return WrapToIndentation.wrap(s, lineLen, lineLen); } 722 723 /** 724 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_DESCRIPTION> 725 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_RIGHT_TRIM> 726 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_TO_INDENT> 727 * 728 * @param s Any Java {@code String}; may not contain {@code '\t', '\f' or '\r'} 729 * @param firstLineLen <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_1ST_LN_LEN> 730 * @param lineLen The maximum allowable Line-Length for all other lines of text. 731 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_RETURNS> 732 * 733 * <BR /><BR />As already explained, the returned {@code String} shall contain "wrapped" text 734 * which has an amount of indentation (space characters) equal to whatever line is directly 735 * above it. Indented lines, effectively, "inherit" the amount of indentation present in the 736 * line coming directly before them. 737 * 738 * @throws StringFormatException <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_STR_FMT_EX> 739 * @throws IllegalArgumentException If {@code 'firstLineLen'} or {@code 'lineLen'} are 740 * zero or negative. 741 */ 742 @LinkJavaSource(handle="WrapToIndentation") 743 @LinkJavaSource(handle="WrapHelpers") 744 public static String wrapToIndentation(String s, int firstLineLen, int lineLen) 745 { return WrapToIndentation.wrap(s, firstLineLen, lineLen); } 746 747 /** 748 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_DESCRIPTION> 749 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_RIGHT_TRIM> 750 * 751 * @param s Any Java {@code String}; may not contain {@code '\t', '\f' or '\r'} 752 * @param firstLineLen <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_1ST_LN_LEN> 753 * @param lineLen The maximum allowable Line-Length for all other lines of text. 754 * 755 * @param extraSpaces Wrapped text will get an additional amount of indentation, past 756 * any and all inherited indentation 757 * @return Wrapped. 758 * 759 * @throws StringFormatException <EMBED CLASS='external-html' DATA-FILE-ID=SP_WRAP_STR_FMT_EX> 760 * @throws IllegalArgumentException If {@code 'firstLineLen'} or {@code 'lineLen'} are 761 * zero or negative. 762 */ 763 @LinkJavaSource(handle="WrapToIndentationPlus") 764 @LinkJavaSource(handle="WrapHelpers") 765 public static String wrapToIndentationPlus 766 (String s, int firstLineLen, int lineLen, int extraSpaces) 767 { return WrapToIndentationPlus.wrap(s, firstLineLen, lineLen, extraSpaces); } 768 769 770 // ******************************************************************************************** 771 // ******************************************************************************************** 772 // Misc Date String Functions 773 // ******************************************************************************************** 774 // ******************************************************************************************** 775 776 777 private static final Calendar internalCalendar = Calendar.getInstance(); 778 779 /** 780 * Generates a "Date String" using the character separator {@code '.'} 781 * @return A {@code String} in the form: {@code YYYY.MM.DD} 782 */ 783 public static String dateStr() { return dateStr('.', false); } 784 785 /** 786 * Generates a "Date String" using the <I>separator</I> parameter as the separator between 787 * numbers 788 * 789 * @param separator Any ASCII or UniCode character. 790 * 791 * @return A {@code String} of the form: {@code YYYYcMMcDD} where {@code 'c'} is the passed 792 * {@code 'separator'} parameter. 793 */ 794 public static String dateStr(char separator) { return dateStr(separator, false); } 795 796 /** 797 * Generates a "Date String" that is consistent with the directory-name file-storage locations 798 * used to store articles from {@code http://Gov.CN}. 799 * 800 * @return The {@code String's} used for the Chinese Government Web-Portal Translation Pages 801 */ 802 public static String dateStrGOVCN() { return dateStr('/', false).replaceFirst("/", "-"); } 803 // "2017-12/05" 804 805 /** 806 * This class is primary included because although Java has a pretty reasonable "general 807 * purpose" calendar class/interface, but a consistent / same {@code String} since is needed 808 * because the primary use here is for building the names of files. 809 * 810 * @param separator Any ASCII or Uni-Code character. 811 * 812 * @param includeMonthName When <I>TRUE</I>, the English-Name of the month ({@code 'January'} 813 * ... {@code 'December'}) will be appended to the month number in the returned {@code String}. 814 * 815 * @return The year, month, and day as a {@code String}. 816 */ 817 public static String dateStr(char separator, boolean includeMonthName) 818 { 819 Calendar c = internalCalendar; 820 String m = zeroPad10e2(c.get(Calendar.MONTH) + 1); // January is month zero! 821 String d = zeroPad10e2(c.get(Calendar.DAY_OF_MONTH)); 822 823 if (includeMonthName) m += " - " + c.getDisplayName(Calendar.MONTH, 2, Locale.US); 824 825 return (separator != 0) 826 ? (c.get(Calendar.YEAR) + "" + separator + m + separator + d) 827 : (c.get(Calendar.YEAR) + "" + m + d); 828 } 829 830 831 // ******************************************************************************************** 832 // ******************************************************************************************** 833 // Misc Month-Date String Functions 834 // ******************************************************************************************** 835 // ******************************************************************************************** 836 837 838 /** The months of the year, as an immutable list of {@code String's}. */ 839 public static final ReadOnlyList<String> months = new ReadOnlyArrayList<>( 840 "January", "February", "March", "April", "May", "June", 841 "July", "August", "September", "October", "November", "December" 842 ); 843 844 /** 845 * Converts an integer into a Month. 846 * @param month The month, as a number from {@code '1'} to {@code '12'}. 847 * @return A month as a {@code String} like: {@code "January"} or {@code "August"} 848 * @see #months 849 */ 850 public static String monthStr(int month) { return months.get(month); } 851 852 /** 853 * Returns a {@code String} that has the year and the month (but not the day, or any other 854 * time related components). 855 * 856 * @return Returns the current year and month as a {@code String}. 857 */ 858 public static String ymDateStr() { return ymDateStr('.', false); } 859 860 /** 861 * Returns a {@code String} that has the year and the month (but not the day, or other time 862 * components). 863 * 864 * @param separator The single-character separator used between year, month and day. 865 * @return The current year and month as a {@code String}. 866 */ 867 public static String ymDateStr(char separator) { return ymDateStr(separator, false); } 868 869 /** 870 * Returns a {@code String} that has the year and the month (but not the day, or other time 871 * components). 872 * 873 * @param separator The single-character separator used between year, month and day. 874 * 875 * @param includeMonthName When this is true, the name of the month, in English, is included 876 * with the return {@code String}. 877 * 878 * @return {@code YYYY<separator>MM(? include-month-name)} 879 */ 880 public static String ymDateStr(char separator, boolean includeMonthName) 881 { 882 Calendar c = internalCalendar; 883 String m = zeroPad10e2(c.get(Calendar.MONTH) + 1); // January is month zero! 884 885 if (includeMonthName) m += " - " + c.getDisplayName(Calendar.MONTH, 2, Locale.US); 886 887 return (separator != 0) 888 ? (c.get(Calendar.YEAR) + "" + separator + m) 889 : (c.get(Calendar.YEAR) + "" + m); 890 } 891 892 893 // ******************************************************************************************** 894 // ******************************************************************************************** 895 // Misc Time String Functions 896 // ******************************************************************************************** 897 // ******************************************************************************************** 898 899 900 /** 901 * Returns the current time as a {@code String}. 902 * 903 * @return military time - with AM|PM (redundant) added too. 904 * Includes only Hour and Minute - separated by a colon character {@code ':'} 905 * 906 * @see #timeStr(char) 907 */ 908 public static String timeStr() { return timeStr(':'); } 909 910 /** 911 * Returns the current time as a {@code String}. 912 * @param separator The character used to separate the minute & hour fields 913 * @return military time - with AM|PM added redundantly, and a separator of your choosing. 914 */ 915 public static String timeStr(char separator) 916 { 917 Calendar c = internalCalendar; 918 int ht = c.get(Calendar.HOUR) + ((c.get(Calendar.AM_PM) == Calendar.AM) ? 0 : 12); 919 String h = zeroPad10e2((ht == 0) ? 12 : ht); // 12:00 is represented as "0"... changes this... 920 String m = zeroPad10e2(c.get(Calendar.MINUTE)); 921 String p = (c.get(Calendar.AM_PM) == Calendar.AM) ? "AM" : "PM"; 922 923 return (separator != 0) 924 ? (h + separator + m + separator + p) 925 : (h + m + p); 926 } 927 928 /** 929 * Returns the current time as a {@code String}. This method uses all time components 930 * available. 931 * 932 * @return military time - with AM|PM added redundantly. 933 */ 934 public static String timeStrComplete() 935 { 936 Calendar c = internalCalendar; 937 int ht = c.get(Calendar.HOUR) + ((c.get(Calendar.AM_PM) == Calendar.AM) ? 0 : 12); 938 String h = zeroPad10e2((ht == 0) ? 12 : ht); // 12:00 is represented as "0" 939 String m = zeroPad10e2(c.get(Calendar.MINUTE)); 940 String s = zeroPad10e2(c.get(Calendar.SECOND)); 941 String ms = zeroPad(c.get(Calendar.MILLISECOND)); 942 String p = (c.get(Calendar.AM_PM) == Calendar.AM) ? "AM" : "PM"; 943 944 return h + '-' + m + '-' + p + '-' + s + '-' + ms + "ms"; 945 } 946 947 948 // ******************************************************************************************** 949 // ******************************************************************************************** 950 // More Numeric Methods 951 // ******************************************************************************************** 952 // ******************************************************************************************** 953 954 955 private static final DecimalFormat formatter = new DecimalFormat("#,###"); 956 957 /** 958 * Makes a {@code long} number like {@code 123456789} into a number-string such as: 959 * {@code "123,456,789"}. Java's {@code package java.text.*} is easy to use, and versatile, but 960 * the commands are not always so easy to remember. 961 * 962 * @param l Any {@code long} integer. Comma's will be inserted for every third power of ten 963 * 964 * @return After calling java's {@code java.text.DecimalFormat} class, a {@code String} 965 * representing this parameter will be returned. 966 */ 967 public static String commas(long l) 968 { return formatter.format(l); } 969 970 /** 971 * The words "ordinal indicator" are referring to the little character {@code String} that is 972 * often used in English to make a number seem more a part of an english sentence. 973 * 974 * @param i Any positive integer (greater than 0) 975 * 976 * @return This will return the following strings: 977 * 978 * <TABLE CLASS=JDBriefTable> 979 * <TR><TH>Input: </TH><TH>RETURNS:</TH></TR> 980 * <TR><TD>i = 1 </TD><TD>"st" (as in "1st","first") </TD></TR> 981 * <TR><TD>i = 2 </TD><TD>"nd" (as in "2nd", "second") </TD></TR> 982 * <TR><TD>i = 4 </TD><TD>"th" (as in "4th") </TD></TR> 983 * <TR><TD>i = 23 </TD><TD>"rd" (as in "23rd") </TD></TR> 984 * </TABLE> 985 * 986 * @throws IllegalArgumentException If i is negative, or zero 987 */ 988 public static String ordinalIndicator(int i) 989 { 990 if (i < 1) throw new IllegalArgumentException 991 ("i: " + i + "\tshould be a natural number > 0."); 992 993 994 // Returns the last 2 digits of the number, or the number itself if it is less than 100. 995 // Any number greater than 100 - will not have the "text-ending" (1st, 2nd, 3rd..) affected 996 // by the digits after the first two digits. Just analyze the two least-significant digits 997 998 i = i % 100; 999 1000 // All numbers between "4th" and "19th" end with "th" 1001 if ((i > 3) && (i < 20)) return "th"; 1002 1003 // set i to be the least-significant digit of the number - if that number was 1, 2, or 3 1004 i = i % 10; 1005 1006 // Obvious: English Rules. 1007 if (i == 1) return "st"; 1008 if (i == 2) return "nd"; 1009 if (i == 3) return "rd"; 1010 1011 // Compiler is complaining. This statement should never be executed. 1012 return "th"; 1013 } 1014 1015 1016 // ******************************************************************************************** 1017 // ******************************************************************************************** 1018 // Zero Padding stuff 1019 // ******************************************************************************************** 1020 // ******************************************************************************************** 1021 1022 1023 /** 1024 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZERO_PAD_DESC> 1025 * @param n Any Integer. If {@code 'n'} is negative or greater than 1,000 - null is returned. 1026 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZERO_PAD_RET> 1027 * @see #zeroPad10e2(int) 1028 * @see #zeroPad10e4(int) 1029 */ 1030 public static String zeroPad(int n) 1031 { 1032 if (n < 0) return null; 1033 if (n < 10) return "00" + n; 1034 if (n < 100) return "0" + n; 1035 if (n < 1000) return "" + n; 1036 return null; 1037 } 1038 1039 /** 1040 * Pads an integer such that it contains enough leading zero's to ensure a 1041 * {@code String}-length of two. 1042 * 1043 * @param n Must be an integer between 0 and 99, or else null will be returned 1044 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZP_10E2_RET> 1045 * @see #zeroPad(int) 1046 */ 1047 public static String zeroPad10e2(int n) 1048 { 1049 if (n < 0) return null; 1050 if (n < 10) return "0" + n; 1051 if (n < 100) return "" + n; 1052 return null; 1053 } 1054 1055 /** 1056 * Pads an integer such that it contains enough leading zero's to ensure a String-length of 1057 * four. 1058 * 1059 * @param n Must be an integer between 0 and 9999, or else null will be returned 1060 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZP_10E4_RET> 1061 * @see #zeroPad(int) 1062 */ 1063 public static String zeroPad10e4(int n) 1064 { 1065 if (n < 0) return null; 1066 if (n < 10) return "000" + n; 1067 if (n < 100) return "00" + n; 1068 if (n < 1000) return "0" + n; 1069 if (n < 10000) return "" + n; 1070 return null; 1071 } 1072 1073 /** 1074 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZP_POW2_DESC> 1075 * 1076 * @param n Must be an integer between {@code '0'} and {@code '9999'} where the number of 1077 * {@code '9'} digits is equal to the value of parameter {@code int 'powerOf10'} 1078 * 1079 * @param powerOf10 This must be a positive integer greater than {@code '1'}. It may not be 1080 * larger {@code '11'}. The largest value that any integer in Java may attain is 1081 * {@code '2,147,483, 647'} 1082 * 1083 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_ZP_POW2_RET> 1084 * 1085 * @throws IllegalArgumentException if the value parameter {@code 'powerOf10'} is less than 2, 1086 * or greater than {@code 11}. 1087 */ 1088 public static String zeroPad(int n, int powerOf10) 1089 { 1090 if (n < 0) return null; // Negative Values of 'n' not allowed 1091 1092 char[] cArr = new char[powerOf10]; // The String's length will be equal to 'powerOf10' 1093 String s = "" + n; // (or else 'null' would be returned) 1094 int i = powerOf10 - 1; // Internal Loop variable 1095 int j = s.length() - 1; // Internal Loop variable 1096 1097 Arrays.fill(cArr, '0'); // Initially, fill the output char-array with all 1098 // zeros 1099 1100 while ((i >= 0) && (j >= 0)) // Now start filling that char array with the 1101 cArr[i--] = s.charAt(j--); // actual number 1102 1103 if (j >= 0) return null; // if all of parameter 'n' was inserted into the 1104 // output (number 'n' didn't fit) then powerOf10 1105 // was insufficient, so return null. 1106 1107 return new String(cArr); 1108 } 1109 1110}