001package Torello.Java; 002 003import Torello.Java.Function.IntTFunction; 004import static Torello.Java.C.*; 005 006// Needed for a few JavaDoc Comments 007import Torello.JavaDoc.Field; 008import Torello.JavaDoc.Constructor; 009import Torello.JavaDoc.Method; 010import Torello.JavaDoc.AnnotationElem; 011 012/** 013 * This class provides several {@code String} printing utilities such as abbreviation and list 014 * printing. 015 */ 016@Torello.JavaDoc.StaticFunctional 017public class StrPrint 018{ 019 private StrPrint() { } 020 021 022 // ******************************************************************************************** 023 // ******************************************************************************************** 024 // HELPER & BASIC 025 // ******************************************************************************************** 026 // ******************************************************************************************** 027 028 029 /** 030 * Converts every line-character ({@code '\n'}) - <I>and any white-space before or after 031 * that character</I>, into the {@code String} - {@code "\\n"} - which is the actual two 032 * character sequence of a back-slash ({@code '\'}), followed by the letter {@code 'n'}. 033 * 034 * <BR /><BR />After new-line characters are replaced, the method will remove any duplicate 035 * spaces that are present in the {@code String}, and reduce them to a single space character 036 * 037 * <BR /><TABLE CLASS=JDBriefTable> 038 * <TR><TH>Input {@code String}</TH><TH>Returned {@code String}</TH></TR> 039 * <TR><TD>"Hello World"</TD><TD>"Hello World"</TD></TR> 040 * <TR><TD>"Hello \t World"</TD><TD>"Hello World"</TD></TR> 041 * <TR><TD>"Hello World\n"</TD><TD>"Hello World\\n"</TD></TR> 042 * <TR><TD>"Hello World \n\t \n"</TD><TD>"Hello World\\n\\n"</TD></TR> 043 * <TR> 044 * <TD>"Hello Today!\nHow Are You?"</TD> 045 * <TD>"Hello Today!\\nHow Are You?"</TD> 046 * </TR> 047 * <TR> 048 * <TD>"Hello,\n Testing 1, 2, 3\n"</TD> 049 * <TD>"Hello,\\nTesting 1, 2, 3\\n"</TD> 050 * </TR> 051 * <TR> 052 * <TD>"Hello,\n Testing 1, 2, 3 \n\t\t\t"</TD> 053 * <TD>"Hello,\\nTesting 1, 2, 3\\n"</TD> 054 * </TR> 055 * <TR><TD>"\n"</TD><TD>"\\n"</TD></TR> 056 * <TR><TD>"\n \t"</TD><TD>"\\n"</TD></TR> 057 * <TR><TD>"\n\t \n\t \n\t "</TD><TD>"\\n\\n\\n"</TD></TR> 058 * </TABLE> 059 * 060 * <BR />This method is used in printing Java Source Code to a terminal - in an abbreviated 061 * way! After this method is finished, java-source-as-text is actually <B><I>still</I></B> 062 * look readable, and can be printed in a table of methods on a page. It is used in the Java 063 * Doc Upgrader tool, and makes printing up <B><I>both</I></B> method-signatures 064 * <B><I>and</I></B> method bodies quite a bit easier. 065 * 066 * <BR /><BR />For a better understanding of the use and application of this function, please 067 * take a look at the <B>{@code 'toString'}</B> methods: <B>{@link Method#toString()}, 068 * {@link Constructor#toString()}, {@link Field#toString()} and 069 * {@link AnnotationElem#toString()}</B> 070 * 071 * <BR /><BR /><B CLASS=JDDescLabel>Regular Expressions:</B> 072 * 073 * <BR />This method uses regular-expressions, rather performing an optimized, in-place, 074 * {@code String} replacement (such as one with a {@code for} or {@code while} loop). This 075 * means that there is a little efficiency sacrificed in the name of brevity. 076 * 077 * <BR /><BR />The replacement used in the {@code String.replaceAll} method was thouroughly 078 * tested. The quadruple-backslash {@code '\n'} <I>is actually necessary!</I> The first 079 * escape used is to communicate with the Java-Compiler, and the second round of escaping is 080 * communicating with the Regular Expression Processor. 081 * 082 * @param s Any {@code java.lang.String}, preferably one with multiple lines of text. 083 * 084 * @return A {@code String}, where each line of text has been "trimmed", and the two 085 * character sequence {@code "\\n"} inserted in-between each line. 086 * 087 * @see #abbrevStartRDSF(String, int, boolean) 088 * @see #abbrevEndRDSF(String, int, boolean) 089 */ 090 public static String newLinesAsText(String s) 091 { 092 return s 093 .replaceAll( 094 // White-Space-Except-Newline, THEN newline, THEN White-SpaceExcept-Newline 095 "[ \t\r\f\b]*\n[ \t\r\f\b]*", 096 097 // Replace Each Occurence of that with: 098 // == COMPILES-TO ==> "\\n" == REG-EX-READS ==> BackSlash and letter 'n' 099 "\\\\n" 100 ) 101 // == COMPILES-TO ==> "\s+" == REG-EX-READS ==> 'spaces' 102 .replaceAll("\\s+", " ") 103 104 // Don't forget about leading and trailing stuff... 105 .trim(); 106 } 107 108 109 // ******************************************************************************************** 110 // ******************************************************************************************** 111 // Abbreviating Text, with "newLinesAsText" - Helper 112 // ******************************************************************************************** 113 // ******************************************************************************************** 114 115 116 /** 117 * Convenience Method. 118 * <BR /><B STYLE='color: red;'>RDSF: Remove Duplicate Spaces First</B> 119 * <BR />Invokes: {@link StringParse#removeDuplicateSpaces(String)} 120 * <BR />Or Invokes: {@link #newLinesAsText(String)} 121 * <BR />Finally: {@link #abbrevStart(String, boolean, int)} 122 */ 123 public static String abbrevStartRDSF 124 (String s, int maxLength, boolean seeEscapedNewLinesAsText) 125 { 126 // false is passed to 'abbrevStart' parameter 'escapeNewLines' because in both scenarios 127 // of this conditional-statement, the new-lines have already been removed by the previous 128 // method call. 129 // 130 // both 'removeDuplicateSpaces' and 'newLinesAsText' remove the new-lines 131 132 return seeEscapedNewLinesAsText 133 ? abbrevStart(newLinesAsText(s), false, maxLength) 134 : abbrevStart(StringParse.removeDuplicateSpaces(s), false, maxLength); 135 } 136 137 /** 138 * Convenience Method. 139 * <BR /><B STYLE='color: red;'>RDSF: Remove Duplicate Spaces First</B> 140 * <BR />Invokes: {@link StringParse#removeDuplicateSpaces(String)} 141 * <BR />Or Invokes: {@link #newLinesAsText(String)} 142 * <BR />Finally: {@link #abbrevEnd(String, boolean, int)} 143 */ 144 public static String abbrevEndRDSF 145 (String s, int maxLength, boolean seeEscapedNewLinesAsText) 146 { 147 // false is passed to 'abbrevStart' parameter 'escapeNewLines' because in both scenarios 148 // of this conditional-statement, the new-lines have already been removed by the previous 149 // method call. 150 // 151 // both 'removeDuplicateSpaces' and 'newLinesAsText' remove the new-lines 152 153 return seeEscapedNewLinesAsText 154 ? abbrevEnd(newLinesAsText(s), false, maxLength) 155 : abbrevEnd(StringParse.removeDuplicateSpaces(s), false, maxLength); 156 } 157 158 /** 159 * Convenience Method. 160 * <BR />Passes: {@code '0'} to parameter {@code 'abbrevPos'}, forcing the abbreviation to 161 * occur at the <B>start</B> of the {@code String} (if long enough to be abbreviated) 162 * @see #abbrev(String, int, boolean, String, int) 163 */ 164 public static String abbrevStart(String s, boolean escNewLines, int maxLength) 165 { return Abbrev.print(s, 0, escNewLines, null, maxLength); } 166 167 /** 168 * This will abbreviate any {@code String} using either the ellipsis ({@code '...'}), or some 169 * other use provided abbreviation-{@code String} - <I>as long as the provided {@code String} 170 * is longer than {@code 'maxLength'}.</I> When {@code 's'} is, indeed, longer than 171 * {@code 'maxLength'} the returned-{@code String} will contain the ellipsis abbreviation 172 * beginning at {@code String}-index {@code 'abbrevPos'}. 173 * 174 * <BR /><BR />You have the option of asking that new-line characters ({@code '\n'}) be 175 * escaped into the two-character {@code String: "\\n"}. This optional is provided so that 176 * the output may fit on a single-line, for readability purposes. It will look somewhat like 177 * an escaped {@code JSON} file, which also substitues {@code '\n'} characters for the 178 * 'escaped' version {@code "\\n"}. <I>Note that when this occurs, the replaced-{@code String} 179 * actually only contains two characters, <B>not three,</B> since the first back-slash your are 180 * looking right here is, itself, an escape character!</I> 181 * 182 * @param s This may be any Java (non-null) {@code String} 183 * 184 * @param abbrevPos This parameter is used to indicate where the abbreviation-{@code String} 185 * should occur - <I>if this {@code String 's'} is long enough to be abbreviated.</I> For 186 * instance, if {@code '0'} (zero) were passed to this parameter, and {@code 's'} were longer 187 * than parameter {@code 'maxLength'}, then an ellipsis would be appended to the beginning of 188 * the returned-{@code 'String'}. (Or, if some other {@code 'abbrevStr'} were specified, that 189 * other abbreviation would be appended to the beginning of the returned-{@code String}) 190 * 191 * @param escapeNewLines <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_ENL> 192 * @param abbrevStr <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_STR> 193 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_MXL> 194 * 195 * @return If the input {@code String} has a <I>length less-than {@code 'maxLength'}</I>, then 196 * it is returned, unchanged. If the input contained new-line characters, and you have 197 * requested to escape them, that replacement is performed first (which makes the original 198 * {@code String}} longer). Then, if the {@code String} is longer than {@code 'maxLength'}, 199 * it is abbreviated, and either the default ellipsis <I>or the user-provided 200 * {@code 'abbrevStr'}</I> are inserted at location {@code 'abbrevPos'} and returned. 201 * 202 * <BR /><BR />If, after the new-line escape-replacement, the returned-{@code String} would not 203 * be longer than {@code 'maxLength'}, then that escaped-{@code String} is returned, as is 204 * (without any elliptical-characters). 205 * 206 * @throws IllegalArgumentException If the value for {@code 'maxLength'} is negative, or if it 207 * is less than the length of the abbreviation. 208 * 209 * <BR /><BR />Specifically, if {@code 'maxLength'} isn't even long enough to fit the abbreviation 210 * itself, then this exception will throw. 211 * 212 * <BR /><BR />If the value passed to {@code 'abbrevPos'} is negative or longer than the value 213 * passed to {@code 'maxLength'} minus the length of the ellipsis-{@code String}, then this 214 * exception will also throw. 215 */ 216 public static String abbrev( 217 String s, 218 int abbrevPos, 219 boolean escapeNewLines, 220 String abbrevStr, 221 int maxLength 222 ) 223 { return Abbrev.print(s, abbrevPos, escapeNewLines, abbrevStr, maxLength); } 224 225 /** 226 * Convenience Method. 227 * <BR />Parameter: {@code spaceBeforeAbbrev} set to {@code FALSE} 228 * <BR />Abbreviates: Default ellipsis ({@code '...'}) are placed at the end of the 229 * {@code String} 230 * @see #abbrev(String, boolean, boolean, String, int) 231 */ 232 public static String abbrevEnd(String s, boolean escapeNewLines, int maxLength) 233 { return Abbrev.print(s, false, escapeNewLines, null, maxLength); } 234 235 /** 236 * This will abbreviate any {@code String} using either the ellipsis ({@code '...'}), or some 237 * other use provided abbreviation-{@code String}, if the provided {@code String} is longer 238 * than {@code 'maxLength'}. If the returned-{@code String} is, indeed, abbreviated then the 239 * elliptical-abbreviation {@code String} will be placed <I>at the end of the 240 * returned-{@code String}</I> 241 * 242 * <BR /><BR />You have the option of asking that new-line characters ({@code '\n'}) be 243 * escaped into the two-character {@code String: "\\n"}. This optional is provided so that 244 * the output may fit on a single-line, for readability purposes. It will look somewhat like 245 * an escaped {@code JSON} file, which also substitues {@code '\n'} characters for the 246 * 'escaped' version {@code "\\n"}. <I>Note that when this occurs, the replaced-{@code String} 247 * actually only contains two characters, <B>not three,</B> since the first back-slash your are 248 * looking right here is, itself, an escape character!</I> 249 * 250 * @param s This may be any Java (non-null) {@code String} 251 * 252 * @param spaceBeforeAbbrev This ensures that for whatever variant of ellipsis being used, the 253 * space-character is inserted directly before appending the ellipsis {@code "..."} or the 254 * user-provided {@code 'abbrevStr'}. 255 * 256 * @param escapeNewLines <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_ENL> 257 * @param abbrevStr <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_STR> 258 * @param maxLength <EMBED CLASS='external-html' DATA-FILE-ID=SP_ABBREV_MXL> 259 * 260 * @return If the input {@code String} has a <I>length less-than {@code 'maxLength'}</I>, then 261 * it is returned, unchanged. If the input contained new-line characters, and you have 262 * requested to escape them, that replacement is performed first (which makes the original 263 * {@code String}} longer). Then, if the {@code String} is longer than {@code 'maxLength'}, 264 * it is abbreviated, and either the default ellipsis <I>or the user-provided 265 * {@code 'abbrevStr'}</I> are are appended to the end and returned. 266 * 267 * @throws IllegalArgumentException If the value for {@code 'maxLength'} is negative, or if it 268 * is less than the length of the abbreviation plus the value of {@code 'spaceBeforeAbbrev'}. 269 * <BR /><BR />Specifically, if {@code 'maxLength'} isn't even long enough to fit the abbreviation 270 * itself, then this exception will throw. 271 */ 272 public static String abbrev( 273 String s, 274 boolean spaceBeforeAbbrev, 275 boolean escapeNewLines, 276 String abbrevStr, 277 int maxLength 278 ) 279 { return Abbrev.print(s, spaceBeforeAbbrev, escapeNewLines, abbrevStr, maxLength); } 280 281 282 // ******************************************************************************************** 283 // ******************************************************************************************** 284 // Abbreviated List Printing 285 // ******************************************************************************************** 286 // ******************************************************************************************** 287 288 289 /** 290 * Convenience Method. 291 * <BR />Passes: {@code Object.toString()} to {@code 'listItemPrinter'} 292 * @see #printListAbbrev(Iterable, IntTFunction, int, int, boolean, boolean, boolean) 293 */ 294 public static <ELEM> String printListAbbrev( 295 Iterable<ELEM> list, int lineWidth, int indentation, boolean seeEscapedNewLinesAsText, 296 boolean printNulls, boolean showLineNumbers 297 ) 298 { 299 return PrintListAbbrev.print( 300 list, (int i, Object o) -> o.toString(), lineWidth, indentation, 301 seeEscapedNewLinesAsText, printNulls, showLineNumbers 302 ); 303 } 304 305 /** 306 * <EMBED CLASS=defs DATA-LIST_TYPE=Array> 307 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_DESCRIPTION> 308 * @param list Any iterable-list of Java Object's 309 * @param listItemPrinter <EMBED CLASS='extenal-html' DATA-FILE-ID=SP_PLA_LIST_ITEM_PR> 310 * @param lineWidth <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_LINE_WIDTH> 311 * @param indentation <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_INDENTATION> 312 * @param seeEscapedNewLinesAsText <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_SEE_ESC_NL> 313 * @param printNulls <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_PRINT_NULLS> 314 * @param showLineNumbers <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_SHOW_LNUMS> 315 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_RETURNS> 316 * @see StringParse#zeroPad10e2(int) 317 * @see #abbrevEndRDSF(String, int, boolean) 318 * @see StringParse#nChars(char, int) 319 * @see StringParse#trimLeft(String) 320 */ 321 public static <ELEM> String printListAbbrev( 322 Iterable<ELEM> list, 323 IntTFunction<? super ELEM, String> listItemPrinter, 324 int lineWidth, 325 int indentation, 326 boolean seeEscapedNewLinesAsText, 327 boolean printNulls, 328 boolean showLineNumbers 329 ) 330 { 331 return PrintListAbbrev.print( 332 list, listItemPrinter, lineWidth, indentation, seeEscapedNewLinesAsText, 333 printNulls, showLineNumbers 334 ); 335 } 336 337 /** 338 * Convenience Method. 339 * <BR />Passes: {@code Object.toString()} to {@code 'listItemPrinter'} 340 * @see #printListAbbrev(Object[], IntTFunction, int, int, boolean, boolean, boolean)} 341 */ 342 public static <ELEM> String printListAbbrev( 343 ELEM[] arr, 344 int lineWidth, 345 int indentation, 346 boolean seeEscapedNewLinesAsText, 347 boolean printNulls, 348 boolean showLineNumbers 349 ) 350 { 351 return PrintListAbbrev.print( 352 arr, (int i, Object o) -> o.toString(), lineWidth, indentation, 353 seeEscapedNewLinesAsText, printNulls, showLineNumbers 354 ); 355 } 356 357 /** 358 * <EMBED CLASS=defs DATA-LIST_TYPE=Array> 359 * <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_DESCRIPTION> 360 * @param list Any iterable-list of Java Object's 361 * @param listItemPrinter <EMBED CLASS='extenal-html' DATA-FILE-ID=SP_PLA_LIST_ITEM_PR> 362 * @param lineWidth <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_LINE_WIDTH> 363 * @param indentation <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_INDENTATION> 364 * @param seeEscapedNewLinesAsText <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_SEE_ESC_NL> 365 * @param printNulls <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_PRINT_NULLS> 366 * @param showLineNumbers <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_SHOW_LNUMS> 367 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SP_PLA_RETURNS> 368 * @see StringParse#zeroPad10e2(int) 369 * @see #abbrevEndRDSF(String, int, boolean) 370 * @see StringParse#trimLeft(String) 371 */ 372 public static <ELEM> String printListAbbrev( 373 ELEM[] list, 374 IntTFunction<? super ELEM, String> listItemPrinter, 375 int lineWidth, 376 int indentation, 377 boolean seeEscapedNewLinesAsText, 378 boolean printNulls, 379 boolean showLineNumbers 380 ) 381 { 382 return PrintListAbbrev.print( 383 list, listItemPrinter, lineWidth, indentation, seeEscapedNewLinesAsText, 384 printNulls, showLineNumbers 385 ); 386 } 387 388 389 // ******************************************************************************************** 390 // ******************************************************************************************** 391 // Line(s) of Text 392 // ******************************************************************************************** 393 // ******************************************************************************************** 394 395 396 /** 397 * This will return the complete text-lines of character data for the line identified by 398 * token-substring position parameters {@code pos} and {@code len}. This method will search, 399 * in the left-direction (decreasing {@code String} index) for the first new-line character 400 * identified. It will also search, starting at position {@code pos + len}, for the first 401 * new-line character in the right-direction (increasing {@code String} index). 402 * 403 * <BR /><BR />If the token-substring identified by {@code s.substring(pos, len)} itself 404 * contains any new-line characters, these will neither affect the prepended, nor the 405 * post-pended search {@code String}. To be precise, any newline characters between 406 * {@code 'pos'} and {@code 'len'} will be irrelevant to the left-wards and right-wards 407 * newlines searches for new-line characters. 408 * 409 * @param s This may be any valid Java {@code String}. It ought to be some variant of a 410 * text-file. It will be searched for the nearest {@code '\n'} character - <I>in both 411 * directions, left and right</I> - from parameter {@code int 'pos'} and parameter 412 * {@code int 'len'} 413 * 414 * @param pos This is a position in the input-parameter {@code String 's'}. The nearest 415 * {@code '\n'} (new-line) character, <I>to the left</I> of this position, will be found and 416 * identified. If the {@code char} at {@code s.charAt(pos)} is, itself, a {@code '\n'} 417 * (newline) character, then no left-direction search will be performed. The left-most 418 * position of the returned substring would then be {@code pos + 1}. 419 * 420 * @param len The search for the 'right-most' {@code '\n'} (newline-character) will begin at 421 * position {@code 'len'}. If the character at {@code s.charAt(pos + len)} is, itself, a 422 * new-line character, then no right-direction search will be performed. The right-most 423 * position of the returned substring would be {@code pos + len - 1}. 424 * 425 * @param unixColorCode If this {@code String} is null, it will be ignored. If this 426 * {@code String} is non-null, it will be inserted before the "Matching {@code String}" 427 * indicated by the index-boundaries {@code pos} <I>TO</I> {@code pos + len}. 428 * 429 * <BR /><BR /><B>NOTE:</B> No Validity Check shall be performed on this {@code String}, and 430 * the user is not obligated to provide a {@link C} valid UNIX Color-Code {@code String}. 431 * Also, a closing {@code C.RESET} is inserted after the terminus of the match. 432 * 433 * @return The {@code String} demarcated by the first new-line character PLUS 1 434 * <I><B>BEFORE</I></B> index {@code 'pos'}, and the first new-line character MINUS 1 435 * <I><B>AFTER</I></B> index {@code pos + len}. 436 * 437 * <BR /><BR /><B>NOTE:</B> The above does mean, indeed, that the starting and ending 438 * new-lines <B>WILL NOT</B> be included in the returned {@code String}. 439 * 440 * <BR /><BR /><B>ALSO:</B> Also, if there are no new-line characters before position 441 * {@code 'pos'}, then every character beginning at position zero will be included in the 442 * returned {@code String} result. Also, if there are no new-line characters after position 443 * {@code pos + len} then every character after position {@code pos + len} will be appended to 444 * the returned {@code String} result. 445 * 446 * @throws StringIndexOutOfBoundsException If either {@code 'pos'}, or {@code 'pos + len'} are 447 * not within the bounds of the input {@code String 's'} 448 * 449 * @throws IllegalArgumentException If the value passed to parameter {@code 'len'} is zero or 450 * negative. 451 */ 452 public static String lineOrLines(String s, int pos, int len, String unixColorCode) 453 { 454 if ((pos >= s.length()) || (pos < 0)) throw new StringIndexOutOfBoundsException( 455 "The integer passed to parameter 'pos' [" + pos + "], is past the bounds of the end " + 456 "of String 's', which has length [" + s.length() + "]" 457 ); 458 459 if (len <= 0) throw new IllegalArgumentException 460 ("The value passed to parameter 'len' [" + len + "], may not be negative."); 461 462 if ((pos + len) > s.length()) throw new StringIndexOutOfBoundsException( 463 "The total of parameter 'pos' [" + pos + "], and parameter 'len' [" + len + "], is: " + 464 "[" + (pos + len) + "]. Unfortunately, String parameter 's' only has length " + 465 "[" + s.length() + "]" 466 ); 467 468 int linesStart, linesEnd, temp; 469 470 if (pos == 0) linesStart = 0; 471 else if (s.charAt(pos) == '\n') linesStart = pos + 1; 472 else if ((temp = StrIndexOf.left(s, pos, '\n')) != -1) linesStart = temp + 1; 473 else linesStart = 0; 474 475 if ((pos + len) == s.length()) linesEnd = s.length(); 476 else if (s.charAt(pos + len) == '\n') linesEnd = pos + len; 477 else if ((temp = s.indexOf('\n', pos + len)) != -1) linesEnd = temp; 478 else linesEnd = s.length(); 479 480 /* 481 // VERY USEFUL FOR DEBUGGING. DO NOT DELETE... 482 // NOTE: This method is the one that GREP uses. 483 System.out.println("s.charAt(pos)\t\t= " + "[" + s.charAt(pos) + "]"); 484 System.out.println("s.charAt(pos+len)\t= " + "[" + s.charAt(pos+len) + "]"); 485 System.out.println("s.length()\t\t= " + s.length()); 486 System.out.println("pos\t\t\t= " + pos); 487 System.out.println("pos + len\t\t= " + (pos + len)); 488 System.out.println("linesStart\t\t= " + linesStart); 489 System.out.println("linesEnd\t\t= " + linesEnd); 490 */ 491 492 return (unixColorCode != null) 493 ? s.substring(linesStart, pos) + 494 unixColorCode + s.substring(pos, pos + len) + RESET + 495 s.substring(pos + len, linesEnd) 496 : s.substring(linesStart, linesEnd); 497 /* 498 OOPS.... For Posterity, this shall remain, here, but commented 499 s.substring(linesStart, pos) + 500 s.substring(pos, pos + len) + 501 s.substring(pos + len, linesEnd); 502 */ 503 } 504 505 /** 506 * This will return the complete text-line of character data from 'inside' the input-parameter 507 * {@code String s}. The meaning of {@code 'complete text-line'}, in this method, is that any 508 * and all character data between the first {@code '\n'} (new-line character) when scanning 509 * towards <I>the right</I> (increasing {@code String}-index) and the first {@code '\n'} 510 * character when scanning towards <I>the left</I> (decreasing index) constitutes 511 * {@code 'a line'} (of text-data). 512 * 513 * <BR /><BR />This scan shall for the left-most and right-most new-line shall begin at 514 * {@code String}-index parameter {@code pos}. If either the left-direction or 515 * right-direction scan does not find any new-line characters, then start and end indices of 516 * the returned line of text shall be demarcated by input-{@code String} index {@code '0'} and 517 * index {@code String.length()}, <I><B>respectively</B></I> 518 * 519 * @param s This may be any valid Java {@code String}. It ought to be some variant of a 520 * text-file. It will be searched for the nearest {@code '\n'} character - <I>in both 521 * directions, left and right</I> - from parameter {@code int 'pos'}. 522 * 523 * @param pos This is a position in the input-parameter {@code String 's'}. The nearest 524 * new-line character both to the left of this position, and to the right, will be found and 525 * identified. If the character at {@code s.charAt(pos)} is itself a newline {@code '\n'} 526 * character, then <I>an exception shall throw</I>. 527 * 528 * @return The {@code String} identified by the first new-line character PLUS 1 529 * <I><B>BEFORE</I></B> index {@code 'pos'}, and the first new-line character MINUS 1 530 * <I><B>AFTER</I></B> index {@code 'pos + len'}. 531 * 532 * <BR /><BR /><B>NOTE:</B> The above means, that the starting and ending new-lines, 533 * themselves, will not be included in the {@code String} that is returned. 534 * 535 * <BR /><BR /><B>ALSO:</B> Also, if there are no new-line characters before position 536 * {@code 'pos'}, then every character beginning at position zero will be included in the 537 * returned {@code String} result. Also, if there are no new-line characters after position 538 * {@code 'pos + len'} then every character after position {@code 'pos + len'} will be appended 539 * to the returned {@code String} result. 540 * 541 * @throws StringIndexOutOfBoundsException If {@code 'pos'} is not within the bounds of the 542 * input {@code String 's'} 543 * 544 * @throws IllegalArgumentException If the character in {@code String 's'} at position 545 * {@code 'pos'} is a newline {@code '\n'}, itself. 546 */ 547 public static String line(String s, int pos) 548 { 549 if ((pos > s.length()) || (pos < 0)) throw new StringIndexOutOfBoundsException( 550 "The integer passed to parameter 'pos' [" + pos + "], is past the bounds of the end of " + 551 "String 's', which has length [" + s.length() + "]" 552 ); 553 554 if (s.charAt(pos) == '\n') throw new IllegalArgumentException( 555 "The position-index for string-parameter 's' contains, itself, a new line character " + 556 "'\\n.' This is not allowed here." 557 ); 558 559 int lineStart, lineEnd; 560 561 // Prevents StrIndexOf from throwing StringINdexOutOfBounds 562 if (pos == 0) lineStart = 0; 563 564 // Also prevent lineStart equal-to '-1' 565 else if ((lineStart = StrIndexOf.left(s, pos, '\n')) == -1) lineStart = 0; 566 567 // Prevent lineEnd equal to '-1' 568 if ((lineEnd = s.indexOf('\n', pos)) == -1) lineEnd = s.length(); 569 570 // if this is the first line, there was no initial '\n', so don't skip it! 571 return (lineStart == 0) 572 573 // This version returns the String from the position-0 (Pay Attention!) 574 ? s.substring(0, lineEnd) 575 576 // This version simply eliminates the '\n' that is in the directly-preceeding character 577 : s.substring(lineStart + 1, lineEnd); 578 } 579 580 /** 581 * This will retrieve the first {@code 'n'} lines of a {@code String} - where a line is defined 582 * as everything up to and including the next newline {@code '\n'} character. 583 * 584 * @param s Any java {@code String}. 585 * 586 * @param n This is the number of lines of text to retrieve. 587 * 588 * @return a substring of s where the last character in the {@code String} is a {@code '\n'}. 589 * The last character should be the nth {@code '\n'} character found in s. If there is no such 590 * character, then the original {@code String} shall be returned instead. 591 * 592 * @throws NException This exception shall throw if parameter {@code 'n'} is less than 1, or 593 * longer than {@code s.length()}. 594 */ 595 public static String firstNLines(String s, int n) 596 { 597 NException.check(n, s); 598 int pos = StrIndexOf.nth(s, n, '\n'); 599 600 if (pos != -1) return s.substring(0, pos + 1); 601 else return s; 602 } 603 604 /** 605 * This will retrieve the last 'n' lines of a {@code String} - where a line is defined as 606 * everything up to and including the next newline {@code '\n'} character. 607 * 608 * @param s Any java {@code String}. 609 * 610 * @param n This is the number of lines of text to retrieve. 611 * 612 * @return a substring of {@code 's'} where the last character in the {@code String} is a 613 * new-line character {@code '\n'}, and the first character is the character directly before 614 * the nth newline {@code '\n'} found in {@code 's'} - starting the count at the end of the 615 * {@code String}. If there is no such substring, then the original {@code String} shall be 616 * returned. 617 * 618 * @throws NException This exception shall throw if {@code 'n'} is less than 1, or longer 619 * {@code s.length()}. 620 */ 621 public static String lastNLines(String s, int n) 622 { 623 NException.check(n, s); 624 int pos = StrIndexOf.nthFromEnd(s, n, '\n'); 625 626 if (pos != -1) return s.substring(pos + 1); 627 else return s; 628 } 629 630 /** 631 * This is used for "trimming each line" of an input {@code String}. Generally, when dealing 632 * with HTML there may be superfluous white-space that is useful in some places, but not 633 * necessarily when HTML is copied and pasted to other sections of a page (or to another page, 634 * altogether). This will split a {@code String} by new-line characters, and then trim each 635 * line, and afterward rebuild the {@code String} and return it. 636 * 637 * <BR /><BR /><B CLASS=JDDescLabel>CRLF Issues:</B> 638 * 639 * <BR />This will only split the {@code String} using the standard {@code '\n'} character. If 640 * the {@code String} being used uses {@code '\r'} or {@code '\n\r'}, use a different trim 641 * method. 642 * 643 * @param str This may be any {@code String}. It will be split by new-line characters 644 * {@code '\n'} 645 * 646 * @return Returns the rebuilt {@code String}, with each line having a {@code String.trim();} 647 * operation performed. 648 */ 649 public static String trimEachLine(String str) 650 { 651 StringBuilder sb = new StringBuilder(); 652 653 for (String s : str.split("\\n")) 654 655 if ((s = s.trim()).length() == 0) continue; 656 else sb.append(s + '\n'); 657 658 return sb.toString().trim(); 659 } 660 661 /** 662 * Interprets an input {@code String} as one which was read out of a Text-File. Counts the 663 * number of new-line ({@code '\n'}) characters between {@code String} indices {@code '0'} and 664 * {@code 'pos'} 665 * 666 * <BR /><BR />This is intended be the Line-Number where {@code String}-Index parameter 667 * {@code 'pos'} is located inside the {@code 'str'} (presuming {@code 'str'} was retrieved 668 * from a Text-File). 669 * 670 * @param str Any Java {@code String}, preferably one with multiple lines of text. 671 * @param pos Any valid {@code String}-Index that occurs ithin {@code 'str'} 672 * 673 * @return The Line-Number within Text-File parameter {@code 'str'} which contains 674 * {@code String}-Index parameter {@code 'pos'} 675 * 676 * @throws StringIndexOutOfBoundsException If integer-parameter {@code 'pos'} is negative or 677 * past the length of the {@code String}-Parameter {@code 'str'}. 678 * 679 * @see #lineNumberSince(String, int, int, int) 680 */ 681 public static int lineNumber(String str, int pos) 682 { 683 if (pos < 0) throw new StringIndexOutOfBoundsException 684 ("The number provided to index parameter 'pos' : [" + pos + "] is negative."); 685 686 if (pos >= str.length()) throw new StringIndexOutOfBoundsException( 687 "The number provided to index parameter 'pos' : [" + pos + "] is greater than the " + 688 "length of the input String-Parameter 'str' [" + str.length() + "]." 689 ); 690 691 int lineNum = 1; 692 693 for (int i=0; i <= pos; i++) if (str.charAt(i) == '\n') lineNum++; 694 695 return lineNum; 696 } 697 698 /** 699 * This methe may be used, iteratively, inside of a loop for finding the location of any 700 * subsequent {@code String}-Index within a Text-File, based on the information obtained from 701 * a previous Line-Number retrieval. 702 * 703 * <BR /><BR /><B CLASS=JDDescLabel>Use inside For-Loop:</B> 704 * 705 * <BR />This method is designed to be used within a {@code 'for'} or {@code 'while'} loop. 706 * Though it is true that the exception-check which occurs inside this method is superfluous 707 * and redundant, the cost incurred by the two {@code if}-statements is minimal. These checks 708 * are used here, in the code, primarily for readability. 709 * 710 * <BR /><BR />If maximum efficiency is needed, then copy and paste the bottom two lines of 711 * code into your editor, and use that instead, without the exception-checks. 712 * 713 * <BR />In the example below, it should be noted how to use both methods to iterate through 714 * the line numbers in a Text-File, efficiently. 715 * 716 * <DIV CLASS=EXAMPLE>{@code 717 * 718 * int[] posArr = findIndices(myString, "Raindrops on Roses", "Whiskers on Kittens"); 719 * int lineNumber = StrPrint.lineNumber(myString, posArr[0]); 720 * int prevPos = posArr[0]; 721 * 722 * System.out.println("There is a match on line: " + lineNumber); 723 * 724 * for (int i=1; i < posArr.length; i++) 725 * { 726 * lineNumber = StrPrint.lineNumberSince(myString, posArr[i], lineNumber, prevPos); 727 * System.out.println("There is a match on line: " + lineNumber); 728 * 729 * prevPos = posArr[i]; 730 * } 731 * }</DIV> 732 * 733 * @param str Any Java {@code String}. This {@code String} will be interpreted as a Text-File 734 * whose newline characters ({@code '\n'} chars) represent lines of text. 735 * 736 * @param pos Any valid {@code String}-index within {@code 'str'} 737 * 738 * @param prevLineNum This should be the Line-Number that contains the {@code String}-index 739 * {@code 'prevPos'} 740 * 741 * @param prevPos This may be any index contained by {@code String} parameter {@code 'str'}. 742 * It is expected that this parameter be an index that occured on Line-Number 743 * {@code 'prevLineNum'} of the Text-File {@code 'str'} 744 * 745 * @return The Line-Number within Text-File parameter {@code 'str'} that contains 746 * {@code String}-index {@code 'pos'} 747 * 748 * @throws IllegalArgumentException If {@code 'pos'} is less than or equal to 749 * {@code 'prevPos'}, or if {@code 'prevLineNum'} is less than zero. 750 * 751 * @see #lineNumber(String, int) 752 */ 753 public static int lineNumberSince(String str, int pos, int prevLineNum, int prevPos) 754 { 755 if (pos <= prevPos) throw new IllegalArgumentException( 756 "The number provided to index parameter 'pos' : [" + pos + "] is less than or equal " + 757 "to previous-match index-parameter prevPos : [" + prevPos + "]" 758 ); 759 760 if (prevLineNum < 0) throw new IllegalArgumentException( 761 "You have provided a negative number to Line-Number parameter 'prevLineNum' : " + 762 "[" + prevLineNum + "]" 763 ); 764 765 for (int i = (prevPos + 1); i <= pos; i++) if (str.charAt(i) == '\n') prevLineNum++; 766 767 return prevLineNum; 768 } 769 770 771 // ******************************************************************************************** 772 // ******************************************************************************************** 773 // Abbreviation: Line-Length **AND** Number of Lines 774 // ******************************************************************************************** 775 // ******************************************************************************************** 776 777 778 /** 779 * This method allows for printing an abbreviation of a {@code String} such that 780 * <B STYLE='color: red;'><I>BOTH</I></B> the number of lines (height), 781 * <B STYLE='color: red;'><I>AND</I></B> the length of each line of text (width) can both be 782 * abbreviated. There is even a third abbreviation that is possible, and that is where 783 * blank-links can be compacted / flattened first (before the abbreviation process starts). 784 * 785 * <BR /><BR />This method is being used for printing JSON-Response Objects that contain large 786 * HTML-Page {@code String's}. Primarily, if you want to see a message, but do not want 787 * hundreds or even thousands of lines of HTML blasted across your terminal, then this method is 788 * for you! 789 * 790 * <BR /><BR />The package {@code Torello.Browser's} Web-Sockets Communications is making use 791 * of this for printing Chrome-Browser Messages to the terminal. 792 * 793 * @param s Any Java {@code String} 794 * 795 * @param horizAbbrevStr If you have a specific Abbreviation-{@code String} that you would like 796 * to see used in Horizontally-Abbreviated Lines, please pass it here. 797 * 798 * <BR /><BR />Note that this value is directly passed to the {@code 'abbrevStr'} parameters 799 * in the Standard {@code String}-Abbreviation methods. This means that when this parameter is 800 * null, it will be ignored - <I>and if any horizontal (line-length) abbreviattions occur, then 801 * the 'Default-Abbreviation {@code String}' {@code "..."} will be used</I>. 802 * 803 * <BR ><BR />Also note that if parameter {@code 'maxLineLength'} is passed null, then lines of 804 * text will not be shortened. In that case, each line of text will retain its exact length 805 * that occured prior to the internal {@code String.split()} invocation. 806 * 807 * @param maxLineLength If you would like to shorten each line of text which is appended to the 808 * returned {@code String}, then pass a positive value to this parameter. 809 * 810 * <BR /><BR />This parameter may be null, and if it is, it will be ignored. In such cases, 811 * individual lines of text will retain their original length. 812 * 813 * @param maxNumLines This is the maximum number of lines of text that will appear in the 814 * returned {@code String}. Note, under normal operation, if this parameter is passed 815 * {@code '3'}, then there will be exactly three lines of text. Furthermore there will be 816 * exactly {@code '2'} newline {@code '\n'} characters. 817 * 818 * @param compactConsecutiveBlankLines When this parameter is passed {@code TRUE}, any 819 * series of Empty-Lines, or lines only containing White-Space will be compacted to a single 820 * line of text that simply states {@code "[Compacted 10 Blank Lines]"} (or however many 821 * White-Space-Only Lines were actually compacted, if that number isn't {@code '10'}) 822 * 823 * @return The modified {@code String}. 824 * 825 * @throws IllegalArgumentException If parameter {@code 'maxNumLines'} is less than 3. The 826 * returned {@code String} must be long enough to keep the first line, the last line and the 827 * abbreviation note. 828 * 829 * <BR /><BR />This exception will also throw if the internal invocation of the standard 830 * {@code String}-abbreviation method is passed a {@code 'maxLineLength'} that is less than 831 * the minimum line-length requirements for a successful horizontal abbreviation. 832 * 833 * <BR /><BR />Finally, this exception throws if {@code 'maxLineLength'} and 834 * {@code 'maxNumLines'} are both passed null, and {@code 'compactConsecutiveBlankLines'}. 835 * This scenario is considered an error-case because there it would exact a situation where 836 * there is nothing for this method to do. 837 */ 838 public static String widthHeightAbbrev( 839 final String s, 840 final String horizAbbrevStr, 841 final Integer maxLineLength, 842 final Integer maxNumLines, 843 final boolean compactConsecutiveBlankLines 844 ) 845 { 846 return VertAndHorizAbbrev.print 847 (s, horizAbbrevStr, maxLineLength, maxNumLines, compactConsecutiveBlankLines); 848 } 849}