001package Torello.Java; 002 003import java.util.*; 004import java.util.regex.*; 005import java.io.*; 006import java.util.stream.*; 007import java.util.function.*; 008 009import java.text.DecimalFormat; 010import java.net.URL; 011 012import Torello.JavaDoc.IntoHTMLTable; 013import Torello.JavaDoc.LinkJavaSource; 014 015import static Torello.JavaDoc.Entity.FIELD; 016import static Torello.JavaDoc.IntoHTMLTable.Background.BlueDither; 017import static Torello.JavaDoc.IntoHTMLTable.Background.GreenDither; 018 019/** 020 * A plethora of extensions to Java's {@code String} class. 021 * <EMBED CLASS='external-html' DATA-FILE-ID=STRING_PARSE> 022 */ 023@Torello.JavaDoc.StaticFunctional 024public class StringParse 025{ 026 private StringParse() { } 027 028 029 // ******************************************************************************************** 030 // ******************************************************************************************** 031 // Constants 032 // ******************************************************************************************** 033 // ******************************************************************************************** 034 035 036 /** 037 * This regular expression simply matches white-space found in a java {@code String}. 038 * @see #removeWhiteSpace(String) 039 */ 040 public static final Pattern WHITE_SPACE_REGEX = Pattern.compile("\\s+"); 041 042 /** 043 * This {@code Predicate<String>} checks whether the contents of a {@code java.lang.String} 044 * are comprised of only White-Space Characters. 045 * 046 * <BR /><BR />Java's {@code 'asMatchPredicate'} is very similar to appending the Reg-Ex 047 * Control-Characters {@code '^'} and {@code '$'} to the beginning and ending of a 048 * {@code String}. 049 * 050 * <BR /><BR /><B CLASS=JDDescLabel>Important:</B> Since the Regular Expression used is the 051 * one defined, above, as {@code \w+} - <I>using the {@code '+'}, rather than the 052 * {@code '*'}</I> - this {@code Predicate} will return {@code FALSE} when a Zero-Length 053 * {@code String} is passed as input. 054 * 055 * @see #WHITE_SPACE_REGEX 056 * @see #onlyWhiteSpace_OrZeroLen 057 */ 058 public static final Predicate<String> onlyWhiteSpace = 059 WHITE_SPACE_REGEX.asMatchPredicate(); 060 061 /** 062 * This is a {@code Predicate} that works in an identical manner to {@link #onlyWhiteSpace}, 063 * with the minor addded stipulation that a Zero-Length {@code String} will generate a 064 * {@code TRUE} / pass result from the {@code Predicate.test(String)} method. 065 * 066 * @see #onlyWhiteSpace 067 */ 068 public static final Predicate<String> onlyWhiteSpace_OrZeroLen = 069 Pattern.compile("^\\s*$").asPredicate(); 070 071 /** 072 * This regular expression simply matches the comma. The only reason for including this here 073 * is because the java {@code class 'Pattern'} contains a method called 074 * {@code Stream<String> 'splitAsStream(CharSequence)'} which is used for the CSV method 075 * further below 076 * 077 * @see StrCSV#CSV(String, boolean, boolean) 078 * @see FileRW#readDoublesFromFile(String, boolean, boolean) 079 * @see FileRW#readLongsFromFile(String, boolean, boolean, int) 080 */ 081 public static final Pattern COMMA_REGEX = Pattern.compile(","); 082 083 /** 084 * This regular expression is used for integer and floating-point numbers that use the 085 * comma ({@code ','}) between the digits that comprise the number. For example, this 086 * Regular Expression would match the {@code String} {@code "900,800,75.00"}. 087 * 088 * @see FileRW#readIntsFromFile(String, boolean, boolean, int) 089 */ 090 public static final Pattern NUMBER_COMMMA_REGEX = Pattern.compile("(\\d),(\\d)"); 091 092 /** 093 * This represents any version of the new-line character. Note that the {@code '\r\n'} version 094 * comes before the single {@code '\r'} version in the regular-expression, to guarantee that 095 * if both are present, they are treated as a single newline. 096 */ 097 public static final Pattern NEWLINEP = Pattern.compile("\\r\\n|\\r|\\n"); 098 099 /** 100 * Predicate for new-line characters 101 * @see #NEWLINEP 102 */ 103 public static final Predicate<String> newLinePred = NEWLINEP.asPredicate(); 104 105 /** This is the list of characters that need to be escaped for a regular expression */ 106 public static final String REG_EX_ESCAPE_CHARS = "\\/()[]{}$^+*?-."; 107 108 /** Alpha-Numeric RegEx */ 109 public static final Pattern ALPHA_NUMERIC = Pattern.compile("^[\\d\\w]*$"); 110 111 /** 112 * Alpha-Numeric {@code String} Predicate. 113 * @see #ALPHA_NUMERIC 114 */ 115 public static final Predicate<String> alphaNumPred = ALPHA_NUMERIC.asPredicate(); 116 117 /** An empty {@code String} array. */ 118 public static final String[] EMPTY_STR_ARRAY = {}; 119 120 121 // ******************************************************************************************** 122 // ******************************************************************************************** 123 // methods 124 // ******************************************************************************************** 125 // ******************************************************************************************** 126 127 128 /** 129 * Trims any white-space {@code Characters} from the end of a {@code String}. 130 * 131 * <BR /><TABLE CLASS=JDBriefTable> 132 * <TR><TH>Input String:</TH><TH>Output String:</TH></TR> 133 * <TR><TD>{@code "A Quick Brown Fox\n \t"}</TD><TD>{@code "A Quick Brown Fox"}</TD></TR> 134 * <TR><TD>{@code "\tA Lazy Dog."}</TD><TD>{@code "\tA Lazy Dog."}</TD></TR> 135 * <TR><TD>{@code " " (only white-space)}</TD><TD>{@code ""}</TD></TR> 136 * <TR><TD>{@code "" (empty-string)}</TD><TD>{@code ""}</TD></TR> 137 * <TR><TD>{@code null}</TD><TD>throws {@code NullPointerException}</TD></TR> 138 * </TABLE> 139 * 140 * @param s Any Java {@code String} 141 * 142 * @return A copy of the same {@code String} - <I>but all characters that matched Java 143 * method {@code java.lang.Character.isWhitespace(char)}</I> and were at the end of the 144 * {@code String} will not be included in the returned {@code String}. 145 * 146 * <BR /><BR />If the {@code zero-length String} is passed to parameter {@code 's'}, it 147 * shall be returned immediately. 148 * 149 * <BR /><BR />If the resultant-{@code String} has zero-length, it is returned, without 150 * exception. 151 */ 152 public static String trimRight(String s) 153 { 154 if (s.length() == 0) return s; 155 156 int pos = s.length(); 157 158 while ((pos > 0) && Character.isWhitespace(s.charAt(--pos))); 159 160 if (pos == 0) if (Character.isWhitespace(s.charAt(0))) return ""; 161 162 return s.substring(0, pos + 1); 163 } 164 165 /** 166 * Trims any white-space {@code Characters} from the beginning of a {@code String}. 167 * 168 * <TABLE CLASS=JDBriefTable> 169 * <TR><TH>Input String:</TH><TH>Output String:</TH></TR> 170 * <TR><TD>{@code "\t A Quick Brown Fox"}</TD><TD>{@code "A Quick Brown Fox"}</TD></TR> 171 * <TR><TD>{@code "A Lazy Dog. \n\r\t"}</TD><TD>{@code "A Lazy Dog. \n\r\t"}</TD></TR> 172 * <TR><TD>{@code " " (only white-space)}</TD><TD>{@code ""}</TD></TR> 173 * <TR><TD>{@code "" (empty-string)}</TD><TD>{@code ""}</TD></TR> 174 * <TR><TD>{@code null}</TD><TD>throws {@code NullPointerException}</TD></TR> 175 * </TABLE> 176 * 177 * @param s Any Java {@code String} 178 * 179 * @return A copy of the same {@code String} - <I>but all characters that matched Java 180 * method {@code java.lang.Character.isWhitespace(char)}</I> and were at the start of the 181 * {@code String} will not be included in the returned {@code String}. 182 * 183 * <BR /><BR />If the {@code zero-length String} is passed to parameter {@code 's'}, it 184 * shall be returned immediately. 185 * 186 * <BR /><BR />If the resultant-{@code String} has zero-length, it is returned, without 187 * exception. 188 */ 189 public static String trimLeft(String s) 190 { 191 int pos = 0; 192 int len = s.length(); 193 194 if (len == 0) return s; 195 196 while ((pos < len) && Character.isWhitespace(s.charAt(pos++))); 197 198 if (pos == len) if (Character.isWhitespace(s.charAt(len-1))) return ""; 199 200 return s.substring(pos - 1); 201 } 202 203 /** 204 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_SPC_PAD_L_DESC> 205 * @param s This may be any {@code java.lang.String} 206 * @param totalStringLength 207 * <EMBED CLASS='external-html' DATA-PREPOST=pre DATA-FILE-ID=STRP_SPC_PAD_TOTAL_LEN> 208 * @throws IllegalArgumentException If {@code totalStringLength} is zero or negative. 209 * @see #rightSpacePad(String, int) 210 */ 211 public static String leftSpacePad(String s, int totalStringLength) 212 { 213 CHECK_NEGATIVE(totalStringLength); 214 215 return (s.length() >= totalStringLength) 216 ? s 217 : String.format("%1$" + totalStringLength + "s", s); 218 } 219 220 /** 221 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_SPC_PAD_R_DESC> 222 * @param s This may be any {@code java.lang.String} 223 * @param totalStringLength 224 * <EMBED CLASS='external-html' DATA-PREPOST=post DATA-FILE-ID=STRP_SPC_PAD_TOTAL_LEN> 225 * @throws IllegalArgumentException If {@code totalStringLength} is zero or negative. 226 * @see #leftSpacePad(String, int) 227 */ 228 public static String rightSpacePad(String s, int totalStringLength) 229 { 230 CHECK_NEGATIVE(totalStringLength); 231 232 return (s.length() >= totalStringLength) 233 ? s 234 : String.format("%1$-" + totalStringLength + "s", s); 235 } 236 237 private static void CHECK_NEGATIVE(int totalStringLength) 238 { 239 if (totalStringLength <= 0) throw new IllegalArgumentException( 240 "totalString length was '" + totalStringLength + ", " + 241 "however it is expected to be a positive integer." 242 ); 243 } 244 245 /** 246 * Runs a Regular-Expression over a {@code String} to retrieve all matches that occur between 247 * input {@code String} parameter {@code 's'} and Regular-Expression {@code 'regEx'}. 248 * 249 * @param s Any Java {@code String} 250 * @param regEx Any Java Regular-Expression 251 * 252 * @param eliminateOverlappingMatches When this parameter is passed {@code 'TRUE'}, successive 253 * matches that have portions which overlap each-other are eliminated. 254 * 255 * @return An array of all {@code MatchResult's} (from package {@code 'java.util.regex.*'}) that 256 * were produced by iterating the {@code Matcher's} {@code 'find()'} method. 257 */ 258 public static MatchResult[] getAllMatches 259 (String s, Pattern regEx, boolean eliminateOverlappingMatches) 260 { 261 Stream.Builder<MatchResult> b = Stream.builder(); 262 Matcher m = regEx.matcher(s); 263 int prevEnd = 0; 264 265 while (m.find()) 266 { 267 MatchResult matchResult = m.toMatchResult(); 268 269 // This skip any / all overlapping matches - if the user has requested it 270 if (eliminateOverlappingMatches) if (matchResult.start() < prevEnd) continue; 271 272 b.accept(matchResult); 273 274 prevEnd = matchResult.end(); 275 } 276 277 // Convert the Java-Stream into a Java-Array and return the result 278 return b.build().toArray(MatchResult[]::new); 279 } 280 281 282 // ******************************************************************************************** 283 // ******************************************************************************************** 284 // Helper set & get for strings 285 // ******************************************************************************************** 286 // ******************************************************************************************** 287 288 289 /** 290 * This sets a character in a {@code String} to a new value, and returns a result 291 * @param str Any java {@code String} 292 * @param i An index into the underlying character array of that {@code String}. 293 * @param c A new character to be placed at the <I>i'th position</I> of this {@code String}. 294 * 295 * @return a new java {@code String}, with the appropriate index into the {@code String} 296 * substituted using character parameter {@code 'c'}. 297 */ 298 public static String setChar(String str, int i, char c) 299 { 300 return ((i + 1) < str.length()) 301 ? (str.substring(0, i) + c + str.substring(i + 1)) 302 : (str.substring(0, i) + c); 303 } 304 305 /** 306 * This removes a character from a {@code String}, and returns a new {@code String} as a 307 * result. 308 * 309 * @param str Any Java-{@code String}. 310 * 311 * @param i This is the index into the underlying java {@code char}-array whose character will 312 * be removed from the return {@code String}. 313 * 314 * @return Since Java {@code String}'s are all immutable, this {@code String} that is returned 315 * is completely new, with the character that was originally at index 'i' removed. 316 */ 317 public static String delChar(String str, int i) 318 { 319 if ((i + 1) < str.length()) 320 return str.substring(0, i) + str.substring(i + 1); 321 else 322 return str.substring(0, i); 323 } 324 325 /** 326 * Returns the same {@code String} is input, but trims all spaces down to a single space. 327 * Each and every <I>lone / independent or contiguous</I> white-space character is reduced 328 * to a single space-character. 329 * 330 * <TABLE CLASS=JDBriefTable> 331 * <TR><TH>Input String</TH><TH>Output String</TH></TR> 332 * <TR><TD><PRE>{@code "This has extra spaces\n"}</PRE></TD> 333 * <TD>{@code "This has extra spaces "}</TD> 334 * </TR> 335 * <TR><TD>{@code "This does not"}</TD> 336 * <TD>{@code "This does not"}</TD> 337 * </TR> 338 * <TR><TD>{@code "\tThis\nhas\ttabs\nand\tnewlines\n"}</TD> 339 * <TD>{@code " This has tabs and newlines "}</TD> 340 * </TR> 341 * </TABLE> 342 * 343 * @param s Any Java {@code String} 344 * 345 * @return A {@code String} where all white-space is compacted to a single space. This is 346 * generally how HTML works, when it is displayed in a browser. 347 */ 348 public static String removeDuplicateSpaces(String s) 349 { return StringParse.WHITE_SPACE_REGEX.matcher(s).replaceAll(" "); } 350 351 /** 352 * This string-modify method simply removes any and all white-space matches found within a 353 * java-{@code String}. 354 * 355 * <TABLE CLASS=JDBriefTable> 356 * <TR><TH>Input String</TH><TH>Output String</TH></TR> 357 * <TR><TD><PRE>{@code "This Has Extra Spaces\n"}</PRE></TD> 358 * <TD>{@code "ThisHasExtraSpaces"}</TD> 359 * </TR> 360 * <TR><TD>{@code "This Does Not"}</TD> 361 * <TD>{@code "ThisDoesNot"}</TD> 362 * </TR> 363 * <TR><TD>{@code "\tThis\nHas\tTabs\nAnd\tNewlines\n"}</TD> 364 * <TD>{@code "ThisHasTabsAndNewlines"}</TD> 365 * </TR> 366 * </TABLE> 367 * 368 * @param s Any {@code String}, but if it has any white-space (space that matches 369 * regular-expression: {@code \w+}) then those character-blocks will be removed 370 * 371 * @return A new {@code String} without any {@code \w} (RegEx for 'whitespace') 372 * 373 * @see #WHITE_SPACE_REGEX 374 */ 375 public static String removeWhiteSpace(String s) 376 { return WHITE_SPACE_REGEX.matcher(s).replaceAll(""); } 377 378 /** 379 * Generates a {@code String} that contains {@code n} copies of character {@code c}. 380 * @return {@code n} copies of {@code c}, as a {@code String}. 381 * @throws IllegalArgumentException If the value passed to parameter {@code 'n'} is negative 382 * @see StrSource#caretBeneath(String, int) 383 */ 384 public static String nChars(char c, int n) 385 { 386 if (n < 0) throw new IllegalArgumentException("Value of parameter 'n' is negative: " + n); 387 388 char[] cArr = new char[n]; 389 Arrays.fill(cArr, c); 390 return new String(cArr); 391 } 392 393 /** 394 * Generates a {@code String} that contains {@code n} copies of {@code s}. 395 * @return {@code n} copies of {@code s} as a {@code String}. 396 * @throws NException if the value provided to parameter {@code 'n'} is negative. 397 */ 398 public static String nStrings(String s, int n) 399 { 400 if (n < 0) throw new NException("A negative value was passed to 'n' [" + n + ']'); 401 402 StringBuilder sb = new StringBuilder(); 403 404 for (int i=0; i < n; i++) sb.append(s); 405 406 return sb.toString(); 407 } 408 409 /** 410 * This method checks whether or not a java-{@code String} has white-space. 411 * 412 * @param s Any Java-{@code String}. If this {@code String} has any white-space, this method 413 * will return {@code TRUE} 414 * 415 * @return {@code TRUE} If there is any white-space in this method, and {@code FALSE} otherwise. 416 * 417 * @see #WHITE_SPACE_REGEX 418 */ 419 public static boolean hasWhiteSpace(String s) 420 { return WHITE_SPACE_REGEX.matcher(s).find(); } 421 422 /** 423 * Counts the number of instances of character input {@code char c} contained by the 424 * input {@code String s} 425 * 426 * @param s Any {@code String} containing any combination of ASCII/UniCode characters 427 * 428 * @param c Any ASCII/UniCode character. 429 * 430 * @return The number of times {@code char c} occurs in {@code String s} 431 */ 432 public static int countCharacters(String s, char c) 433 { 434 int count = 0; 435 int pos = 0; 436 while ((pos = s.indexOf(c, pos + 1)) != -1) count++; 437 return count; 438 } 439 440 441 /** 442 * If the {@code String} passed to this method contains a single-quote on both sides of the 443 * {@code String}, or if it contains a double-quote on both sides of this {@code String}, then 444 * this method shall return a new {@code String} that is shorter in length by 2, and leaves off 445 * the first and last characters of the input parameter {@code String}. 446 * 447 * <BR /><BR /><B>HOPEFULLY,</B> The name of this method explains clearly what this method does 448 * 449 * @param s This may be any java {@code String}. Only {@code String's} whose first and last 450 * characters are not only quotation marks (single or double), but also they are <B>the same, 451 * identical, quotation marks on each side.</B> 452 * 453 * @return A new {@code String} that whose first and last quotation marks are gone - if they 454 * were there when this method began. 455 */ 456 public static String ifQuotesStripQuotes(String s) 457 { 458 if (s == null) return null; 459 if (s.length() < 2) return s; 460 461 int lenM1 = s.length() - 1; // Position of the last character in the String 462 463 if ( ((s.charAt(0) == '\"') && (s.charAt(lenM1) == '\"')) // String has Double-Quotation-Marks 464 || // ** or *** 465 ((s.charAt(0) == '\'') && (s.charAt(lenM1) == '\'')) ) // String has Single-Quotation-Marks 466 return s.substring(1, lenM1); 467 else 468 return s; 469 } 470 471 /** 472 * Counts the number of lines of text inside of a Java {@code String}. 473 * 474 * @param text This may be any text, as a {@code String}. 475 * 476 * @return Returns the number of lines of text. The integer returned shall be precisely 477 * equal to the number of {@code '\n'} characters <B><I>plus one!</I></B> 478 */ 479 public static int numLines(String text) 480 { 481 if (text.length() == 0) return 0; 482 483 int pos = -1; 484 int count = 0; 485 486 do 487 { 488 pos = text.indexOf('\n', pos + 1); 489 count++; 490 } 491 while (pos != -1); 492 493 return count; 494 } 495 496 497 498 // ******************************************************************************************** 499 // ******************************************************************************************** 500 // Find / Front Last-Front-Slash 501 // ******************************************************************************************** 502 // ******************************************************************************************** 503 504 505 /** 506 * This function finds the position of the last "front-slash" character {@code '/'} in a 507 * java-{@code String} 508 * 509 * @param urlOrDir This is any java-{@code String}, but preferably one that is a 510 * {@code URL}, or directory. 511 * 512 * @return The {@code String}-index of the last 'front-slash' {@code '/'} position in a 513 * {@code String}, or {@code -1} if there are not front-slashes. 514 */ 515 public static int findLastFrontSlashPos(String urlOrDir) 516 { return urlOrDir.lastIndexOf('/'); } 517 518 /** 519 * This returns the contents of a {@code String}, after the last front-slash found. 520 * 521 * <BR /><BR /><B>NOTE:</B> If not front-slash {@code '/'} character is found, then the 522 * original {@code String} is returned. 523 * 524 * @param urlOrDir This is any java-{@code String}, but preferably one that is a 525 * {@code URL}, or directory. 526 * 527 * @return the portion of the {@code String} after the final front-slash {@code '/'} character. 528 * If there are no front-slash characters found in this {@code String}, then the original 529 * {@code String} shall be returned. 530 */ 531 public static String fromLastFrontSlashPos(String urlOrDir) 532 { 533 int pos = urlOrDir.lastIndexOf('/'); 534 if (pos == -1) return urlOrDir; 535 return urlOrDir.substring(pos + 1); 536 } 537 538 /** 539 * This returns the contents of a {@code String}, before the last front-slash found (including 540 * the front-slash {@code '/'} itself). 541 * 542 * <BR /><BR /><B>NOTE:</B> If no front-slash {@code '/'} character is found, then null is 543 * returned. 544 * 545 * @param urlOrDir This is any java-{@code String}, but preferably one that is a 546 * {@code URL}, or directory. 547 * 548 * @return the portion of the {@code String} <I><B>before and including</B></I> the final 549 * front-slash {@code '/'} character. If there are no front-slash characters found in this 550 * {@code String}, then null. 551 */ 552 public static String beforeLastFrontSlashPos(String urlOrDir) 553 { 554 int pos = urlOrDir.lastIndexOf('/'); 555 if (pos == -1) return null; 556 return urlOrDir.substring(0, pos + 1); 557 } 558 559 560 // ******************************************************************************************** 561 // ******************************************************************************************** 562 // Find / From Last-File-Separator 563 // ******************************************************************************************** 564 // ******************************************************************************************** 565 566 567 /** 568 * This function finds the position of the last {@code 'java.io.File.separator'} character in a 569 * java-{@code String}. In UNIX-based systems, this is a forward-slash {@code '/'} character, 570 * but in Windows-MSDOS, this is a back-slash {@code '\'} character. Identifying which of the 571 * two is used is obtained by "using" Java's {@code File.separator} class and field. 572 * 573 * @param fileOrDir This may be any Java-{@code String}, but preferably one that represents a 574 * file or directory. 575 * 576 * @return The {@code String}-index of the last 'file-separator' position in a {@code String}, 577 * or {@code -1} if there are no such file-separators. 578 */ 579 public static int findLastFileSeparatorPos(String fileOrDir) 580 { return fileOrDir.lastIndexOf(File.separator.charAt(0)); } 581 582 /** 583 * This returns the contents of a {@code String}, after the last 584 * {@code 'java.io.File.separator'} found. 585 * 586 * <BR /><BR /><B>NOTE:</B> If no {@code 'java.io.File.separator'} character is found, then 587 * the original {@code String} is returned. 588 * 589 * @param fileOrDir This is any java-{@code String}, but preferably one that is a filename or 590 * directory-name 591 * 592 * @return the portion of the {@code String} after the final {@code 'java.io.File.separator'} 593 * character. If there are no such characters found, then the original {@code String} shall 594 * be returned. 595 */ 596 public static String fromLastFileSeparatorPos(String fileOrDir) 597 { 598 int pos = fileOrDir.lastIndexOf(File.separator.charAt(0)); 599 if (pos == -1) return fileOrDir; 600 return fileOrDir.substring(pos + 1); 601 } 602 603 /** 604 * This returns the contents of a {@code String}, before the last 605 * {@code 'java.io.File.separator'} (including the separator itself). 606 * 607 * <BR /><BR /><B>NOTE:</B> If no {@code 'java.io.File.separator'} character is found, 608 * then null is returned. 609 * 610 * @param urlOrDir This is any java-{@code String}, but preferably one that is a 611 * {@code URL}, or directory. 612 * 613 * @return the portion of the {@code String} <I><B>before and including</B></I> the final 614 * {@code 'java.io.File.separator'} character. If there are no such characters found in this 615 * {@code String}, then null is returned. 616 */ 617 public static String beforeLastFileSeparatorPos(String urlOrDir) 618 { 619 int pos = urlOrDir.lastIndexOf(File.separator.charAt(0)); 620 if (pos == -1) return null; 621 return urlOrDir.substring(0, pos + 1); 622 } 623 624 625 // ******************************************************************************************** 626 // ******************************************************************************************** 627 // Find / From File-Extension 628 // ******************************************************************************************** 629 // ******************************************************************************************** 630 631 632 /** 633 * This method swaps the ending 'File Extension' with another, parameter-provided, extension. 634 * @param fileNameOrURLWithExtension Any file-name (or {@code URL}) that has an extension. 635 * @param newExtension <EMBED CLASS='external-html' DATA-FILE-ID=STRP_SWAP_EXT_NEWEX> 636 * @return The new file-name or {@code URL} having the substituted extension. 637 * @throws StringFormatException 638 */ 639 public static String swapExtension(String fileNameOrURLWithExtension, String newExtension) 640 { 641 final int dotPos = fileNameOrURLWithExtension.lastIndexOf('.'); 642 643 if (dotPos == -1) throw new StringFormatException( 644 "The file-name provided\n[" + fileNameOrURLWithExtension + "]\n" + 645 "does not have a file-extension" 646 ); 647 648 if (newExtension.length() == 0) throw new StringFormatException( 649 "The new file-name extension has length 0. " + 650 " To remove an extension, use 'StringParse.removeFileExtension(fileName)'" 651 ); 652 653 return (newExtension.charAt(0) == '.') 654 ? fileNameOrURLWithExtension.substring(0, dotPos) + newExtension 655 : fileNameOrURLWithExtension.substring(0, dotPos) + '.' + newExtension; 656 } 657 658 /** 659 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_REM_EXT_DESC> 660 * @param fileNameOrURL Any file-name or {@code URL}, as a {@code String}. 661 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_REM_EXT_RET> 662 */ 663 public static String removeExtension(String fileNameOrURL) 664 { 665 final int dotPos = fileNameOrURL.lastIndexOf('.'); 666 667 return (dotPos == -1) 668 ? fileNameOrURL 669 : fileNameOrURL.substring(0, dotPos); 670 } 671 672 /** 673 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FIND_EXT_DESC> 674 * @param file This may be any Java-{@code String}, but preferably one that represents a file. 675 * @param includeDot <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FIND_EXT_INCL> 676 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FIND_EXT_RET> 677 */ 678 public static int findExtension(String file, boolean includeDot) 679 { 680 int pos = file.lastIndexOf('.'); 681 682 if (pos == -1) return -1; 683 else if (includeDot) return pos; 684 else if (++pos < file.length()) return pos; 685 else return -1; 686 } 687 688 /** 689 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FROM_EXT_DESC> 690 * @param file This is any java-{@code String}, but preferably one that is a filename. 691 * 692 * @param includeDot Indicates whether the period {@code '.'} is to be included in the 693 * returned-{@code String}. 694 * 695 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FROM_EXT_RET> 696 */ 697 public static String fromExtension(String file, boolean includeDot) 698 { 699 final int pos = findExtension(file, includeDot); 700 701 return (pos == -1) 702 ? null 703 : file.substring(pos); 704 } 705 706 /** 707 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_BEFORE_EXT_DESC> 708 * @param file This is any java-{@code String}, but preferably one that is a filename. 709 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_BEFORE_EXT_RET> 710 */ 711 public static String beforeExtension(String file) 712 { 713 final int pos = file.lastIndexOf('.'); 714 715 return (pos == -1) 716 ? file 717 : file.substring(0, pos); 718 } 719 720 /** 721 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_BEFORE_EXT_DESC> 722 * @param url A URL as a {@code String} - like {@code http://domain/directory/[file]} 723 * @return substring(0, index of last front-slash ({@code '/'}) in {@code String}) 724 */ 725 public static String findURLRoot(String url) 726 { 727 final int pos = findLastFrontSlashPos(url); 728 729 return (pos == -1) 730 ? null 731 : url.substring(0, pos + 1); 732 } 733 734 /** 735 * String text that is situated before the first white-space character in the string. 736 * @return After breaking the {@code String} by white-space, this returns the first 'chunk' 737 * before the first whitespace. 738 */ 739 public static String firstWord(String s) 740 { 741 final int pos = s.indexOf(" "); 742 743 return (pos == -1) 744 ? s 745 : s.substring(0, pos); 746 } 747 748 749 // ******************************************************************************************** 750 // ******************************************************************************************** 751 // Removing parts of a string 752 // ******************************************************************************************** 753 // ******************************************************************************************** 754 755 756 /** 757 * This function will remove any pairs of Brackets within a {@code String}, and returned the 758 * paired down {@code String} 759 * 760 * @param s <EMBED CLASS='external-html' DATA-FILE-ID=STRP_RMV_BRACKETS_S> 761 * @return The same {@code String}, but with any bracket-pairs removed. 762 */ 763 public static String removeBrackets(String s) { return remove_(s, '[', ']'); } 764 765 /** 766 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_RMV_BRACES_DESC> 767 * @param s <EMBED CLASS='external-html' DATA-FILE-ID=STRP_RMV_BRACES_S> 768 * @return The same {@code String}, but with any curly-brace-pairs removed. 769 */ 770 public static String removeBraces(String s) { return remove_(s, '{', '}'); } 771 772 /** 773 * Removes Parenthesis, similar to other parenthetical removing functions. 774 * @param s <EMBED CLASS='external-html' DATA-FILE-ID=STRP_RMV_PARENS_S> 775 * @return The same {@code String}, but with any parenthesis removed. 776 */ 777 public static String removeParens(String s) { return remove_(s, '(', ')'); } 778 779 /** 780 * Removes all parenthetical notations. Calls all <I><B>remove functions</B></I> 781 * @param s Any valid string 782 * @return The same string, but with all parenthesis, curly-brace & bracket pairs removed. 783 * @see #removeParens(String) 784 * @see #removeBraces(String) 785 * @see #removeBrackets(String) 786 */ 787 public static String removeAllParenthetical(String s) 788 { return removeParens(removeBraces(removeBrackets(s))); } 789 790 private static String remove_(String s, char left, char right) 791 { 792 int p = s.indexOf(left); 793 if (p == -1) return s; 794 795 String ret = s.substring(0, p).trim(); 796 797 for (++p; (s.charAt(p) != right) && (p < s.length()); p++); 798 799 if (p >= (s.length() - 1)) return ret; 800 801 ret += " " + s.substring(p + 1).trim(); 802 803 if (ret.indexOf(left) != -1) return remove_(ret.trim(), left, right); 804 else return ret.trim(); 805 } 806 807 808 809 // ******************************************************************************************** 810 // ******************************************************************************************** 811 // Base-64 Encoded Java Objects 812 // ******************************************************************************************** 813 // ******************************************************************************************** 814 815 816 /** 817 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_OBJ_2_B64_STR_DESC> 818 * @param o Any java {@code java.lang.Object}. This object must be Serializable, or throws. 819 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_OBJ_2_B64_STR_RET> 820 * @see #b64StrToObj(String) 821 */ 822 @LinkJavaSource(handle="B64", name="objToB64Str") 823 public static String objToB64Str(Object o) throws IOException 824 { return B64.objToB64Str(o); } 825 826 /** 827 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_B64_STR_2_OBJ_DESC> 828 * @param str <EMBED CLASS='external-html' DATA-FILE-ID=STRP_B64_STR_2_OBJ_STR> 829 * @return A de-compressed {@code java.lang.Object} converted back from a B64-{@code String} 830 * @see #objToB64Str(Object) 831 */ 832 @LinkJavaSource(handle="B64", name="b64StrToObj") 833 public static Object b64StrToObj(String str) throws IOException 834 { return B64.b64StrToObj(str); } 835 836 /** 837 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_O_2_B64_MSTR_DESC> 838 * @param o <EMBED CLASS='external-html' DATA-FILE-ID=STRP_O_2_B64_MSTR_O> 839 * @return A Base-64 MIME-Encoded {@code String} of any serializable {@code java.lang.Object} 840 * @see #objToB64Str(Object) 841 * @see #b64MimeStrToObj(String) 842 */ 843 @LinkJavaSource(handle="B64", name="objToB64MimeStr") 844 public static String objToB64MimeStr(Object o) throws IOException 845 { return B64.objToB64MimeStr(o); } 846 847 /** 848 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_B64_MSTR_2_O_DESC> 849 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_B64_MSTR_2_O_RET> 850 * @see #b64StrToObj(String) 851 * @see #objToB64MimeStr(Object) 852 */ 853 @LinkJavaSource(handle="B64", name="b64MimeStrToObj") 854 public static Object b64MimeStrToObj(String str) throws IOException 855 { return B64.b64MimeStrToObj(str); } 856 857 858 // ******************************************************************************************** 859 // ******************************************************************************************** 860 // '../' (Parent Directory) 861 // ******************************************************************************************** 862 // ******************************************************************************************** 863 864 865 /** 866 * Computes a "relative {@code URL String}". 867 * @param fileName This is a fileName whose ancestor directory needs to be <I>relative-ized</I> 868 * @param ancestorDirectory This is an ancestor (container) directory. 869 * @param separator The separator character used to separate file-system directory names. 870 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_RET> 871 * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_IAEX> 872 */ 873 @LinkJavaSource(handle="DotDots", name="specifiedAncestor") 874 public static String dotDots(String fileName, String ancestorDirectory, char separator) 875 { return DotDots.specifiedAncestor(fileName, ancestorDirectory, separator); } 876 877 878 /** 879 * <BR>See Docs: Method {@link #dotDotParentDirectory(String, char, short)} 880 * <BR>Converts: Input {@code URL} to a {@code String} - eliminates non-essential 881 * {@code URI}-information (Such as: {@code Query-Strings, and others as well}) 882 * <BR>Passes: Character {@code char '/'}, the separator character used in {@code URL's} 883 * <BR>Passes: A {@code '1'} to parameter {@code 'nLevels'} - only going up one directory 884 */ 885 @IntoHTMLTable(background=BlueDither, title="Rerieve the Parent-Directory of a URL") 886 @LinkJavaSource(handle="DotDots", name="parentDir") 887 public static String dotDotParentDirectory(URL url) 888 { 889 final String urlStr = url.getProtocol() + "://" + url.getHost() + url.getPath(); 890 return DotDots.parentDir(urlStr, '/', (short) 1); 891 } 892 893 894 /** 895 * <BR>See Docs: Method {@link #dotDotParentDirectory(String, char, short)} 896 * <BR>Passes: {@code char '/'}, the separator character used in {@code URL's} 897 * <BR>Passes: {@code '1'} to parameter {@code 'nLevels'} - only going up on directory 898 */ 899 @IntoHTMLTable( 900 background=GreenDither, 901 title="Rerieve the Parent-Directory of a URL as a String" 902 ) 903 @LinkJavaSource(handle="DotDots", name="parentDir") 904 public static String dotDotParentDirectory(String urlAsStr) 905 { return DotDots.parentDir(urlAsStr, '/', (short) 1); } 906 907 908 /** 909 * <BR>See Docs: Method {@link #dotDotParentDirectory(String, char, short)} 910 * <BR>Converts: {@code URL} to {@code String}, eliminates non-essential 911 * {@code URI}-information (such as Query-Strings, etc.) 912 * <BR>Passes: A Separator-Character {@code char '/'} - the separator used in {@code URL's} 913 */ 914 @IntoHTMLTable( 915 background=BlueDither, 916 title="Rerieve the n<SUP>th</SUP> Ancestory-Directory of a URL" 917 ) 918 @LinkJavaSource(handle="DotDots", name="parentDir") 919 public static String dotDotParentDirectory(URL url, short nLevels) 920 { 921 final String urlStr = url.getProtocol() + "://" + url.getHost() + url.getPath(); 922 return DotDots.parentDir(urlStr, '/', nLevels); 923 } 924 925 926 /** 927 * <BR>See Docs: Method {@link #dotDotParentDirectory(String, char, short)} 928 * <BR>Passes: {@code char '/'}, the separator character used in {@code URL's} 929 */ 930 @IntoHTMLTable( 931 background=GreenDither, 932 title="Rerieve the n<SUP>th</SUP> Ancestory-Directory of a URL as a String" 933 ) 934 @LinkJavaSource(handle="DotDots", name="parentDir") 935 public static String dotDotParentDirectory(String urlAsStr, short nLevels) 936 { return DotDots.parentDir(urlAsStr, '/', nLevels); } 937 938 939 /** 940 * <BR>See Docs: Method {@link #dotDotParentDirectory(String, char, short)} 941 * <BR>Passes: {@code '1'} to parameter {@code nLevels} - only going up one directory. 942 */ 943 @IntoHTMLTable( 944 background=BlueDither, 945 title="Rerieve the Parent-Directory from String, use a Specified Separator-Char" 946 ) 947 @LinkJavaSource(handle="DotDots", name="parentDir") 948 public static String dotDotParentDirectory(String directoryStr, char dirSeparator) 949 { return DotDots.parentDir(directoryStr, dirSeparator, (short) 1); } 950 951 952 /** 953 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_DESC> 954 * @param directoryStr <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_DSTR> 955 * @param separator <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_SEP> 956 * @param nLevels <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_NLVL> 957 * @return <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_RET> 958 * 959 * @throws IllegalArgumentException 960 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_DOTDOT_PD_IAEX> 961 */ 962 @LinkJavaSource(handle="DotDots", name="parentDir") 963 public static String dotDotParentDirectory(String directoryStr, char separator, short nLevels) 964 { return DotDots.parentDir(directoryStr, separator, nLevels); } 965 966 967 // ******************************************************************************************** 968 // ******************************************************************************************** 969 // Quick 'isNumber' methods 970 // ******************************************************************************************** 971 // ******************************************************************************************** 972 973 974 /** 975 * <EMBED CLASS='external-html' DATA-FILE-ID=SPA_IS_INTEGER_DESC> 976 * @param s Any java {@code String} 977 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SPA_IS_INTEGER_RET> 978 * @see #isInt(String) 979 */ 980 @LinkJavaSource(handle="IOPT", name="isInteger") 981 public static boolean isInteger(String s) 982 { return IsOfPrimitiveType.isInteger(s); } 983 984 985 /** <BR>Passes: The ASCII characters that comprise {@code Integer.MIN_VALUE} */ 986 @IntoHTMLTable( 987 background=BlueDither, 988 title="Check if a Java-String Comprises a Valid Integer" 989 ) 990 @LinkJavaSource(handle="IOPT", entity=FIELD, name="INT_MIN_VALUE_DIGITS_AS_CHARS") 991 @LinkJavaSource(handle="IOPT", name="check") 992 public static boolean isInt(String s) 993 { return IsOfPrimitiveType.check(s, IsOfPrimitiveType.INT_MIN_VALUE_DIGITS_AS_CHARS); } 994 995 996 /** <BR>Passes: The ASCII characters that comprise {@code Long.MIN_VALUE} */ 997 @IntoHTMLTable( 998 background=GreenDither, 999 title="Check if a Java-String Comprises a Valid Long-Integer" 1000 ) 1001 @LinkJavaSource(handle="IOPT", entity=FIELD, name="LONG_MIN_VALUE_DIGITS_AS_CHARS") 1002 @LinkJavaSource(handle="IOPT", name="check") 1003 public static boolean isLong(String s) 1004 { return IsOfPrimitiveType.check(s, IsOfPrimitiveType.LONG_MIN_VALUE_DIGITS_AS_CHARS); } 1005 1006 1007 /** <BR>Passes: ASCII characters that comprise {@code Byte.MIN_VALUE} */ 1008 @IntoHTMLTable( 1009 background=BlueDither, 1010 title="Check if a Java-String Comprises a Valid Byte" 1011 ) 1012 @LinkJavaSource(handle="IOPT", entity=FIELD, name="BYTE_MIN_VALUE_DIGITS_AS_CHARS") 1013 @LinkJavaSource(handle="IOPT", name="check") 1014 public static boolean isByte(String s) 1015 { return IsOfPrimitiveType.check(s, IsOfPrimitiveType.BYTE_MIN_VALUE_DIGITS_AS_CHARS); } 1016 1017 1018 /** <BR>Passes: ASCII characters that comprise {@code Short.MIN_VALUE} */ 1019 @IntoHTMLTable( 1020 background=GreenDither, 1021 title="Check if a Java-String Comprises a Valid Short-Integer" 1022 ) 1023 @LinkJavaSource(handle="IOPT", entity=FIELD, name="SHORT_MIN_VALUE_DIGITS_AS_CHARS") 1024 @LinkJavaSource(handle="IOPT", name="check") 1025 public static boolean isShort(String s) 1026 { return IsOfPrimitiveType.check(s, IsOfPrimitiveType.SHORT_MIN_VALUE_DIGITS_AS_CHARS); } 1027 1028 1029 /** 1030 * <EMBED CLASS='external-html' DATA-FILE-ID=SPA_IS_PRMTYPE_DESC> 1031 * @param s Any Java <CODE>String</CODE> 1032 * @param minArr <EMBED CLASS='external-html' DATA-FILE-ID=SPA_IS_PRMTYPE_MARR> 1033 * @return <EMBED CLASS='external-html' DATA-FILE-ID=SPA_IS_PRMTYPE_RET> 1034 * @see #isInteger(String) 1035 * @see #isInt(String) 1036 * @see #isByte(String) 1037 * @see #isLong(String) 1038 * @see #isShort(String) 1039 */ 1040 @LinkJavaSource(handle="IOPT", name="check") 1041 protected static boolean isOfPrimitiveType(String s, char[] minArr) 1042 { return IsOfPrimitiveType.check(s, minArr); } 1043 1044 1045 /** 1046 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_FLOAT_PT_REGEX> 1047 * <EMBED CLASS='external-html' DATA-FILE-ID=STRP_D_VALUEOF> 1048 * @see #floatingPointPred 1049 * @see #isDouble(String) 1050 */ 1051 @LinkJavaSource(handle="IOPT", entity=FIELD, name="FLOATING_POINT_REGEX") 1052 public static final Pattern FLOATING_POINT_REGEX = IsOfPrimitiveType.FLOATING_POINT_REGEX; 1053 1054 1055 /** 1056 * This is the floating-point regular-expression, simply converted to a predicate. 1057 * @see #FLOATING_POINT_REGEX 1058 * @see #isDouble(String) 1059 */ 1060 @LinkJavaSource(handle="IOPT", entity=FIELD, name="FLOATING_POINT_REGEX") 1061 public static final Predicate<String> floatingPointPred = 1062 IsOfPrimitiveType.FLOATING_POINT_REGEX.asPredicate(); 1063 1064 1065 /** 1066 * Tests whether an input-{@code String} can be parsed into a {@code double} 1067 * @return <EMBED CLASSS='external-html' DATA-FILE-ID=SPA_IS_DOUBLE_RET> 1068 * @see #FLOATING_POINT_REGEX 1069 * @see #floatingPointPred 1070 */ 1071 @LinkJavaSource(handle="IOPT", entity=FIELD, name="FLOATING_POINT_REGEX") 1072 public static boolean isDouble(String s) 1073 { return floatingPointPred.test(s); } 1074}