001 /** 002 * Copyright (c) 2000-present Liferay, Inc. All rights reserved. 003 * 004 * This library is free software; you can redistribute it and/or modify it under 005 * the terms of the GNU Lesser General Public License as published by the Free 006 * Software Foundation; either version 2.1 of the License, or (at your option) 007 * any later version. 008 * 009 * This library is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 011 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 012 * details. 013 */ 014 015 package com.liferay.portal.kernel.util; 016 017 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader; 018 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader; 019 import com.liferay.portal.kernel.log.Log; 020 import com.liferay.portal.kernel.log.LogFactoryUtil; 021 import com.liferay.portal.kernel.search.highlight.HighlightUtil; 022 import com.liferay.portal.kernel.security.RandomUtil; 023 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.InputStreamReader; 027 028 import java.net.URL; 029 030 import java.util.ArrayList; 031 import java.util.Collection; 032 import java.util.Enumeration; 033 import java.util.List; 034 import java.util.Locale; 035 import java.util.Map; 036 import java.util.Random; 037 import java.util.regex.Pattern; 038 039 /** 040 * The String utility class. 041 * 042 * @author Brian Wing Shun Chan 043 * @author Sandeep Soni 044 * @author Ganesh Ram 045 * @author Shuyang Zhou 046 * @author Hugo Huijser 047 */ 048 public class StringUtil { 049 050 /** 051 * Adds string <code>add</code> to string <code>s</code> resulting in a 052 * comma delimited list of strings, disallowing duplicate strings in the 053 * list. 054 * 055 * <p> 056 * The resulting string ends with a comma even if the original string does 057 * not. 058 * </p> 059 * 060 * @param s the original string, representing a comma delimited list of 061 * strings 062 * @param add the string to add to the original, representing the string to 063 * add to the list 064 * @return a string that represents the original string and the added string 065 * separated by a comma, or <code>null</code> if the string to add 066 * is <code>null</code> 067 */ 068 public static String add(String s, String add) { 069 return add(s, add, StringPool.COMMA); 070 } 071 072 /** 073 * Adds string <code>add</code> to string <code>s</code> that represents a 074 * delimited list of strings, using a specified delimiter and disallowing 075 * duplicate words. 076 * 077 * <p> 078 * The returned string ends with the delimiter even if the original string 079 * does not. 080 * </p> 081 * 082 * @param s the original string, representing a delimited list of strings 083 * @param add the string to add to the original, representing the string to 084 * add to the list 085 * @param delimiter the delimiter used to separate strings in the list 086 * @return a string that represents the original string and the added string 087 * separated by the delimiter, or <code>null</code> if the string to 088 * add or the delimiter string is <code>null</code> 089 */ 090 public static String add(String s, String add, String delimiter) { 091 return add(s, add, delimiter, false); 092 } 093 094 /** 095 * Adds string <code>add</code> to string <code>s</code> that represents a 096 * delimited list of strings, using a specified delimiter and optionally 097 * allowing duplicate words. 098 * 099 * <p> 100 * The returned string ends with the delimiter even if the original string 101 * does not. 102 * </p> 103 * 104 * @param s the original string, representing a delimited list of strings 105 * @param add the string to add to the original, representing the string to 106 * add to the list 107 * @param delimiter the delimiter used to separate strings in the list 108 * @param allowDuplicates whether to allow duplicate strings 109 * @return a string that represents the original string and the added string 110 * separated by the delimiter, or <code>null</code> if the string to 111 * add or the delimiter string is <code>null</code> 112 */ 113 public static String add( 114 String s, String add, String delimiter, boolean allowDuplicates) { 115 116 if ((add == null) || (delimiter == null)) { 117 return null; 118 } 119 120 if (s == null) { 121 s = StringPool.BLANK; 122 } 123 124 if (allowDuplicates || !contains(s, add, delimiter)) { 125 StringBundler sb = new StringBundler(4); 126 127 sb.append(s); 128 129 if (Validator.isNull(s) || s.endsWith(delimiter)) { 130 sb.append(add); 131 sb.append(delimiter); 132 } 133 else { 134 sb.append(delimiter); 135 sb.append(add); 136 sb.append(delimiter); 137 } 138 139 s = sb.toString(); 140 } 141 142 return s; 143 } 144 145 /** 146 * Returns the original string with an appended space followed by the string 147 * value of the suffix surrounded by parentheses. 148 * 149 * <p> 150 * If the original string ends with a numerical parenthetical suffix having 151 * an integer value equal to <code>suffix - 1</code>, then the existing 152 * parenthetical suffix is replaced by the new one. 153 * </p> 154 * 155 * <p> 156 * Examples: 157 * </p> 158 * 159 * <p> 160 * <pre> 161 * <code> 162 * appendParentheticalSuffix("file", 0) returns "file (0)" 163 * appendParentheticalSuffix("file (0)", 0) returns "file (0) (0)" 164 * appendParentheticalSuffix("file (0)", 1) returns "file (1)" 165 * appendParentheticalSuffix("file (0)", 2) returns "file (0) (2)" 166 * </code> 167 * </pre> 168 * </p> 169 * 170 * @param s the original string 171 * @param suffix the suffix to be appended 172 * @return the resultant string whose characters equal those of the original 173 * string, followed by a space, followed by the specified suffix 174 * enclosed in parentheses, or, if the difference between the 175 * provided suffix and the existing suffix is 1, the existing suffix 176 * is incremented by 1 177 */ 178 public static String appendParentheticalSuffix(String s, int suffix) { 179 if (Pattern.matches(".* \\(" + String.valueOf(suffix - 1) + "\\)", s)) { 180 int pos = s.lastIndexOf(" ("); 181 182 s = s.substring(0, pos); 183 } 184 185 return appendParentheticalSuffix(s, String.valueOf(suffix)); 186 } 187 188 /** 189 * Returns the original string with an appended space followed by the suffix 190 * surrounded by parentheses. 191 * 192 * <p> 193 * Example: 194 * </p> 195 * 196 * <p> 197 * <pre> 198 * <code> 199 * appendParentheticalSuffix("Java", "EE") returns "Java (EE)" 200 * </code> 201 * </pre> 202 * </p> 203 * 204 * @param s the original string 205 * @param suffix the suffix to be appended 206 * @return a string that represents the original string, followed by a 207 * space, followed by the suffix enclosed in parentheses 208 */ 209 public static String appendParentheticalSuffix(String s, String suffix) { 210 StringBundler sb = new StringBundler(5); 211 212 sb.append(s); 213 sb.append(StringPool.SPACE); 214 sb.append(StringPool.OPEN_PARENTHESIS); 215 sb.append(suffix); 216 sb.append(StringPool.CLOSE_PARENTHESIS); 217 218 return sb.toString(); 219 } 220 221 /** 222 * Converts an array of bytes to a string representing the bytes in 223 * hexadecimal form. 224 * 225 * @param bytes the array of bytes to be converted 226 * @return the string representing the bytes in hexadecimal form 227 */ 228 public static String bytesToHexString(byte[] bytes) { 229 char[] chars = new char[bytes.length * 2]; 230 231 for (int i = 0; i < bytes.length; i++) { 232 chars[i * 2] = HEX_DIGITS[(bytes[i] & 0xFF) >> 4]; 233 chars[i * 2 + 1] = HEX_DIGITS[bytes[i] & 0x0F]; 234 } 235 236 return new String(chars); 237 } 238 239 /** 240 * Returns <code>true</code> if the string contains the text as one or more 241 * consecutive comma delimited list entries. 242 * 243 * <p> 244 * Examples: 245 * </p> 246 * 247 * <p> 248 * <pre> 249 * <code> 250 * contains("one,two,three", "two") returns true 251 * contains("one,two,three", "thr") returns false 252 * contains("one,two,three", "one,two") returns true 253 * </code> 254 * </pre> 255 * </p> 256 * 257 * @param s the string in which to search 258 * @param text the text to search for in the string 259 * @return <code>true</code> if the string contains the text as one or more 260 * consecutive comma delimited list entries; <code>false</code> 261 * otherwise 262 */ 263 public static boolean contains(String s, String text) { 264 return contains(s, text, StringPool.COMMA); 265 } 266 267 /** 268 * Returns <code>true</code> if the string contains the text as one or more 269 * consecutive delimited list entries. 270 * 271 * <p> 272 * Examples: 273 * </p> 274 * 275 * <p> 276 * <pre> 277 * <code> 278 * contains("three...two...one", "two", "...") returns true 279 * contains("three...two...one", "thr", "...") returns false 280 * contains("three...two...one", "two...one", "...") returns true 281 * </code> 282 * </pre> 283 * </p> 284 * 285 * @param s the string in which to search 286 * @param text the text to search for in the string 287 * @param delimiter the delimiter 288 * @return <code>true</code> if the string contains the text as one or more 289 * consecutive delimited list entries; <code>false</code> otherwise 290 */ 291 public static boolean contains(String s, String text, String delimiter) { 292 if ((s == null) || (text == null) || (delimiter == null)) { 293 return false; 294 } 295 296 if (!s.endsWith(delimiter)) { 297 s = s.concat(delimiter); 298 } 299 300 String dtd = delimiter.concat(text).concat(delimiter); 301 302 int pos = s.indexOf(dtd); 303 304 if (pos == -1) { 305 String td = text.concat(delimiter); 306 307 if (s.startsWith(td)) { 308 return true; 309 } 310 311 return false; 312 } 313 314 return true; 315 } 316 317 /** 318 * Returns <code>true</code> if the string contains the text as one or more 319 * consecutive comma delimited list entries, ignoring case. 320 * 321 * <p> 322 * Examples: 323 * </p> 324 * 325 * <p> 326 * <pre> 327 * <code> 328 * containsIgnoreCase("one,two,three", "Two") returns true 329 * containsIgnoreCase("one,two,three", "thr") returns false 330 * containsIgnoreCase("one,two,three", "one,two") returns true 331 * </code> 332 * </pre> 333 * </p> 334 * 335 * @param s the string in which to search 336 * @param text the text to search for in the string 337 * @return <code>true</code> if the string contains the text as one or more 338 * consecutive comma delimited list entries; <code>false</code> 339 * otherwise 340 */ 341 public static boolean containsIgnoreCase(String s, String text) { 342 return containsIgnoreCase(s, text, StringPool.COMMA); 343 } 344 345 /** 346 * Returns <code>true</code> if the string contains the text as one or more 347 * consecutive delimited list entries, ignoring case. 348 * 349 * <p> 350 * Examples: 351 * </p> 352 * 353 * <p> 354 * <pre> 355 * <code> 356 * containsIgnoreCase("three...two...one", "Two", "...") returns true 357 * containsIgnoreCase("three...two...one", "thr", "...") returns false 358 * containsIgnoreCase("three...two...one", "two...one", "...") returns true 359 * </code> 360 * </pre> 361 * </p> 362 * 363 * @param s the string in which to search 364 * @param text the text to search for in the string 365 * @param delimiter the delimiter 366 * @return <code>true</code> if the string contains the text as one or more 367 * consecutive delimited list entries; <code>false</code> otherwise 368 */ 369 public static boolean containsIgnoreCase( 370 String s, String text, String delimiter) { 371 372 if ((s == null) || (text == null) || (delimiter == null)) { 373 return false; 374 } 375 376 return contains(toLowerCase(s), toLowerCase(text), delimiter); 377 } 378 379 public static int count(String s, char c) { 380 return count(s, 0, s.length(), c); 381 } 382 383 public static int count(String s, int start, int end, char c) { 384 if ((s == null) || s.isEmpty() || ((end - start) < 1)) { 385 return 0; 386 } 387 388 int count = 0; 389 390 int pos = start; 391 392 while ((pos < end) && ((pos = s.indexOf(c, pos)) != -1)) { 393 if (pos < end) { 394 count++; 395 } 396 397 pos++; 398 } 399 400 return count; 401 } 402 403 public static int count(String s, int start, int end, String text) { 404 if ((s == null) || s.isEmpty() || ((end - start) < 1) || 405 (text == null) || text.isEmpty()) { 406 407 return 0; 408 } 409 410 int count = 0; 411 412 int pos = start; 413 414 while ((pos < end) && (pos = s.indexOf(text, pos)) != -1) { 415 if (pos < end) { 416 count++; 417 } 418 419 pos += text.length(); 420 } 421 422 return count; 423 } 424 425 /** 426 * Returns the number of times the text appears in the string. 427 * 428 * @param s the string in which to search 429 * @param text the text to search for in the string 430 * @return the number of times the text appears in the string 431 */ 432 public static int count(String s, String text) { 433 return count(s, 0, s.length(), text); 434 } 435 436 /** 437 * Returns <code>true</code> if the string ends with the specified 438 * character, ignoring case. 439 * 440 * @param s the string in which to search 441 * @param end the character to search for at the end of the string 442 * @return <code>true</code> if the string ends with the specified 443 * character, ignoring case; <code>false</code> otherwise 444 */ 445 public static boolean endsWith(String s, char end) { 446 return endsWith(s, (Character.valueOf(end)).toString()); 447 } 448 449 /** 450 * Returns <code>true</code> if the string ends with the string 451 * <code>end</code>, ignoring case. 452 * 453 * @param s the string in which to search 454 * @param end the string to check for at the end of the string 455 * @return <code>true</code> if the string ends with the string 456 * <code>end</code>, ignoring case; <code>false</code> otherwise 457 */ 458 public static boolean endsWith(String s, String end) { 459 if ((s == null) || (end == null)) { 460 return false; 461 } 462 463 if (end.length() > s.length()) { 464 return false; 465 } 466 467 String temp = s.substring(s.length() - end.length()); 468 469 if (equalsIgnoreCase(temp, end)) { 470 return true; 471 } 472 else { 473 return false; 474 } 475 } 476 477 /** 478 * Returns <code>true</code> if the strings are equal, ignoring new line 479 * characters. 480 * 481 * @param s1 the first string to compare 482 * @param s2 the second string to compare 483 * @return <code>true</code> if the strings are equal, ignoring new line 484 * characters; <code>false</code> otherwise 485 */ 486 public static boolean equalsIgnoreBreakLine(String s1, String s2) { 487 if (s1 == s2) { 488 return true; 489 } 490 491 if ((s1 == null) || (s2 == null)) { 492 return false; 493 } 494 495 s1 = removeChars(s1, CharPool.RETURN, CharPool.NEW_LINE); 496 s2 = removeChars(s2, CharPool.RETURN, CharPool.NEW_LINE); 497 498 if (s1.length() != s2.length()) { 499 return false; 500 } 501 502 return s1.equals(s2); 503 } 504 505 /** 506 * Returns <code>true</code> if the strings are equal, ignoring case. 507 * 508 * @param s1 the first string to compare 509 * @param s2 the second string to compare 510 * @return <code>true</code> if the strings are equal, ignoring case; 511 * <code>false</code> otherwise 512 */ 513 public static boolean equalsIgnoreCase(String s1, String s2) { 514 if (s1 == s2) { 515 return true; 516 } 517 518 if ((s1 == null) || (s2 == null)) { 519 return false; 520 } 521 522 if (s1.length() != s2.length()) { 523 return false; 524 } 525 526 for (int i = 0; i < s1.length(); i++) { 527 char c1 = s1.charAt(i); 528 529 char c2 = s2.charAt(i); 530 531 if (c1 == c2) { 532 continue; 533 } 534 535 // Fast fallback for non-acsii code. 536 537 if ((c1 > 127) || (c2 > 127)) { 538 539 // Georgian alphabet needs to check both upper and lower case 540 541 if ((Character.toLowerCase(c1) == Character.toLowerCase(c2)) || 542 (Character.toUpperCase(c1) == Character.toUpperCase(c2))) { 543 544 continue; 545 } 546 547 return false; 548 } 549 550 // Fast fallback for non-letter ascii code 551 552 if ((c1 < CharPool.UPPER_CASE_A) || (c1 > CharPool.LOWER_CASE_Z) || 553 (c2 < CharPool.UPPER_CASE_A) || (c2 > CharPool.LOWER_CASE_Z)) { 554 555 return false; 556 } 557 558 int delta = c1 - c2; 559 560 if ((delta != 32) && (delta != -32)) { 561 return false; 562 } 563 } 564 565 return true; 566 } 567 568 /** 569 * Returns the substring of each character instance in string <code>s</code> 570 * that is found in the character array <code>chars</code>. The substring of 571 * characters returned maintain their original order. 572 * 573 * @param s the string from which to extract characters 574 * @param chars the characters to extract from the string 575 * @return the substring of each character instance in string <code>s</code> 576 * that is found in the character array <code>chars</code>, or an 577 * empty string if the given string is <code>null</code> 578 */ 579 public static String extract(String s, char[] chars) { 580 if (s == null) { 581 return StringPool.BLANK; 582 } 583 584 StringBundler sb = new StringBundler(); 585 586 for (char c1 : s.toCharArray()) { 587 for (char c2 : chars) { 588 if (c1 == c2) { 589 sb.append(c1); 590 591 break; 592 } 593 } 594 } 595 596 return sb.toString(); 597 } 598 599 /** 600 * Returns the substring of English characters from the string. 601 * 602 * @param s the string from which to extract characters 603 * @return the substring of English characters from the string, or an empty 604 * string if the given string is <code>null</code> 605 */ 606 public static String extractChars(String s) { 607 if (s == null) { 608 return StringPool.BLANK; 609 } 610 611 StringBundler sb = new StringBundler(); 612 613 char[] chars = s.toCharArray(); 614 615 for (char c : chars) { 616 if (Validator.isChar(c)) { 617 sb.append(c); 618 } 619 } 620 621 return sb.toString(); 622 } 623 624 /** 625 * Returns a string consisting of all of the digits extracted from the 626 * string. 627 * 628 * @param s the string from which to extract digits 629 * @return a string consisting of all of the digits extracted from the 630 * string 631 */ 632 public static String extractDigits(String s) { 633 if (s == null) { 634 return StringPool.BLANK; 635 } 636 637 StringBundler sb = new StringBundler(); 638 639 char[] chars = s.toCharArray(); 640 641 for (char c : chars) { 642 if (Validator.isDigit(c)) { 643 sb.append(c); 644 } 645 } 646 647 return sb.toString(); 648 } 649 650 /** 651 * Returns the substring of <code>s</code> up to but not including the first 652 * occurrence of the delimiter. 653 * 654 * @param s the string from which to extract a substring 655 * @param delimiter the character whose index in the string marks where to 656 * end the substring 657 * @return the substring of <code>s</code> up to but not including the first 658 * occurrence of the delimiter, <code>null</code> if the string is 659 * <code>null</code> or the delimiter does not occur in the string 660 */ 661 public static String extractFirst(String s, char delimiter) { 662 if (s == null) { 663 return null; 664 } 665 666 int index = s.indexOf(delimiter); 667 668 if (index < 0) { 669 return null; 670 } 671 else { 672 return s.substring(0, index); 673 } 674 } 675 676 /** 677 * Returns the substring of <code>s</code> up to but not including the first 678 * occurrence of the delimiter. 679 * 680 * @param s the string from which to extract a substring 681 * @param delimiter the smaller string whose index in the larger string 682 * marks where to end the substring 683 * @return the substring of <code>s</code> up to but not including the first 684 * occurrence of the delimiter, <code>null</code> if the string is 685 * <code>null</code> or the delimiter does not occur in the string 686 */ 687 public static String extractFirst(String s, String delimiter) { 688 if (s == null) { 689 return null; 690 } 691 692 int index = s.indexOf(delimiter); 693 694 if (index < 0) { 695 return null; 696 } 697 else { 698 return s.substring(0, index); 699 } 700 } 701 702 /** 703 * Returns the substring of <code>s</code> after but not including the last 704 * occurrence of the delimiter. 705 * 706 * @param s the string from which to extract the substring 707 * @param delimiter the character whose last index in the string marks 708 * where to begin the substring 709 * @return the substring of <code>s</code> after but not including the last 710 * occurrence of the delimiter, <code>null</code> if the string is 711 * <code>null</code> or the delimiter does not occur in the string 712 */ 713 public static String extractLast(String s, char delimiter) { 714 if (s == null) { 715 return null; 716 } 717 718 int index = s.lastIndexOf(delimiter); 719 720 if (index < 0) { 721 return null; 722 } 723 else { 724 return s.substring(index + 1); 725 } 726 } 727 728 /** 729 * Returns the substring of <code>s</code> after but not including the last 730 * occurrence of the delimiter. 731 * 732 * @param s the string from which to extract the substring 733 * @param delimiter the string whose last index in the string marks where 734 * to begin the substring 735 * @return the substring of <code>s</code> after but not including the last 736 * occurrence of the delimiter, <code>null</code> if the string is 737 * <code>null</code> or the delimiter does not occur in the string 738 */ 739 public static String extractLast(String s, String delimiter) { 740 if (s == null) { 741 return null; 742 } 743 744 int index = s.lastIndexOf(delimiter); 745 746 if (index < 0) { 747 return null; 748 } 749 else { 750 return s.substring(index + delimiter.length()); 751 } 752 } 753 754 /** 755 * Returns the substring of all leading digits of string <code>s</code>, or 756 * an empty string if it has no leading digits. 757 * 758 * @param s the string from which to extract the substring 759 * @return the substring of all leading digits of string <code>s</code>, or 760 * an empty string if it has no leading digits 761 */ 762 public static String extractLeadingDigits(String s) { 763 if (s == null) { 764 return StringPool.BLANK; 765 } 766 767 StringBundler sb = new StringBundler(); 768 769 char[] chars = s.toCharArray(); 770 771 for (char c : chars) { 772 if (Validator.isDigit(c)) { 773 sb.append(c); 774 } 775 else { 776 return sb.toString(); 777 } 778 } 779 780 return sb.toString(); 781 } 782 783 /** 784 * @deprecated As of 7.0.0, moved to {@link HighlightUtil#highlight(String, 785 * String[])}} 786 */ 787 @Deprecated 788 public static String highlight(String s, String[] queryTerms) { 789 return HighlightUtil.highlight(s, queryTerms); 790 } 791 792 /** 793 * @deprecated As of 7.0.0, moved to {@link HighlightUtil#highlight(String, 794 * String[], String, String)}} 795 */ 796 @Deprecated 797 public static String highlight( 798 String s, String[] queryTerms, String highlight1, String highlight2) { 799 800 return HighlightUtil.highlight(s, queryTerms, highlight1, highlight2); 801 } 802 803 /** 804 * Returns the index within the string of the first occurrence of any 805 * character from the array. 806 * 807 * <p> 808 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 809 * or empty array returns <code>-1</code>. 810 * </p> 811 * 812 * <p> 813 * Examples: 814 * </p> 815 * 816 * <p> 817 * <pre> 818 * <code> 819 * indexOfAny(null, *) returns -1 820 * indexOfAny(*, null) returns -1 821 * indexOfAny(*, []) returns -1 822 * indexOfAny("zzabyycdxx", ['a','c']) returns 2 823 * indexOfAny("zzabyycdxx", ['c','a']) returns 2 824 * indexOfAny("zzabyycdxx", ['m','n']) returns -1 825 * </code> 826 * </pre> 827 * </p> 828 * 829 * @param s the string to search (optionally <code>null</code>) 830 * @param chars the characters to search for (optionally <code>null</code>) 831 * @return the index within the string of the first occurrence of any 832 * character from the array, or <code>-1</code> if none of the 833 * characters occur 834 */ 835 public static int indexOfAny(String s, char[] chars) { 836 if (s == null) { 837 return -1; 838 } 839 840 return indexOfAny(s, chars, 0, s.length() - 1); 841 } 842 843 /** 844 * Returns the index within the string of the first occurrence of any 845 * character from the array, starting the search at the specified index 846 * within the string. 847 * 848 * <p> 849 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 850 * or empty array returns <code>-1</code>. 851 * </p> 852 * 853 * <p> 854 * Examples: 855 * </p> 856 * 857 * <p> 858 * <pre> 859 * <code> 860 * indexOfAny(null, *, *) returns -1 861 * indexOfAny(*, null, *) returns -1 862 * indexOfAny(*, [], *) returns -1 863 * indexOfAny("zzabyycdxx", ['a','c'], 3) returns 6 864 * </code> 865 * </pre> 866 * </p> 867 * 868 * @param s the string to search (optionally <code>null</code>) 869 * @param chars the characters to search for (optionally <code>null</code>) 870 * @param fromIndex the start index within the string 871 * @return the index within the string of the first occurrence of any 872 * character from the array, starting the search at the specified 873 * index within the string, or <code>-1</code> if none of the 874 * characters occur 875 */ 876 public static int indexOfAny(String s, char[] chars, int fromIndex) { 877 if (s == null) { 878 return -1; 879 } 880 881 return indexOfAny(s, chars, fromIndex, s.length() - 1); 882 } 883 884 /** 885 * Returns the index within the string of the first occurrence of any 886 * character from the array, up to and including the specified end index 887 * within the string, starting the search at the specified start index 888 * within the string. 889 * 890 * <p> 891 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 892 * or empty array returns <code>-1</code>. 893 * </p> 894 * 895 * <p> 896 * Examples: 897 * </p> 898 * 899 * <p> 900 * <pre> 901 * <code> 902 * indexOfAny(null, *, *, *) returns -1 903 * indexOfAny(*, null, *, *) returns -1 904 * indexOfAny(*, [], *, *) returns -1 905 * indexOfAny("zzabyycdxx", ['a','c'], 3, 7) returns 6 906 * </code> 907 * </pre> 908 * </p> 909 * 910 * @param s the string to search (optionally <code>null</code>) 911 * @param chars the characters to search for (optionally <code>null</code>) 912 * @param fromIndex the start index within the string 913 * @param toIndex the end index within the string 914 * @return the index within the string of the first occurrence of any 915 * character from the array, up to and including the specified end 916 * index within the string, starting the search at the specified 917 * start index within the string, or <code>-1</code> if none of the 918 * characters occur 919 */ 920 public static int indexOfAny( 921 String s, char[] chars, int fromIndex, int toIndex) { 922 923 if ((s == null) || (toIndex < fromIndex)) { 924 return -1; 925 } 926 927 if (ArrayUtil.isEmpty(chars)) { 928 return -1; 929 } 930 931 if (fromIndex >= s.length()) { 932 return -1; 933 } 934 935 if (fromIndex < 0) { 936 fromIndex = 0; 937 } 938 939 if (toIndex >= s.length()) { 940 toIndex = s.length() - 1; 941 } 942 943 for (int i = fromIndex; i <= toIndex; i++) { 944 char c = s.charAt(i); 945 946 for (int j = 0; j < chars.length; j++) { 947 if (c == chars[j]) { 948 return i; 949 } 950 } 951 } 952 953 return -1; 954 } 955 956 /** 957 * Returns the index within the string of the first occurrence of any string 958 * from the array. 959 * 960 * <p> 961 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 962 * or empty array returns <code>-1</code>, but an array containing 963 * <code>""</code> returns <code>0</code> if the string is not 964 * <code>null</code>. 965 * </p> 966 * 967 * <p> 968 * Examples: 969 * </p> 970 * 971 * <p> 972 * <pre> 973 * <code> 974 * indexOfAny(null, *) returns -1 975 * indexOfAny(*, null) returns -1 976 * indexOfAny(*, [null]) returns -1 977 * indexOfAny(*, []) returns -1 978 * indexOfAny("zzabyycdxx", ["ab","cd"]) returns 2 979 * indexOfAny("zzabyycdxx", ["cd","ab"]) returns 2 980 * indexOfAny("zzabyycdxx", ["mn","op"]) returns -1 981 * indexOfAny("zzabyycdxx", ["mn",""]) returns 0 982 * </code> 983 * </pre> 984 * </p> 985 * 986 * @param s the string (optionally <code>null</code>) 987 * @param texts the strings to search for (optionally <code>null</code>) 988 * @return the index within the string of the first occurrence of any string 989 * from the array, <code>0</code> if the search array contains 990 * <code>""</code>, or <code>-1</code> if none of the strings occur 991 */ 992 public static int indexOfAny(String s, String[] texts) { 993 if (s == null) { 994 return -1; 995 } 996 997 return indexOfAny(s, texts, 0, s.length() - 1); 998 } 999 1000 /** 1001 * Returns the index within the string of the first occurrence of any string 1002 * from the array, starting the search at the specified index within the 1003 * string. 1004 * 1005 * <p> 1006 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1007 * or empty array returns <code>-1</code>, but an array containing 1008 * <code>""</code> returns the specified start index if the string is not 1009 * <code>null</code>. 1010 * </p> 1011 * 1012 * <p> 1013 * Examples: 1014 * </p> 1015 * 1016 * <p> 1017 * <pre> 1018 * <code> 1019 * indexOfAny(null, *, *) returns -1 1020 * indexOfAny(*, null, *) returns -1 1021 * indexOfAny(*, [null], *) returns -1 1022 * indexOfAny(*, [], *) returns -1 1023 * indexOfAny("zzabyycdxx", ["ab","cd"], 3) returns 6 1024 * indexOfAny("zzabyycdxx", ["cd","ab"], 3) returns 6 1025 * indexOfAny("zzabyycdxx", ["mn","op"], *) returns -1 1026 * indexOfAny("zzabyycdxx", ["mn",""], 3) returns 3 1027 * </code> 1028 * </pre> 1029 * </p> 1030 * 1031 * @param s the string to search (optionally <code>null</code>) 1032 * @param texts the strings to search for (optionally <code>null</code>) 1033 * @param fromIndex the start index within the string 1034 * @return the index within the string of the first occurrence of any string 1035 * from the array, starting the search at the specified index within 1036 * the string, the start index if the search array contains 1037 * <code>""</code>, or <code>-1</code> if none of the strings occur 1038 */ 1039 public static int indexOfAny(String s, String[] texts, int fromIndex) { 1040 if (s == null) { 1041 return -1; 1042 } 1043 1044 return indexOfAny(s, texts, fromIndex, s.length() - 1); 1045 } 1046 1047 /** 1048 * Returns the index within the string of the first occurrence of any string 1049 * from the array, up to and including the specified end index within the 1050 * string, starting the search at the specified start index within the 1051 * string. 1052 * 1053 * <p> 1054 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1055 * or empty array returns <code>-1</code>, but an array containing 1056 * <code>""</code> returns the specified start index if the string is not 1057 * <code>null</code>. 1058 * </p> 1059 * 1060 * <p> 1061 * Examples: 1062 * </p> 1063 * 1064 * <p> 1065 * <pre> 1066 * <code> 1067 * indexOfAny(null, *, *, *) returns -1 1068 * indexOfAny(*, null, *, *) returns -1 1069 * indexOfAny(*, [null], *, *) returns -1 1070 * indexOfAny(*, [], *, *) returns -1 1071 * indexOfAny("zzabyycdxx", ["ab","cd"], 3, 7) returns 6 1072 * indexOfAny("zzabyycdxx", ["cd","ab"], 2, 7) returns 2 1073 * indexOfAny("zzabyycdxx", ["mn","op"], *, *) returns -1 1074 * indexOfAny("zzabyycdxx", ["mn",""], 3, *) returns 3 1075 * </code> 1076 * </pre> 1077 * </p> 1078 * 1079 * @param s the string to search (optionally <code>null</code>) 1080 * @param texts the strings to search for (optionally <code>null</code>) 1081 * @param fromIndex the start index within the string 1082 * @param toIndex the end index within the string 1083 * @return the index within the string of the first occurrence of any string 1084 * from the array, up to and including the specified end index 1085 * within the string, starting the search at the specified start 1086 * index within the string, the start index if the search array 1087 * contains <code>""</code>, or <code>-1</code> if none of the 1088 * strings occur 1089 */ 1090 public static int indexOfAny( 1091 String s, String[] texts, int fromIndex, int toIndex) { 1092 1093 if ((s == null) || (toIndex < fromIndex)) { 1094 return -1; 1095 } 1096 1097 if (ArrayUtil.isEmpty(texts)) { 1098 return -1; 1099 } 1100 1101 if (fromIndex >= s.length()) { 1102 return -1; 1103 } 1104 1105 if (fromIndex < 0) { 1106 fromIndex = 0; 1107 } 1108 1109 if (toIndex >= s.length()) { 1110 toIndex = s.length() - 1; 1111 } 1112 1113 for (int i = fromIndex; i <= toIndex; i++) { 1114 for (int j = 0; j < texts.length; j++) { 1115 if (texts[j] == null) { 1116 continue; 1117 } 1118 1119 if ((i + texts[j].length() <= toIndex + 1) && 1120 s.startsWith(texts[j], i)) { 1121 1122 return i; 1123 } 1124 } 1125 } 1126 1127 return -1; 1128 } 1129 1130 /** 1131 * Inserts one string into the other at the specified offset index. 1132 * 1133 * @param s the original string 1134 * @param insert the string to be inserted into the original string 1135 * @param offset the index of the original string where the insertion 1136 * should take place 1137 * @return a string representing the original string with the other string 1138 * inserted at the specified offset index, or <code>null</code> if 1139 * the original string is <code>null</code> 1140 */ 1141 public static String insert(String s, String insert, int offset) { 1142 if (s == null) { 1143 return null; 1144 } 1145 1146 if (insert == null) { 1147 return s; 1148 } 1149 1150 if (offset > s.length()) { 1151 return s.concat(insert); 1152 } 1153 1154 String prefix = s.substring(0, offset); 1155 String postfix = s.substring(offset); 1156 1157 return prefix.concat(insert).concat(postfix); 1158 } 1159 1160 /** 1161 * Returns <code>true</code> if all the characters in string <code>s</code> 1162 * are lower case, ignoring any non-alphabetic characters. 1163 * 1164 * @param s the string in which to search 1165 * @return <code>true</code> if all the characters in string <code>s</code> 1166 * are lower case, ignoring any non-alphabetic characters; 1167 * <code>false</code> otherwise 1168 */ 1169 public static boolean isLowerCase(String s) { 1170 if (s == null) { 1171 return false; 1172 } 1173 1174 for (int i = 0; i < s.length(); i++) { 1175 char c = s.charAt(i); 1176 1177 // Fast path for ascii code, fallback to the slow unicode detection 1178 1179 if (c <= 127) { 1180 if ((c >= CharPool.UPPER_CASE_A) && 1181 (c <= CharPool.UPPER_CASE_Z)) { 1182 1183 return false; 1184 } 1185 1186 continue; 1187 } 1188 1189 if (Character.isLetter(c) && Character.isUpperCase(c)) { 1190 return false; 1191 } 1192 } 1193 1194 return true; 1195 } 1196 1197 /** 1198 * Returns <code>true</code> if all the characters in string <code>s</code> 1199 * are upper case, ignoring any non-alphabetic characters. 1200 * 1201 * @param s the string in which to search 1202 * @return <code>true</code> if all the characters in string <code>s</code> 1203 * are upper case, ignoring any non-alphabetic characters; 1204 * <code>false</code> otherwise 1205 */ 1206 public static boolean isUpperCase(String s) { 1207 if (s == null) { 1208 return false; 1209 } 1210 1211 for (int i = 0; i < s.length(); i++) { 1212 char c = s.charAt(i); 1213 1214 // Fast path for ascii code, fallback to the slow unicode detection 1215 1216 if (c <= 127) { 1217 if ((c >= CharPool.LOWER_CASE_A) && 1218 (c <= CharPool.LOWER_CASE_Z)) { 1219 1220 return false; 1221 } 1222 1223 continue; 1224 } 1225 1226 if (Character.isLetter(c) && Character.isLowerCase(c)) { 1227 return false; 1228 } 1229 } 1230 1231 return true; 1232 } 1233 1234 /** 1235 * Returns the index within the string of the last occurrence of any 1236 * character from the array. 1237 * 1238 * <p> 1239 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1240 * or empty array returns <code>-1</code>. 1241 * </p> 1242 * 1243 * <p> 1244 * Examples: 1245 * </p> 1246 * 1247 * <p> 1248 * <pre> 1249 * <code> 1250 * lastIndexOfAny(null, *) returns -1 1251 * lastIndexOfAny(*, null) returns -1 1252 * lastIndexOfAny(*, []) returns -1 1253 * lastIndexOfAny("zzabyycdxx", ['a','c']) returns 6 1254 * lastIndexOfAny("zzabyycdxx", ['c','a']) returns 6 1255 * lastIndexOfAny("zzabyycdxx", ['m','n']) returns -1 1256 * </code> 1257 * </pre> 1258 * </p> 1259 * 1260 * @param s the string to search (optionally <code>null</code>) 1261 * @param chars the characters to search for (optionally <code>null</code>) 1262 * @return the index within the string of the last occurrence of any 1263 * character from the array, or <code>-1</code> if none of the 1264 * characters occur 1265 */ 1266 public static int lastIndexOfAny(String s, char[] chars) { 1267 if (s == null) { 1268 return -1; 1269 } 1270 1271 return lastIndexOfAny(s, chars, 0, s.length() - 1); 1272 } 1273 1274 /** 1275 * Returns the index within the string of the last occurrence of any 1276 * character from the array, starting the search at the specified index 1277 * within the string. 1278 * 1279 * <p> 1280 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1281 * or empty array returns <code>-1</code>. 1282 * </p> 1283 * 1284 * <p> 1285 * Examples: 1286 * </p> 1287 * 1288 * <p> 1289 * <pre> 1290 * <code> 1291 * lastIndexOfAny(null, *, *) returns -1 1292 * lastIndexOfAny(*, null, *) returns -1 1293 * lastIndexOfAny(*, [], *) returns -1 1294 * lastIndexOfAny("zzabyycdxx", ['a','c'], 5) returns 2 1295 * lastIndexOfAny("zzabyycdxx", ['m','n'], *) returns -1 1296 * </code> 1297 * </pre> 1298 * </p> 1299 * 1300 * @param s the string to search (optionally <code>null</code>) 1301 * @param chars the characters to search for (optionally <code>null</code>) 1302 * @param toIndex the end index within the string 1303 * @return the index within the string of the last occurrence of any 1304 * character from the array, starting the search at the specified 1305 * index within the string, or <code>-1</code> if none of the 1306 * characters occur 1307 */ 1308 public static int lastIndexOfAny(String s, char[] chars, int toIndex) { 1309 if (s == null) { 1310 return -1; 1311 } 1312 1313 return lastIndexOfAny(s, chars, 0, toIndex); 1314 } 1315 1316 /** 1317 * Returns the index within the string of the last occurrence of any 1318 * character from the array, up to and including the specified end index 1319 * within the string, starting the search at the specified start index 1320 * within the string. 1321 * 1322 * <p> 1323 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1324 * or empty array returns <code>-1</code>. 1325 * </p> 1326 * 1327 * <p> 1328 * Examples: 1329 * </p> 1330 * 1331 * <p> 1332 * <pre> 1333 * <code> 1334 * lastIndexOfAny(null</code>, *, *, *) returns -1 1335 * lastIndexOfAny(*, null</code>, *, *) returns -1 1336 * lastIndexOfAny(*, [], *, *) returns -1 1337 * lastIndexOfAny("zzabyycdxx", ['a','c'], 5, 7) returns 6 1338 * lastIndexOfAny("zzabyycdxx", ['m','n'], *, *) returns -1 1339 * </code> 1340 * </pre> 1341 * </p> 1342 * 1343 * @param s the string to search (optionally <code>null</code>) 1344 * @param chars the characters to search for (optionally <code>null</code>) 1345 * @param fromIndex the start index within the string 1346 * @param toIndex the end index within the string 1347 * @return the index within the string of the last occurrence of any 1348 * character from the array, up to and including the specified end 1349 * index within the string, starting the search at the specified 1350 * start index within the string, or <code>-1</code> if none of the 1351 * characters occur 1352 */ 1353 public static int lastIndexOfAny( 1354 String s, char[] chars, int fromIndex, int toIndex) { 1355 1356 if ((s == null) || (toIndex < fromIndex)) { 1357 return -1; 1358 } 1359 1360 if (ArrayUtil.isEmpty(chars)) { 1361 return -1; 1362 } 1363 1364 if (fromIndex >= s.length()) { 1365 return -1; 1366 } 1367 1368 if (fromIndex < 0) { 1369 fromIndex = 0; 1370 } 1371 1372 if (toIndex >= s.length()) { 1373 toIndex = s.length() - 1; 1374 } 1375 1376 for (int i = toIndex; i >= fromIndex; i--) { 1377 char c = s.charAt(i); 1378 1379 for (int j = 0; j < chars.length; j++) { 1380 if (c == chars[j]) { 1381 return i; 1382 } 1383 } 1384 } 1385 1386 return -1; 1387 } 1388 1389 /** 1390 * Returns the index within the string of the last occurrence of any string 1391 * from the array. 1392 * 1393 * <p> 1394 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1395 * or empty array returns <code>-1</code>, but an array containing 1396 * <code>""</code> returns <code>0</code> if the string is not 1397 * <code>null</code>. 1398 * </p> 1399 * 1400 * <p> 1401 * Examples: 1402 * </p> 1403 * 1404 * <p> 1405 * <pre> 1406 * <code> 1407 * lastIndexOfAny(null</code>, *) returns -1 1408 * lastIndexOfAny(*, null</code>) returns -1 1409 * lastIndexOfAny(*, []) returns -1 1410 * lastIndexOfAny(*, [null</code>]) returns -1 1411 * lastIndexOfAny("zzabyycdxx", ["ab","cd"]) returns 6 1412 * lastIndexOfAny("zzabyycdxx", ["cd","ab"]) returns 6 1413 * lastIndexOfAny("zzabyycdxx", ["mn","op"]) returns -1 1414 * lastIndexOfAny("zzabyycdxx", ["mn",""]) returns 10 1415 * </code> 1416 * </pre> 1417 * </p> 1418 * 1419 * @param s the string to search (optionally <code>null</code>) 1420 * @param texts the strings to search for (optionally <code>null</code>) 1421 * @return the index within the string of the last occurrence of any string 1422 * from the array, <code>0</code> if the search array contains 1423 * <code>""</code>, or <code>-1</code> if none of the strings occur 1424 */ 1425 public static int lastIndexOfAny(String s, String[] texts) { 1426 if (s == null) { 1427 return -1; 1428 } 1429 1430 return lastIndexOfAny(s, texts, 0, s.length() - 1); 1431 } 1432 1433 /** 1434 * Returns the index within the string of the last occurrence of any string 1435 * from the array, starting the search at the specified index within the 1436 * string. 1437 * 1438 * <p> 1439 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1440 * or empty array returns <code>-1</code>, but an array containing 1441 * <code>""</code> returns the specified start index if the string is not 1442 * <code>null</code>. 1443 * </p> 1444 * 1445 * <p> 1446 * Examples: 1447 * </p> 1448 * 1449 * <p> 1450 * <pre> 1451 * <code> 1452 * lastIndexOfAny(null, *, *) returns -1 1453 * lastIndexOfAny(*, null, *) returns -1 1454 * lastIndexOfAny(*, [], *) returns -1 1455 * lastIndexOfAny(*, [null], *) returns -1 1456 * lastIndexOfAny("zzabyycdxx", ["ab","cd"], 5) returns 2 1457 * lastIndexOfAny("zzabyycdxx", ["cd","ab"], 5) returns 2 1458 * lastIndexOfAny("zzabyycdxx", ["mn","op"], *) returns -1 1459 * lastIndexOfAny("zzabyycdxx", ["mn",""], 5) returns 5 1460 * </code> 1461 * </pre> 1462 * </p> 1463 * 1464 * @param s the string to search (optionally <code>null</code>) 1465 * @param texts the strings to search for (optionally <code>null</code>) 1466 * @param toIndex the end index within the string 1467 * @return the index within the string of the last occurrence of any string 1468 * from the array, starting the search at the specified index within 1469 * the string, the start index if the search array contains 1470 * <code>""</code>, or <code>-1</code> if none of the strings occur 1471 */ 1472 public static int lastIndexOfAny(String s, String[] texts, int toIndex) { 1473 if (s == null) { 1474 return -1; 1475 } 1476 1477 return lastIndexOfAny(s, texts, 0, toIndex); 1478 } 1479 1480 /** 1481 * Returns the index within the string of the last occurrence of any string 1482 * from the array, up to and including the specified end index within the 1483 * string, starting the search at the specified start index within the 1484 * string. 1485 * 1486 * <p> 1487 * A <code>null</code> string returns <code>-1</code>. A <code>null</code> 1488 * or empty array returns <code>-1</code>, but an array containing 1489 * <code>""</code> returns the specified end index if the string is not 1490 * <code>null</code>. 1491 * </p> 1492 * 1493 * <p> 1494 * Examples: 1495 * </p> 1496 * 1497 * <p> 1498 * <pre> 1499 * <code> 1500 * lastIndexOfAny(null, *, *, *) returns -1 1501 * lastIndexOfAny(*, null, *, *) returns -1 1502 * lastIndexOfAny(*, [], *, *) returns -1 1503 * lastIndexOfAny(*, [null], *, *) returns -1 1504 * lastIndexOfAny("zzabyycdxx", ["ab","cd"], 2, 5) returns 2 1505 * lastIndexOfAny("zzabyycdxx", ["mn","op"], *, *) returns -1 1506 * lastIndexOfAny("zzabyycdxx", ["mn",""], 2, 5) returns 5 1507 * </code> 1508 * </pre> 1509 * </p> 1510 * 1511 * @param s the string to search (optionally <code>null</code>) 1512 * @param texts the strings to search for (optionally <code>null</code>) 1513 * @param fromIndex the start index within the string 1514 * @param toIndex the end index within the string 1515 * @return the index within the string of the last occurrence of any string 1516 * from the array, up to and including the specified end index 1517 * within the string, starting the search at the specified start 1518 * index within the string, the end index if the search array 1519 * contains <code>""</code>, or <code>-1</code> if none of the 1520 * strings occur 1521 */ 1522 public static int lastIndexOfAny( 1523 String s, String[] texts, int fromIndex, int toIndex) { 1524 1525 if ((s == null) || (toIndex < fromIndex)) { 1526 return -1; 1527 } 1528 1529 if (ArrayUtil.isEmpty(texts)) { 1530 return -1; 1531 } 1532 1533 if (fromIndex >= s.length()) { 1534 return -1; 1535 } 1536 1537 if (fromIndex < 0) { 1538 fromIndex = 0; 1539 } 1540 1541 if (toIndex >= s.length()) { 1542 toIndex = s.length() - 1; 1543 } 1544 1545 for (int i = toIndex; i >= fromIndex; i--) { 1546 for (int j = 0; j < texts.length; j++) { 1547 if (texts[j] == null) { 1548 continue; 1549 } 1550 1551 if ((i + texts[j].length() <= toIndex + 1) && 1552 s.startsWith(texts[j], i)) { 1553 1554 return i; 1555 } 1556 } 1557 } 1558 1559 return -1; 1560 } 1561 1562 /** 1563 * Converts all of the characters in the string to lower case. 1564 * 1565 * @param s the string to convert 1566 * @return the string, converted to lower case, or <code>null</code> if the 1567 * string is <code>null</code> 1568 * @see String#toLowerCase() 1569 */ 1570 public static String lowerCase(String s) { 1571 return toLowerCase(s); 1572 } 1573 1574 /** 1575 * Converts all of the characters in the arbitrary number of strings to 1576 * lower case. 1577 * 1578 * @param array the array or sequence of string arguments 1579 */ 1580 public static void lowerCase(String... array) { 1581 if (array != null) { 1582 for (int i = 0; i < array.length; i++) { 1583 array[i] = toLowerCase(array[i]); 1584 } 1585 } 1586 } 1587 1588 /** 1589 * Converts the first character of the string to lower case. 1590 * 1591 * @param s the string whose first character is to be converted 1592 * @return the string, with its first character converted to lower-case 1593 */ 1594 public static String lowerCaseFirstLetter(String s) { 1595 char[] chars = s.toCharArray(); 1596 1597 if ((chars[0] >= 65) && (chars[0] <= 90)) { 1598 chars[0] = (char)(chars[0] + 32); 1599 } 1600 1601 return new String(chars); 1602 } 1603 1604 /** 1605 * Returns <code>true</code> if the specified pattern occurs at any position 1606 * in the string. 1607 * 1608 * @param s the string 1609 * @param pattern the pattern to search for in the string 1610 * @return <code>true</code> if the specified pattern occurs at any position 1611 * in the string 1612 */ 1613 public static boolean matches(String s, String pattern) { 1614 String[] array = pattern.split("\\*"); 1615 1616 for (String element : array) { 1617 int pos = s.indexOf(element); 1618 1619 if (pos == -1) { 1620 return false; 1621 } 1622 1623 s = s.substring(pos + element.length()); 1624 } 1625 1626 return true; 1627 } 1628 1629 /** 1630 * Returns <code>true</code> if the specified pattern occurs at any position 1631 * in the string, ignoring case. 1632 * 1633 * @param s the string 1634 * @param pattern the pattern to search for in the string 1635 * @return <code>true</code> if the specified pattern occurs at any position 1636 * in the string 1637 */ 1638 public static boolean matchesIgnoreCase(String s, String pattern) { 1639 return matches(lowerCase(s), lowerCase(pattern)); 1640 } 1641 1642 /** 1643 * Merges the elements of the boolean array into a string representing a 1644 * comma delimited list of its values. 1645 * 1646 * @param array the boolean values to merge 1647 * @return a string representing a comma delimited list of the values of the 1648 * boolean array, an empty string if the array is empty, or 1649 * <code>null</code> if the array is <code>null</code> 1650 */ 1651 public static String merge(boolean[] array) { 1652 return merge(array, StringPool.COMMA); 1653 } 1654 1655 /** 1656 * Merges the elements of the boolean array into a string representing a 1657 * delimited list of its values. 1658 * 1659 * @param array the boolean values to merge 1660 * @param delimiter the delimiter 1661 * @return a string representing a comma delimited list of the values of the 1662 * boolean array, an empty string if the array is empty, or 1663 * <code>null</code> if the array is <code>null</code> 1664 */ 1665 public static String merge(boolean[] array, String delimiter) { 1666 if (array == null) { 1667 return null; 1668 } 1669 1670 if (array.length == 0) { 1671 return StringPool.BLANK; 1672 } 1673 1674 StringBundler sb = new StringBundler(2 * array.length - 1); 1675 1676 for (int i = 0; i < array.length; i++) { 1677 if (i != 0) { 1678 sb.append(delimiter); 1679 } 1680 1681 sb.append(String.valueOf(array[i])); 1682 } 1683 1684 return sb.toString(); 1685 } 1686 1687 /** 1688 * Merges the elements of the character array into a string representing a 1689 * comma delimited list of its values. 1690 * 1691 * @param array the characters to merge 1692 * @return a string representing a comma delimited list of the values of the 1693 * character array, an empty string if the array is empty, or 1694 * <code>null</code> if the array is <code>null</code> 1695 */ 1696 public static String merge(char[] array) { 1697 return merge(array, StringPool.COMMA); 1698 } 1699 1700 /** 1701 * Merges the elements of the character array into a string representing a 1702 * delimited list of its values. 1703 * 1704 * @param array the characters to merge 1705 * @param delimiter the delimiter 1706 * @return a string representing a delimited list of the values of the 1707 * character array, an empty string if the array is empty, or 1708 * <code>null</code> if the array is <code>null</code> 1709 */ 1710 public static String merge(char[] array, String delimiter) { 1711 if (array == null) { 1712 return null; 1713 } 1714 1715 if (array.length == 0) { 1716 return StringPool.BLANK; 1717 } 1718 1719 StringBundler sb = new StringBundler(2 * array.length - 1); 1720 1721 for (int i = 0; i < array.length; i++) { 1722 if (i != 0) { 1723 sb.append(delimiter); 1724 } 1725 1726 sb.append(String.valueOf(array[i])); 1727 } 1728 1729 return sb.toString(); 1730 } 1731 1732 /** 1733 * Merges the elements of the collection by returning a string representing 1734 * a comma delimited list of its values. 1735 * 1736 * @param col the collection of objects 1737 * @return the merged collection elements, or <code>null</code> if the 1738 * collection is <code>null</code> 1739 */ 1740 public static String merge(Collection<?> col) { 1741 return merge(col, StringPool.COMMA); 1742 } 1743 1744 /** 1745 * Merges the elements of the collection by returning a string representing 1746 * a delimited list of its values. 1747 * 1748 * @param col the collection of objects 1749 * @param delimiter the string whose last index in the string marks where 1750 * to begin the substring 1751 * @return the merged collection elements, or <code>null</code> if the 1752 * collection is <code>null</code> 1753 */ 1754 public static String merge(Collection<?> col, String delimiter) { 1755 if (col == null) { 1756 return null; 1757 } 1758 1759 return merge(col.toArray(new Object[col.size()]), delimiter); 1760 } 1761 1762 /** 1763 * Merges the elements of an array of double-precision decimal numbers by 1764 * returning a string representing a comma delimited list of its values. 1765 * 1766 * @param array the doubles to merge 1767 * @return a string representing a comma delimited list of the values of the 1768 * array of double-precision decimal numbers, an empty string if the 1769 * array is empty, or <code>null</code> if the array is 1770 * <code>null</code> 1771 */ 1772 public static String merge(double[] array) { 1773 return merge(array, StringPool.COMMA); 1774 } 1775 1776 /** 1777 * Merges the elements of an array of double-precision decimal numbers by 1778 * returning a string representing a delimited list of its values. 1779 * 1780 * @param array the doubles to merge 1781 * @param delimiter the delimiter 1782 * @return a string representing a delimited list of the values of the array 1783 * of double-precision decimal numbers, an empty string if the array 1784 * is empty, or <code>null</code> if the array is <code>null</code> 1785 */ 1786 public static String merge(double[] array, String delimiter) { 1787 if (array == null) { 1788 return null; 1789 } 1790 1791 if (array.length == 0) { 1792 return StringPool.BLANK; 1793 } 1794 1795 StringBundler sb = new StringBundler(2 * array.length - 1); 1796 1797 for (int i = 0; i < array.length; i++) { 1798 if (i != 0) { 1799 sb.append(delimiter); 1800 } 1801 1802 sb.append(String.valueOf(array[i])); 1803 } 1804 1805 return sb.toString(); 1806 } 1807 1808 /** 1809 * Merges the elements of an array of decimal numbers into a string 1810 * representing a comma delimited list of its values. 1811 * 1812 * @param array the floats to merge 1813 * @return a string representing a comma delimited list of the values of the 1814 * array of decimal numbers, an empty string if the array is empty, 1815 * or <code>null</code> if the array is <code>null</code> 1816 */ 1817 public static String merge(float[] array) { 1818 return merge(array, StringPool.COMMA); 1819 } 1820 1821 /** 1822 * Merges the elements of an array of decimal numbers into a string 1823 * representing a delimited list of its values. 1824 * 1825 * @param array the floats to merge 1826 * @param delimiter the delimiter 1827 * @return a string representing a delimited list of the values of the array 1828 * of decimal numbers, an empty string if the array is empty, or 1829 * <code>null</code> if the array is <code>null</code> 1830 */ 1831 public static String merge(float[] array, String delimiter) { 1832 if (array == null) { 1833 return null; 1834 } 1835 1836 if (array.length == 0) { 1837 return StringPool.BLANK; 1838 } 1839 1840 StringBundler sb = new StringBundler(2 * array.length - 1); 1841 1842 for (int i = 0; i < array.length; i++) { 1843 if (i != 0) { 1844 sb.append(delimiter); 1845 } 1846 1847 sb.append(String.valueOf(array[i])); 1848 } 1849 1850 return sb.toString(); 1851 } 1852 1853 /** 1854 * Merges the elements of an array of integers into a string representing a 1855 * comma delimited list of its values. 1856 * 1857 * @param array the integers to merge 1858 * @return a string representing a comma delimited list of the values of the 1859 * array of integers, an empty string if the array is empty, or 1860 * <code>null</code> if the array is <code>null</code> 1861 */ 1862 public static String merge(int[] array) { 1863 return merge(array, StringPool.COMMA); 1864 } 1865 1866 /** 1867 * Merges the elements of an array of integers into a string representing a 1868 * delimited list of its values. 1869 * 1870 * @param array the integers to merge 1871 * @param delimiter the delimiter 1872 * @return a string representing a delimited list of the values of the array 1873 * of integers, an empty string if the array is empty, or 1874 * <code>null</code> if the array is <code>null</code> 1875 */ 1876 public static String merge(int[] array, String delimiter) { 1877 if (array == null) { 1878 return null; 1879 } 1880 1881 if (array.length == 0) { 1882 return StringPool.BLANK; 1883 } 1884 1885 StringBundler sb = new StringBundler(2 * array.length - 1); 1886 1887 for (int i = 0; i < array.length; i++) { 1888 if (i != 0) { 1889 sb.append(delimiter); 1890 } 1891 1892 sb.append(String.valueOf(array[i])); 1893 } 1894 1895 return sb.toString(); 1896 } 1897 1898 /** 1899 * Merges the elements of an array of long integers by returning a string 1900 * representing a comma delimited list of its values. 1901 * 1902 * @param array the long integers to merge 1903 * @return a string representing a comma delimited list of the values of the 1904 * array of long integers, an empty string if the array is empty, or 1905 * <code>null</code> if the array is <code>null</code> 1906 */ 1907 public static String merge(long[] array) { 1908 return merge(array, StringPool.COMMA); 1909 } 1910 1911 /** 1912 * Merges the elements of an array of long integers by returning a string 1913 * representing a delimited list of its values. 1914 * 1915 * @param array the long integers to merge 1916 * @param delimiter the delimiter 1917 * @return a string representing a delimited list of the values of the array 1918 * of long integers, an empty string if the array is empty, or 1919 * <code>null</code> if the array is <code>null</code> 1920 */ 1921 public static String merge(long[] array, String delimiter) { 1922 if (array == null) { 1923 return null; 1924 } 1925 1926 if (array.length == 0) { 1927 return StringPool.BLANK; 1928 } 1929 1930 StringBundler sb = new StringBundler(2 * array.length - 1); 1931 1932 for (int i = 0; i < array.length; i++) { 1933 if (i != 0) { 1934 sb.append(delimiter); 1935 } 1936 1937 sb.append(String.valueOf(array[i])); 1938 } 1939 1940 return sb.toString(); 1941 } 1942 1943 /** 1944 * Merges the elements of an array of objects into a string representing a 1945 * comma delimited list of the objects. 1946 * 1947 * @param array the objects to merge 1948 * @return a string representing a comma delimited list of the objects, an 1949 * empty string if the array is empty, or <code>null</code> if the 1950 * array is <code>null</code> 1951 */ 1952 public static String merge(Object[] array) { 1953 return merge(array, StringPool.COMMA); 1954 } 1955 1956 /** 1957 * Merges the elements of an array of objects into a string representing a 1958 * delimited list of the objects. 1959 * 1960 * @param array the objects to merge 1961 * @param delimiter the delimiter 1962 * @return a string representing a delimited list of the objects, an empty 1963 * string if the array is empty, or <code>null</code> if the array 1964 * is <code>null</code> 1965 */ 1966 public static String merge(Object[] array, String delimiter) { 1967 if (array == null) { 1968 return null; 1969 } 1970 1971 if (array.length == 0) { 1972 return StringPool.BLANK; 1973 } 1974 1975 StringBundler sb = new StringBundler(2 * array.length - 1); 1976 1977 for (int i = 0; i < array.length; i++) { 1978 if (i != 0) { 1979 sb.append(delimiter); 1980 } 1981 1982 sb.append(String.valueOf(array[i]).trim()); 1983 } 1984 1985 return sb.toString(); 1986 } 1987 1988 /** 1989 * Merges the elements of an array of short integers by returning a string 1990 * representing a comma delimited list of its values. 1991 * 1992 * @param array the short integers to merge 1993 * @return a string representing a comma delimited list of the values of the 1994 * array of short integers, an empty string if the array is empty, 1995 * or <code>null</code> if the array is <code>null</code> 1996 */ 1997 public static String merge(short[] array) { 1998 return merge(array, StringPool.COMMA); 1999 } 2000 2001 /** 2002 * Merges the elements of an array of short integers by returning a string 2003 * representing a delimited list of its values. 2004 * 2005 * @param array the short integers to merge 2006 * @param delimiter the delimiter 2007 * @return a string representing a delimited list of the values of the array 2008 * of short integers, an empty string if the array is empty, or 2009 * <code>null</code> if the array is <code>null</code> 2010 */ 2011 public static String merge(short[] array, String delimiter) { 2012 if (array == null) { 2013 return null; 2014 } 2015 2016 if (array.length == 0) { 2017 return StringPool.BLANK; 2018 } 2019 2020 StringBundler sb = new StringBundler(2 * array.length - 1); 2021 2022 for (int i = 0; i < array.length; i++) { 2023 if (i != 0) { 2024 sb.append(delimiter); 2025 } 2026 2027 sb.append(String.valueOf(array[i])); 2028 } 2029 2030 return sb.toString(); 2031 } 2032 2033 /** 2034 * Returns the string enclosed by apostrophes. 2035 * 2036 * <p> 2037 * Example: 2038 * </p> 2039 * 2040 * <p> 2041 * <pre> 2042 * <code> 2043 * quote("Hello, World!") returns "'Hello, World!'" 2044 * </code> 2045 * </pre> 2046 * </p> 2047 * 2048 * @param s the string to enclose in apostrophes 2049 * @return the string enclosed by apostrophes, or <code>null</code> if the 2050 * string is <code>null</code> 2051 */ 2052 public static String quote(String s) { 2053 return quote(s, CharPool.APOSTROPHE); 2054 } 2055 2056 /** 2057 * Returns the string enclosed by the quote character. 2058 * 2059 * <p> 2060 * Example: 2061 * </p> 2062 * 2063 * <p> 2064 * <pre> 2065 * <code> 2066 * quote("PATH", '%') returns "%PATH%" 2067 * </code> 2068 * </pre> 2069 * </p> 2070 * 2071 * @param s the string to enclose in quotes 2072 * @param quote the character to insert to insert to the beginning of and 2073 * append to the end of the string 2074 * @return the string enclosed in the quote characters, or <code>null</code> 2075 * if the string is <code>null</code> 2076 */ 2077 public static String quote(String s, char quote) { 2078 if (s == null) { 2079 return null; 2080 } 2081 2082 return quote(s, String.valueOf(quote)); 2083 } 2084 2085 /** 2086 * Returns the string enclosed by the quote strings. 2087 * 2088 * <p> 2089 * Example: 2090 * </p> 2091 * 2092 * <p> 2093 * <pre> 2094 * <code> 2095 * quote("WARNING", "!!!") returns "!!!WARNING!!!" 2096 * </code> 2097 * </pre> 2098 * </p> 2099 * 2100 * @param s the string to enclose in quotes 2101 * @param quote the quote string to insert to insert to the beginning of 2102 * and append to the end of the string 2103 * @return the string enclosed in the quote strings, or <code>null</code> if 2104 * the string is <code>null</code> 2105 */ 2106 public static String quote(String s, String quote) { 2107 if (s == null) { 2108 return null; 2109 } 2110 2111 return quote.concat(s).concat(quote); 2112 } 2113 2114 /** 2115 * Returns a randomized string of four lower case, alphabetic characters. 2116 * 2117 * @return a randomized string of four lower case, alphabetic characters 2118 */ 2119 public static String randomId() { 2120 Random random = new Random(); 2121 2122 char[] chars = new char[4]; 2123 2124 for (int i = 0; i < 4; i++) { 2125 chars[i] = (char)(CharPool.LOWER_CASE_A + random.nextInt(26)); 2126 } 2127 2128 return new String(chars); 2129 } 2130 2131 /** 2132 * Pseudorandomly permutes the characters of the string. 2133 * 2134 * @param s the string whose characters are to be randomized 2135 * @return a string of the same length as the string whose characters 2136 * represent a pseudorandom permutation of the characters of the 2137 * string 2138 */ 2139 public static String randomize(String s) { 2140 return RandomUtil.shuffle(s); 2141 } 2142 2143 /** 2144 * Returns a randomized string of eight characters consisting of lower case 2145 * letters, upper case letters, and single-digit whole numbers. 2146 * 2147 * @return a randomized string of eight characters consisting of lower case 2148 * letters, upper case letters, and single-digit whole numbers 2149 */ 2150 public static String randomString() { 2151 return randomString(8); 2152 } 2153 2154 /** 2155 * Returns a randomized string of the specified length consisting of lower 2156 * case letters, upper case letters, and single-digit whole numbers. 2157 * 2158 * @param length the character length of the randomized string 2159 * @return a randomized string of the specified length consisting of lower 2160 * case letters, upper case letters, and single-digit whole numbers 2161 */ 2162 public static String randomString(int length) { 2163 Random random = new Random(); 2164 2165 char[] chars = new char[length]; 2166 2167 for (int i = 0; i < length; i++) { 2168 int index = random.nextInt(_RANDOM_STRING_CHAR_TABLE.length); 2169 2170 chars[i] = _RANDOM_STRING_CHAR_TABLE[index]; 2171 } 2172 2173 return new String(chars); 2174 } 2175 2176 public static String read(ClassLoader classLoader, String name) 2177 throws IOException { 2178 2179 return read(classLoader, name, false); 2180 } 2181 2182 public static String read(ClassLoader classLoader, String name, boolean all) 2183 throws IOException { 2184 2185 if (all) { 2186 StringBundler sb = new StringBundler(); 2187 2188 Enumeration<URL> enu = classLoader.getResources(name); 2189 2190 while (enu.hasMoreElements()) { 2191 URL url = enu.nextElement(); 2192 2193 InputStream is = url.openStream(); 2194 2195 if (is == null) { 2196 throw new IOException( 2197 "Unable to open resource at " + url.toString()); 2198 } 2199 2200 try { 2201 String s = read(is); 2202 2203 if (s != null) { 2204 sb.append(s); 2205 sb.append(StringPool.NEW_LINE); 2206 } 2207 } 2208 finally { 2209 StreamUtil.cleanUp(is); 2210 } 2211 } 2212 2213 return sb.toString().trim(); 2214 } 2215 2216 InputStream is = classLoader.getResourceAsStream(name); 2217 2218 if (is == null) { 2219 throw new IOException( 2220 "Unable to open resource in class loader " + name); 2221 } 2222 2223 try { 2224 String s = read(is); 2225 2226 return s; 2227 } 2228 finally { 2229 StreamUtil.cleanUp(is); 2230 } 2231 } 2232 2233 public static String read(InputStream is) throws IOException { 2234 StringBundler sb = new StringBundler(); 2235 2236 try (UnsyncBufferedReader unsyncBufferedReader = 2237 new UnsyncBufferedReader(new InputStreamReader(is))) { 2238 2239 String line = null; 2240 2241 while ((line = unsyncBufferedReader.readLine()) != null) { 2242 sb.append(line); 2243 sb.append(CharPool.NEW_LINE); 2244 } 2245 } 2246 2247 return sb.toString().trim(); 2248 } 2249 2250 public static void readLines(InputStream is, Collection<String> lines) 2251 throws IOException { 2252 2253 try (UnsyncBufferedReader unsyncBufferedReader = 2254 new UnsyncBufferedReader(new InputStreamReader(is))) { 2255 2256 String line = null; 2257 2258 while ((line = unsyncBufferedReader.readLine()) != null) { 2259 lines.add(line); 2260 } 2261 } 2262 } 2263 2264 /** 2265 * @deprecated As of 7.0.0, replaced by {@link #removeFromList(String, 2266 * String)} 2267 */ 2268 @Deprecated 2269 public static String remove(String s, String element) { 2270 return removeFromList(s, element, StringPool.COMMA); 2271 } 2272 2273 /** 2274 * @deprecated As of 7.0.0, replaced by {@link #removeFromList(String, 2275 * String, String)} 2276 */ 2277 @Deprecated 2278 public static String remove(String s, String element, String delimiter) { 2279 return removeFromList(s, element, delimiter); 2280 } 2281 2282 public static String removeChar(String s, char oldSub) { 2283 if (s == null) { 2284 return null; 2285 } 2286 2287 int y = s.indexOf(oldSub); 2288 2289 if (y >= 0) { 2290 StringBundler sb = new StringBundler(); 2291 2292 int x = 0; 2293 2294 while (x <= y) { 2295 sb.append(s.substring(x, y)); 2296 2297 x = y + 1; 2298 y = s.indexOf(oldSub, x); 2299 } 2300 2301 sb.append(s.substring(x)); 2302 2303 return sb.toString(); 2304 } 2305 else { 2306 return s; 2307 } 2308 } 2309 2310 public static String removeChars(String s, char... oldSubs) { 2311 if (s == null) { 2312 return null; 2313 } 2314 2315 if (oldSubs == null) { 2316 return s; 2317 } 2318 2319 StringBuilder sb = new StringBuilder(s.length()); 2320 2321 iterate: 2322 for (int i = 0; i < s.length(); i++) { 2323 char c = s.charAt(i); 2324 2325 for (int j = 0; j < oldSubs.length; j++) { 2326 if (c == oldSubs[j]) { 2327 continue iterate; 2328 } 2329 } 2330 2331 sb.append(c); 2332 } 2333 2334 if (s.length() == sb.length()) { 2335 return s; 2336 } 2337 2338 return sb.toString(); 2339 } 2340 2341 /** 2342 * Removes the <code>remove</code> string from string <code>s</code> that 2343 * represents a list of comma delimited strings. 2344 * 2345 * <p> 2346 * The resulting string ends with a comma even if the original string does 2347 * not. 2348 * </p> 2349 * 2350 * <p> 2351 * Examples: 2352 * </p> 2353 * 2354 * <p> 2355 * <pre> 2356 * <code> 2357 * remove("red,blue,green,yellow", "blue") returns "red,green,yellow," 2358 * remove("blue", "blue") returns "" 2359 * remove("blue,", "blue") returns "" 2360 * </code> 2361 * </pre> 2362 * </p> 2363 * 2364 * @param s the string representing the list of comma delimited strings 2365 * @param element the string to remove 2366 * @return a string representing the list of comma delimited strings with 2367 * the <code>remove</code> string removed, or <code>null</code> if 2368 * the original string, the string to remove, or the delimiter is 2369 * <code>null</code> 2370 */ 2371 public static String removeFromList(String s, String element) { 2372 return removeFromList(s, element, StringPool.COMMA); 2373 } 2374 2375 /** 2376 * Removes the <code>remove</code> string from string <code>s</code> that 2377 * represents a list of delimited strings. 2378 * 2379 * <p> 2380 * The resulting string ends with the delimiter even if the original string 2381 * does not. 2382 * </p> 2383 * 2384 * <p> 2385 * Examples: 2386 * </p> 2387 * 2388 * <p> 2389 * <pre> 2390 * <code> 2391 * remove("red;blue;green;yellow", "blue", ";") returns "red;green;yellow;" 2392 * remove("blue", "blue", ";") returns "" 2393 * remove("blue;", "blue", ";") returns "" 2394 * </code> 2395 * </pre> 2396 * </p> 2397 * 2398 * @param s the string representing the list of delimited strings 2399 * @param element the string to remove 2400 * @param delimiter the delimiter 2401 * @return a string representing the list of delimited strings with the 2402 * <code>remove</code> string removed, or <code>null</code> if the 2403 * original string, the string to remove, or the delimiter is 2404 * <code>null</code> 2405 */ 2406 public static String removeFromList( 2407 String s, String element, String delimiter) { 2408 2409 if ((s == null) || (element == null) || (delimiter == null)) { 2410 return null; 2411 } 2412 2413 if (Validator.isNotNull(s) && !s.endsWith(delimiter)) { 2414 s += delimiter; 2415 } 2416 2417 String drd = delimiter.concat(element).concat(delimiter); 2418 2419 String rd = element.concat(delimiter); 2420 2421 while (contains(s, element, delimiter)) { 2422 int pos = s.indexOf(drd); 2423 2424 if (pos == -1) { 2425 if (s.startsWith(rd)) { 2426 int x = element.length() + delimiter.length(); 2427 int y = s.length(); 2428 2429 s = s.substring(x, y); 2430 } 2431 } 2432 else { 2433 int x = pos + element.length() + delimiter.length(); 2434 int y = s.length(); 2435 2436 String temp = s.substring(0, pos); 2437 2438 s = temp.concat(s.substring(x, y)); 2439 } 2440 } 2441 2442 return s; 2443 } 2444 2445 public static String removeSubstring(String s, String oldSub) { 2446 if (s == null) { 2447 return null; 2448 } 2449 2450 if (oldSub == null) { 2451 return s; 2452 } 2453 2454 int y = s.indexOf(oldSub); 2455 2456 if (y >= 0) { 2457 StringBundler sb = new StringBundler(); 2458 2459 int length = oldSub.length(); 2460 int x = 0; 2461 2462 while (x <= y) { 2463 sb.append(s.substring(x, y)); 2464 2465 x = y + length; 2466 y = s.indexOf(oldSub, x); 2467 } 2468 2469 sb.append(s.substring(x)); 2470 2471 return sb.toString(); 2472 } 2473 else { 2474 return s; 2475 } 2476 } 2477 2478 public static String removeSubstrings(String s, String... oldSubs) { 2479 if (s == null) { 2480 return null; 2481 } 2482 2483 if (ArrayUtil.isEmpty(oldSubs)) { 2484 return s; 2485 } 2486 2487 for (String oldSub : oldSubs) { 2488 s = removeSubstring(s, oldSub); 2489 } 2490 2491 return s; 2492 } 2493 2494 /** 2495 * Replaces all occurrences of the character with the new character. 2496 * 2497 * @param s the original string 2498 * @param oldSub the character to be searched for and replaced in the 2499 * original string 2500 * @param newSub the character with which to replace the 2501 * <code>oldSub</code> character 2502 * @return a string representing the original string with all occurrences of 2503 * the <code>oldSub</code> character replaced with the 2504 * <code>newSub</code> character, or <code>null</code> if the 2505 * original string is <code>null</code> 2506 */ 2507 public static String replace(String s, char oldSub, char newSub) { 2508 if (s == null) { 2509 return null; 2510 } 2511 2512 return s.replace(oldSub, newSub); 2513 } 2514 2515 /** 2516 * Replaces all occurrences of the character with the new string. 2517 * 2518 * @param s the original string 2519 * @param oldSub the character to be searched for and replaced in the 2520 * original string 2521 * @param newSub the string with which to replace the <code>oldSub</code> 2522 * character 2523 * @return a string representing the original string with all occurrences of 2524 * the <code>oldSub</code> character replaced with the string 2525 * <code>newSub</code>, or <code>null</code> if the original string 2526 * is <code>null</code> 2527 */ 2528 public static String replace(String s, char oldSub, String newSub) { 2529 if ((s == null) || (newSub == null)) { 2530 return null; 2531 } 2532 2533 int index = s.indexOf(oldSub); 2534 2535 if (index == -1) { 2536 return s; 2537 } 2538 2539 int previousIndex = index; 2540 2541 StringBundler sb = new StringBundler(); 2542 2543 if (previousIndex != 0) { 2544 sb.append(s.substring(0, previousIndex)); 2545 } 2546 2547 sb.append(newSub); 2548 2549 while ((index = s.indexOf(oldSub, previousIndex + 1)) != -1) { 2550 sb.append(s.substring(previousIndex + 1, index)); 2551 sb.append(newSub); 2552 2553 previousIndex = index; 2554 } 2555 2556 index = previousIndex + 1; 2557 2558 if (index < s.length()) { 2559 sb.append(s.substring(index)); 2560 } 2561 2562 return sb.toString(); 2563 } 2564 2565 public static String replace(String s, char[] oldSubs, char[] newSubs) { 2566 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 2567 return null; 2568 } 2569 2570 if (oldSubs.length != newSubs.length) { 2571 return s; 2572 } 2573 2574 StringBuilder sb = new StringBuilder(s.length()); 2575 2576 sb.append(s); 2577 2578 boolean modified = false; 2579 2580 for (int i = 0; i < sb.length(); i++) { 2581 char c = sb.charAt(i); 2582 2583 for (int j = 0; j < oldSubs.length; j++) { 2584 if (c == oldSubs[j]) { 2585 sb.setCharAt(i, newSubs[j]); 2586 2587 modified = true; 2588 2589 break; 2590 } 2591 } 2592 } 2593 2594 if (modified) { 2595 return sb.toString(); 2596 } 2597 2598 return s; 2599 } 2600 2601 public static String replace(String s, char[] oldSubs, String[] newSubs) { 2602 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 2603 return null; 2604 } 2605 2606 if (oldSubs.length != newSubs.length) { 2607 return s; 2608 } 2609 2610 StringBundler sb = null; 2611 2612 int lastReplacementIndex = 0; 2613 2614 for (int i = 0; i < s.length(); i++) { 2615 char c = s.charAt(i); 2616 2617 for (int j = 0; j < oldSubs.length; j++) { 2618 if (c == oldSubs[j]) { 2619 if (sb == null) { 2620 sb = new StringBundler(); 2621 } 2622 2623 if (i > lastReplacementIndex) { 2624 sb.append(s.substring(lastReplacementIndex, i)); 2625 } 2626 2627 sb.append(newSubs[j]); 2628 2629 lastReplacementIndex = i + 1; 2630 2631 break; 2632 } 2633 } 2634 } 2635 2636 if (sb == null) { 2637 return s; 2638 } 2639 2640 if (lastReplacementIndex < s.length()) { 2641 sb.append(s.substring(lastReplacementIndex)); 2642 } 2643 2644 return sb.toString(); 2645 } 2646 2647 /** 2648 * Replaces all occurrences of the string with the new string. 2649 * 2650 * @param s the original string 2651 * @param oldSub the string to be searched for and replaced in the original 2652 * string 2653 * @param newSub the string with which to replace the <code>oldSub</code> 2654 * string 2655 * @return a string representing the original string with all occurrences of 2656 * the <code>oldSub</code> string replaced with the string 2657 * <code>newSub</code>, or <code>null</code> if the original string 2658 * is <code>null</code> 2659 */ 2660 public static String replace(String s, String oldSub, String newSub) { 2661 return replace(s, oldSub, newSub, 0); 2662 } 2663 2664 /** 2665 * Replaces all occurrences of the string with the new string, starting from 2666 * the specified index. 2667 * 2668 * @param s the original string 2669 * @param oldSub the string to be searched for and replaced in the original 2670 * string 2671 * @param newSub the string with which to replace the <code>oldSub</code> 2672 * string 2673 * @param fromIndex the index of the original string from which to begin 2674 * searching 2675 * @return a string representing the original string with all occurrences of 2676 * the <code>oldSub</code> string occurring after the specified 2677 * index replaced with the string <code>newSub</code>, or 2678 * <code>null</code> if the original string is <code>null</code> 2679 */ 2680 public static String replace( 2681 String s, String oldSub, String newSub, int fromIndex) { 2682 2683 if (s == null) { 2684 return null; 2685 } 2686 2687 if ((oldSub == null) || oldSub.equals(StringPool.BLANK)) { 2688 return s; 2689 } 2690 2691 if (newSub == null) { 2692 newSub = StringPool.BLANK; 2693 } 2694 2695 int y = s.indexOf(oldSub, fromIndex); 2696 2697 if (y >= 0) { 2698 StringBundler sb = new StringBundler(); 2699 2700 int length = oldSub.length(); 2701 int x = 0; 2702 2703 while (x <= y) { 2704 sb.append(s.substring(x, y)); 2705 sb.append(newSub); 2706 2707 x = y + length; 2708 y = s.indexOf(oldSub, x); 2709 } 2710 2711 sb.append(s.substring(x)); 2712 2713 return sb.toString(); 2714 } 2715 else { 2716 return s; 2717 } 2718 } 2719 2720 /** 2721 * Replaces all occurrences of the keywords found in the substring, defined 2722 * by the beginning and ending strings, with the new values. 2723 * 2724 * <p> 2725 * For example, with the following initialized variables: 2726 * </p> 2727 * 2728 * <p> 2729 * <pre> 2730 * <code> 2731 * String s = "http://www.example-url/${userId}"; 2732 * String begin = "${"; 2733 * String end = "}"; 2734 * Map<String, String> values = new HashMap<String, String>(); 2735 * values.put("userId", "jbloggs"); 2736 * </code> 2737 * </pre> 2738 * </p> 2739 * 2740 * <p> 2741 * <code>replace(s, begin, end, values)</code> returns 2742 * <code>"http://www.example-url/jbloggs"</code> 2743 * </p> 2744 * 2745 * @param s the original string 2746 * @param begin the string preceding the substring to be modified. This 2747 * string is excluded from the result. 2748 * @param end the string following the substring to be modified. This 2749 * string is excluded from the result. 2750 * @param values the key-value map values 2751 * @return a string representing the original string with all occurrences of 2752 * the of the keywords found in the substring, replaced with the new 2753 * values. <code>null</code> is returned if the original string, the 2754 * beginning string, the ending string, or the key-map values are 2755 * <code>null</code>. 2756 */ 2757 public static String replace( 2758 String s, String begin, String end, Map<String, String> values) { 2759 2760 StringBundler sb = replaceToStringBundler(s, begin, end, values); 2761 2762 return sb.toString(); 2763 } 2764 2765 /** 2766 * Replaces all occurrences of the elements of the string array with the 2767 * corresponding elements of the new string array. 2768 * 2769 * @param s the original string 2770 * @param oldSubs the strings to be searched for and replaced in the 2771 * original string 2772 * @param newSubs the strings with which to replace the 2773 * <code>oldSubs</code> strings 2774 * @return a string representing the original string with all occurrences of 2775 * the <code>oldSubs</code> strings replaced with the corresponding 2776 * <code>newSubs</code> strings, or <code>null</code> if the 2777 * original string, the <code>oldSubs</code> array, or the 2778 * <code>newSubs</code> is <code>null</code> 2779 */ 2780 public static String replace(String s, String[] oldSubs, String[] newSubs) { 2781 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 2782 return null; 2783 } 2784 2785 if (oldSubs.length != newSubs.length) { 2786 return s; 2787 } 2788 2789 for (int i = 0; i < oldSubs.length; i++) { 2790 s = replace(s, oldSubs[i], newSubs[i]); 2791 } 2792 2793 return s; 2794 } 2795 2796 /** 2797 * Replaces all occurrences of the elements of the string array with the 2798 * corresponding elements of the new string array, optionally replacing only 2799 * substrings that are surrounded by word boundaries. 2800 * 2801 * <p> 2802 * Examples: 2803 * </p> 2804 * 2805 * <p> 2806 * <pre> 2807 * <code> 2808 * replace("redorangeyellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "REDORANGEYELLOW" 2809 * replace("redorangeyellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, true) returns "redorangeyellow" 2810 * replace("redorange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "REDORANGE YELLOW" 2811 * replace("redorange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, true) returns "redorange YELLOW" 2812 * replace("red orange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "RED ORANGE YELLOW" 2813 * replace("redorange.yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", * "YELLOW"}, true) returns "redorange.YELLOW" 2814 * </code> 2815 * </pre> 2816 * </p> 2817 * 2818 * @param s the original string 2819 * @param oldSubs the strings to be searched for and replaced in the 2820 * original string 2821 * @param newSubs the strings with which to replace the 2822 * <code>oldSubs</code> strings 2823 * @param exactMatch whether or not to replace only substrings of 2824 * <code>s</code> that are surrounded by word boundaries 2825 * @return if <code>exactMatch</code> is <code>true</code>, a string 2826 * representing the original string with all occurrences of the 2827 * <code>oldSubs</code> strings that are surrounded by word 2828 * boundaries replaced with the corresponding <code>newSubs</code> 2829 * strings, or else a string representing the original string with 2830 * all occurrences of the <code>oldSubs</code> strings replaced with 2831 * the corresponding <code>newSubs</code> strings, or 2832 * <code>null</code> if the original string, the 2833 * <code>oldSubs</code> array, or the <code>newSubs</code> is 2834 * <code>null</code> 2835 */ 2836 public static String replace( 2837 String s, String[] oldSubs, String[] newSubs, boolean exactMatch) { 2838 2839 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 2840 return null; 2841 } 2842 2843 if (oldSubs.length != newSubs.length) { 2844 return s; 2845 } 2846 2847 if (!exactMatch) { 2848 return replace(s, oldSubs, newSubs); 2849 } 2850 2851 for (int i = 0; i < oldSubs.length; i++) { 2852 s = s.replaceAll("\\b" + oldSubs[i] + "\\b", newSubs[i]); 2853 } 2854 2855 return s; 2856 } 2857 2858 /** 2859 * Replaces the first occurrence of the character with the new character. 2860 * 2861 * @param s the original string 2862 * @param oldSub the character whose first occurrence in the original 2863 * string is to be searched for and replaced 2864 * @param newSub the character with which to replace the first occurrence 2865 * of the <code>oldSub</code> character 2866 * @return a string representing the original string except with the first 2867 * occurrence of the character <code>oldSub</code> replaced with the 2868 * character <code>newSub</code> 2869 */ 2870 public static String replaceFirst(String s, char oldSub, char newSub) { 2871 if (s == null) { 2872 return null; 2873 } 2874 2875 return replaceFirst(s, String.valueOf(oldSub), String.valueOf(newSub)); 2876 } 2877 2878 /** 2879 * Replaces the first occurrence of the character with the new string. 2880 * 2881 * @param s the original string 2882 * @param oldSub the character whose first occurrence in the original 2883 * string is to be searched for and replaced 2884 * @param newSub the string with which to replace the first occurrence of 2885 * the <code>oldSub</code> character 2886 * @return a string representing the original string except with the first 2887 * occurrence of the character <code>oldSub</code> replaced with the 2888 * string <code>newSub</code> 2889 */ 2890 public static String replaceFirst(String s, char oldSub, String newSub) { 2891 if ((s == null) || (newSub == null)) { 2892 return null; 2893 } 2894 2895 return replaceFirst(s, String.valueOf(oldSub), newSub); 2896 } 2897 2898 /** 2899 * Replaces the first occurrence of the string with the new string. 2900 * 2901 * @param s the original string 2902 * @param oldSub the string whose first occurrence in the original string 2903 * is to be searched for and replaced 2904 * @param newSub the string with which to replace the first occurrence of 2905 * the <code>oldSub</code> string 2906 * @return a string representing the original string except with the first 2907 * occurrence of the string <code>oldSub</code> replaced with the 2908 * string <code>newSub</code> 2909 */ 2910 public static String replaceFirst(String s, String oldSub, String newSub) { 2911 return replaceFirst(s, oldSub, newSub, 0); 2912 } 2913 2914 /** 2915 * Replaces the first occurrences of the elements of the string array with 2916 * the corresponding elements of the new string array, beginning the element 2917 * search from the index position. 2918 * 2919 * @param s the original string 2920 * @param oldSub the strings whose first occurrences are to be searched for 2921 * and replaced in the original string 2922 * @param newSub the strings with which to replace the first occurrences of 2923 * the <code>oldSubs</code> strings 2924 * @param fromIndex the start index within the string 2925 * @return a string representing the original string with the first 2926 * occurrences of the <code>oldSubs</code> strings replaced with the 2927 * corresponding <code>newSubs</code> strings, or <code>null</code> 2928 * if the original string, the <code>oldSubs</code> string, or the 2929 * <code>newSubs</code> string is <code>null</code> 2930 */ 2931 public static String replaceFirst( 2932 String s, String oldSub, String newSub, int fromIndex) { 2933 2934 if ((s == null) || (oldSub == null) || (newSub == null)) { 2935 return null; 2936 } 2937 2938 if (oldSub.equals(newSub)) { 2939 return s; 2940 } 2941 2942 int y = s.indexOf(oldSub, fromIndex); 2943 2944 if (y >= 0) { 2945 return s.substring(0, y).concat(newSub).concat( 2946 s.substring(y + oldSub.length())); 2947 } 2948 else { 2949 return s; 2950 } 2951 } 2952 2953 /** 2954 * Replaces the first occurrences of the elements of the string array with 2955 * the corresponding elements of the new string array. 2956 * 2957 * @param s the original string 2958 * @param oldSubs the strings whose first occurrences are to be searched 2959 * for and replaced in the original string 2960 * @param newSubs the strings with which to replace the first occurrences 2961 * of the <code>oldSubs</code> strings 2962 * @return a string representing the original string with the first 2963 * occurrences of the <code>oldSubs</code> strings replaced with the 2964 * corresponding <code>newSubs</code> strings, or <code>null</code> 2965 * if the original string, the <code>oldSubs</code> array, or the 2966 * <code>newSubs</code> is <code>null</code> 2967 */ 2968 public static String replaceFirst( 2969 String s, String[] oldSubs, String[] newSubs) { 2970 2971 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 2972 return null; 2973 } 2974 2975 if (oldSubs.length != newSubs.length) { 2976 return s; 2977 } 2978 2979 for (int i = 0; i < oldSubs.length; i++) { 2980 s = replaceFirst(s, oldSubs[i], newSubs[i]); 2981 } 2982 2983 return s; 2984 } 2985 2986 /** 2987 * Replaces the last occurrence of the character with the new character. 2988 * 2989 * @param s the original string 2990 * @param oldSub the character whose last occurrence in the original string 2991 * is to be searched for and replaced 2992 * @param newSub the character with which to replace the last occurrence of 2993 * the <code>oldSub</code> character 2994 * @return a string representing the original string except with the first 2995 * occurrence of the character <code>oldSub</code> replaced with the 2996 * character <code>newSub</code> 2997 */ 2998 public static String replaceLast(String s, char oldSub, char newSub) { 2999 if (s == null) { 3000 return null; 3001 } 3002 3003 return replaceLast(s, String.valueOf(oldSub), String.valueOf(newSub)); 3004 } 3005 3006 /** 3007 * Replaces the last occurrence of the character with the new string. 3008 * 3009 * @param s the original string 3010 * @param oldSub the character whose last occurrence in the original string 3011 * is to be searched for and replaced 3012 * @param newSub the string with which to replace the last occurrence of 3013 * the <code>oldSub</code> character 3014 * @return a string representing the original string except with the last 3015 * occurrence of the character <code>oldSub</code> replaced with the 3016 * string <code>newSub</code> 3017 */ 3018 public static String replaceLast(String s, char oldSub, String newSub) { 3019 if ((s == null) || (newSub == null)) { 3020 return null; 3021 } 3022 3023 return replaceLast(s, String.valueOf(oldSub), newSub); 3024 } 3025 3026 /** 3027 * Replaces the last occurrence of the string <code>oldSub</code> in the 3028 * string <code>s</code> with the string <code>newSub</code>. 3029 * 3030 * @param s the original string 3031 * @param oldSub the string whose last occurrence in the original string is 3032 * to be searched for and replaced 3033 * @param newSub the string with which to replace the last occurrence of 3034 * the <code>oldSub</code> string 3035 * @return a string representing the original string except with the last 3036 * occurrence of the string <code>oldSub</code> replaced with the 3037 * string <code>newSub</code> 3038 */ 3039 public static String replaceLast(String s, String oldSub, String newSub) { 3040 if ((s == null) || (oldSub == null) || (newSub == null)) { 3041 return null; 3042 } 3043 3044 if (oldSub.equals(newSub)) { 3045 return s; 3046 } 3047 3048 int y = s.lastIndexOf(oldSub); 3049 3050 if (y >= 0) { 3051 return s.substring(0, y).concat(newSub).concat( 3052 s.substring(y + oldSub.length())); 3053 } 3054 else { 3055 return s; 3056 } 3057 } 3058 3059 /** 3060 * Replaces the last occurrences of the elements of the string array with 3061 * the corresponding elements of the new string array. 3062 * 3063 * @param s the original string 3064 * @param oldSubs the strings whose last occurrences are to be searched for 3065 * and replaced in the original string 3066 * @param newSubs the strings with which to replace the last occurrences of 3067 * the <code>oldSubs</code> strings 3068 * @return a string representing the original string with the last 3069 * occurrences of the <code>oldSubs</code> strings replaced with the 3070 * corresponding <code>newSubs</code> strings, or <code>null</code> 3071 * if the original string, the <code>oldSubs</code> array, or the 3072 * <code>newSubs</code> is <code>null</code> 3073 */ 3074 public static String replaceLast( 3075 String s, String[] oldSubs, String[] newSubs) { 3076 3077 if ((s == null) || (oldSubs == null) || (newSubs == null)) { 3078 return null; 3079 } 3080 3081 if (oldSubs.length != newSubs.length) { 3082 return s; 3083 } 3084 3085 for (int i = 0; i < oldSubs.length; i++) { 3086 s = replaceLast(s, oldSubs[i], newSubs[i]); 3087 } 3088 3089 return s; 3090 } 3091 3092 /** 3093 * Replaces all occurrences of the keywords found in the substring, defined 3094 * by the beginning and ending strings, with the new values. The result is 3095 * returned as a {@link StringBundler}. 3096 * 3097 * <p> 3098 * For example, with the following initialized variables: 3099 * </p> 3100 * 3101 * <p> 3102 * <pre> 3103 * <code> 3104 * String s = "http://www.example-url/${userId}"; 3105 * String begin = "${"; 3106 * String end = "}"; 3107 * Map<String, String> values = new HashMap<String, String>(); 3108 * values.put("userId", "jbloggs"); 3109 * </code> 3110 * </pre> 3111 * </p> 3112 * 3113 * <p> 3114 * <code>StringBundler sb = replaceToStringBundler(s, begin, end, 3115 * values)</code> <code>sb.toString()</code> returns 3116 * <code>"http://www.example-url/jbloggs"</code> 3117 * </p> 3118 * 3119 * @param s the original string 3120 * @param begin the string preceding the substring to be modified. This 3121 * string is excluded from the result. 3122 * @param end the string following the substring to be modified. This 3123 * string is excluded from the result. 3124 * @param values the key-value map values 3125 * @return a string bundler representing the original string with all 3126 * occurrences of the keywords found in the substring, replaced with 3127 * the new values. <code>null</code> is returned if the original 3128 * string, the beginning string, the ending string, or the key-map 3129 * values are <code>null</code>. 3130 * @see #replace(String, String, String, Map) 3131 */ 3132 public static StringBundler replaceToStringBundler( 3133 String s, String begin, String end, Map<String, String> values) { 3134 3135 if (Validator.isBlank(s) || Validator.isBlank(begin) || 3136 Validator.isBlank(end) || MapUtil.isEmpty(values)) { 3137 3138 return new StringBundler(s); 3139 } 3140 3141 StringBundler sb = new StringBundler(values.size() * 2 + 1); 3142 3143 int pos = 0; 3144 3145 while (true) { 3146 int x = s.indexOf(begin, pos); 3147 int y = s.indexOf(end, x + begin.length()); 3148 3149 if ((x == -1) || (y == -1)) { 3150 sb.append(s.substring(pos)); 3151 3152 break; 3153 } 3154 else { 3155 sb.append(s.substring(pos, x)); 3156 3157 String oldValue = s.substring(x + begin.length(), y); 3158 3159 String newValue = values.get(oldValue); 3160 3161 if (newValue == null) { 3162 newValue = oldValue; 3163 } 3164 3165 sb.append(newValue); 3166 3167 pos = y + end.length(); 3168 } 3169 } 3170 3171 return sb; 3172 } 3173 3174 /** 3175 * Replaces all occurrences of the keywords found in the substring, defined 3176 * by the beginning and ending strings, with the new values. The result is 3177 * returned as a {@link StringBundler}. 3178 * 3179 * @param s the original string 3180 * @param begin the string preceding the substring to be modified. This 3181 * string is removed from the result. 3182 * @param end the string following the substring to be modified. This 3183 * string is removed from the result. 3184 * @param values the key-value map values, which has string keys and {@link 3185 * StringBundler} values 3186 * @return a string bundler representing the original string with all 3187 * occurrences of the keywords found in the substring, replaced with 3188 * the new values. <code>null</code> is returned if the original 3189 * string, the beginning string, the ending string, or the key-map 3190 * values are <code>null</code>. 3191 */ 3192 public static StringBundler replaceWithStringBundler( 3193 String s, String begin, String end, Map<String, StringBundler> values) { 3194 3195 if (Validator.isBlank(s) || Validator.isBlank(begin) || 3196 Validator.isBlank(end) || MapUtil.isEmpty(values)) { 3197 3198 return new StringBundler(s); 3199 } 3200 3201 int size = values.size() + 1; 3202 3203 for (StringBundler valueSB : values.values()) { 3204 size += valueSB.index(); 3205 } 3206 3207 StringBundler sb = new StringBundler(size); 3208 3209 int pos = 0; 3210 3211 while (true) { 3212 int x = s.indexOf(begin, pos); 3213 int y = s.indexOf(end, x + begin.length()); 3214 3215 if ((x == -1) || (y == -1)) { 3216 sb.append(s.substring(pos)); 3217 3218 break; 3219 } 3220 else { 3221 sb.append(s.substring(pos, x)); 3222 3223 String oldValue = s.substring(x + begin.length(), y); 3224 3225 StringBundler newValue = values.get(oldValue); 3226 3227 if (newValue == null) { 3228 sb.append(oldValue); 3229 } 3230 else { 3231 sb.append(newValue); 3232 } 3233 3234 pos = y + end.length(); 3235 } 3236 } 3237 3238 return sb; 3239 } 3240 3241 /** 3242 * Reverses the order of the characters of the string. 3243 * 3244 * @param s the original string 3245 * @return a string representing the original string with characters in 3246 * reverse order 3247 */ 3248 public static String reverse(String s) { 3249 if (s == null) { 3250 return null; 3251 } 3252 3253 char[] chars = s.toCharArray(); 3254 char[] reverse = new char[chars.length]; 3255 3256 for (int i = 0; i < chars.length; i++) { 3257 reverse[i] = chars[chars.length - i - 1]; 3258 } 3259 3260 return new String(reverse); 3261 } 3262 3263 /** 3264 * Replaces all double slashes of the string with single slashes. 3265 * 3266 * <p> 3267 * Example: 3268 * </p> 3269 * 3270 * <p> 3271 * <pre> 3272 * <code> 3273 * safePath("http://www.liferay.com") returns "http:/www.liferay.com" 3274 * </code> 3275 * </pre> 3276 * </p> 3277 * 3278 * @param path the original string 3279 * @return a string representing the original string with all double slashes 3280 * replaced with single slashes 3281 */ 3282 public static String safePath(String path) { 3283 return replace(path, StringPool.DOUBLE_SLASH, StringPool.SLASH); 3284 } 3285 3286 /** 3287 * Returns a string representing the original string appended with suffix 3288 * "..." and then shortened to 20 characters. 3289 * 3290 * <p> 3291 * The suffix is only added if the original string exceeds 20 characters. If 3292 * the original string exceeds 20 characters and it contains whitespace, the 3293 * string is shortened at the first whitespace character. 3294 * </p> 3295 * 3296 * <p> 3297 * Examples: 3298 * </p> 3299 * 3300 * <p> 3301 * <pre> 3302 * <code> 3303 * shorten("12345678901234567890xyz") returns "12345678901234567..." 3304 * shorten("1 345678901234567890xyz") returns "1..." 3305 * shorten(" 2345678901234567890xyz") returns "..." 3306 * shorten("12345678901234567890") returns "12345678901234567890" 3307 * shorten(" 2345678901234567890") returns " 2345678901234567890" 3308 * </code> 3309 * </pre> 3310 * </p> 3311 * 3312 * @param s the original string 3313 * @return a string representing the original string shortened to 20 3314 * characters, with suffix "..." appended to it 3315 */ 3316 public static String shorten(String s) { 3317 return shorten(s, 20); 3318 } 3319 3320 /** 3321 * Returns a string representing the original string appended with suffix 3322 * "..." and then shortened to the specified length. 3323 * 3324 * <p> 3325 * The suffix is only added if the original string exceeds the specified 3326 * length. If the original string exceeds the specified length and it 3327 * contains whitespace, the string is shortened at the first whitespace 3328 * character. 3329 * </p> 3330 * 3331 * <p> 3332 * Examples: 3333 * </p> 3334 * 3335 * <p> 3336 * <pre> 3337 * <code> 3338 * shorten("123456789", 8) returns "12345..." 3339 * shorten("1 3456789", 8) returns "1..." 3340 * shorten(" 23456789", 8) returns "..." 3341 * shorten("12345678", 8) returns "12345678" 3342 * shorten(" 1234567", 8) returns " 1234567" 3343 * </code> 3344 * </pre> 3345 * </p> 3346 * 3347 * @param s the original string 3348 * @param length the number of characters to limit from the original string 3349 * @return a string representing the original string shortened to the 3350 * specified length, with suffix "..." appended to it 3351 */ 3352 public static String shorten(String s, int length) { 3353 return shorten(s, length, "..."); 3354 } 3355 3356 /** 3357 * Returns a string representing the original string appended with the 3358 * specified suffix and then shortened to the specified length. 3359 * 3360 * <p> 3361 * The suffix is only added if the original string exceeds the specified 3362 * length. If the original string exceeds the specified length and it 3363 * contains whitespace, the string is shortened at the first whitespace 3364 * character. 3365 * </p> 3366 * 3367 * <p> 3368 * Examples: 3369 * </p> 3370 * 3371 * <p> 3372 * <pre> 3373 * <code> 3374 * shorten("12345678901234", 13, "... etc.") returns "12345... etc." 3375 * shorten("1 345678901234", 13, "... etc.") returns "1... etc." 3376 * shorten(" 2345678901234", 13, "... etc.") returns "... etc." 3377 * shorten("1234567890123", 13, "... etc.") returns "1234567890123" 3378 * shorten(" 123456789012", 13, "... etc.") returns " 123456789012" 3379 * </code> 3380 * </pre> 3381 * </p> 3382 * 3383 * @param s the original string 3384 * @param length the number of characters to limit from the original string 3385 * @param suffix the suffix to append 3386 * @return a string representing the original string shortened to the 3387 * specified length, with the specified suffix appended to it 3388 */ 3389 public static String shorten(String s, int length, String suffix) { 3390 if ((s == null) || (suffix == null)) { 3391 return null; 3392 } 3393 3394 if (s.length() <= length) { 3395 return s; 3396 } 3397 3398 if (length < suffix.length()) { 3399 return s.substring(0, length); 3400 } 3401 3402 int curLength = length; 3403 3404 for (int j = (curLength - suffix.length()); j >= 0; j--) { 3405 if (Character.isWhitespace(s.charAt(j))) { 3406 curLength = j; 3407 3408 break; 3409 } 3410 } 3411 3412 if (curLength == length) { 3413 curLength = length - suffix.length(); 3414 } 3415 3416 String temp = s.substring(0, curLength); 3417 3418 return temp.concat(suffix); 3419 } 3420 3421 /** 3422 * Returns a string representing the original string appended with the 3423 * specified suffix and then shortened to 20 characters. 3424 * 3425 * <p> 3426 * The suffix is only added if the original string exceeds 20 characters. If 3427 * the original string exceeds 20 characters and it contains whitespace, the 3428 * string is shortened at the first whitespace character. 3429 * </p> 3430 * 3431 * <p> 3432 * Examples: 3433 * </p> 3434 * 3435 * <p> 3436 * <pre> 3437 * <code> 3438 * shorten("12345678901234567890xyz", "... etc.") returns "123456789012... etc." 3439 * shorten("1 345678901234567890xyz", "... etc.") returns "1... etc." 3440 * shorten(" 2345678901234567890xyz", "... etc.") returns "... etc." 3441 * shorten("12345678901234567890", "... etc.") returns "12345678901234567890" 3442 * shorten(" 2345678901234567890", "... etc.") returns " 2345678901234567890" 3443 * </code> 3444 * </pre> 3445 * </p> 3446 * 3447 * @param s the original string 3448 * @param suffix the suffix to append 3449 * @return a string representing the original string shortened to 20 3450 * characters, with the specified suffix appended to it 3451 */ 3452 public static String shorten(String s, String suffix) { 3453 return shorten(s, 20, suffix); 3454 } 3455 3456 /** 3457 * Splits string <code>s</code> around comma characters. 3458 * 3459 * <p> 3460 * Examples: 3461 * </p> 3462 * 3463 * <p> 3464 * <pre> 3465 * <code> 3466 * split("Alice,Bob,Charlie") returns {"Alice", "Bob", "Charlie"} 3467 * split("Alice, Bob, Charlie") returns {"Alice", " Bob", " Charlie"} 3468 * </code> 3469 * </pre> 3470 * </p> 3471 * 3472 * @param s the string to split 3473 * @return the array of strings resulting from splitting string 3474 * <code>s</code> around comma characters, or an empty string array 3475 * if <code>s</code> is <code>null</code> or <code>s</code> is empty 3476 */ 3477 public static String[] split(String s) { 3478 return split(s, CharPool.COMMA); 3479 } 3480 3481 /** 3482 * Splits the string <code>s</code> around comma characters returning the 3483 * boolean values of the substrings. 3484 * 3485 * @param s the string to split 3486 * @param x the default value to use for a substring in case an exception 3487 * occurs in getting the boolean value for that substring 3488 * @return the array of boolean values resulting from splitting string 3489 * <code>s</code> around comma characters, or an empty array if 3490 * <code>s</code> is <code>null</code> 3491 */ 3492 public static boolean[] split(String s, boolean x) { 3493 return split(s, StringPool.COMMA, x); 3494 } 3495 3496 /** 3497 * Splits the string <code>s</code> around the specified delimiter. 3498 * 3499 * <p> 3500 * Example: 3501 * </p> 3502 * 3503 * <p> 3504 * <pre> 3505 * <code> 3506 * splitLines("First;Second;Third", ';') returns {"First","Second","Third"} 3507 * </code> 3508 * </pre> 3509 * </p> 3510 * 3511 * @param s the string to split 3512 * @param delimiter the delimiter 3513 * @return the array of strings resulting from splitting string 3514 * <code>s</code> around the specified delimiter character, or an 3515 * empty string array if <code>s</code> is <code>null</code> or if 3516 * <code>s</code> is empty 3517 */ 3518 public static String[] split(String s, char delimiter) { 3519 if (Validator.isNull(s)) { 3520 return _emptyStringArray; 3521 } 3522 3523 s = s.trim(); 3524 3525 if (s.length() == 0) { 3526 return _emptyStringArray; 3527 } 3528 3529 if ((delimiter == CharPool.RETURN) || 3530 (delimiter == CharPool.NEW_LINE)) { 3531 3532 return splitLines(s); 3533 } 3534 3535 List<String> nodeValues = new ArrayList<>(); 3536 3537 int offset = 0; 3538 int pos = s.indexOf(delimiter, offset); 3539 3540 while (pos != -1) { 3541 nodeValues.add(s.substring(offset, pos)); 3542 3543 offset = pos + 1; 3544 pos = s.indexOf(delimiter, offset); 3545 } 3546 3547 if (offset < s.length()) { 3548 nodeValues.add(s.substring(offset)); 3549 } 3550 3551 return nodeValues.toArray(new String[nodeValues.size()]); 3552 } 3553 3554 /** 3555 * Splits the string <code>s</code> around comma characters returning the 3556 * double-precision decimal values of the substrings. 3557 * 3558 * @param s the string to split 3559 * @param x the default value to use for a substring in case an exception 3560 * occurs in getting the double-precision decimal value for that 3561 * substring 3562 * @return the array of double-precision decimal values resulting from 3563 * splitting string <code>s</code> around comma characters, or an 3564 * empty array if <code>s</code> is <code>null</code> 3565 */ 3566 public static double[] split(String s, double x) { 3567 return split(s, StringPool.COMMA, x); 3568 } 3569 3570 /** 3571 * Splits the string <code>s</code> around comma characters returning the 3572 * decimal values of the substrings. 3573 * 3574 * @param s the string to split 3575 * @param x the default value to use for a substring in case an exception 3576 * occurs in getting the decimal value for that substring 3577 * @return the array of decimal values resulting from splitting string 3578 * <code>s</code> around comma characters, or an empty array if 3579 * <code>s</code> is <code>null</code> 3580 */ 3581 public static float[] split(String s, float x) { 3582 return split(s, StringPool.COMMA, x); 3583 } 3584 3585 /** 3586 * Splits the string <code>s</code> around comma characters returning the 3587 * integer values of the substrings. 3588 * 3589 * @param s the string to split 3590 * @param x the default value to use for a substring in case an exception 3591 * occurs in getting the integer value for that substring 3592 * @return the array of integer values resulting from splitting string 3593 * <code>s</code> around comma characters, or an empty array if 3594 * <code>s</code> is <code>null</code> 3595 */ 3596 public static int[] split(String s, int x) { 3597 return split(s, StringPool.COMMA, x); 3598 } 3599 3600 /** 3601 * Splits the string <code>s</code> around comma characters returning the 3602 * long integer values of the substrings. 3603 * 3604 * @param s the string to split 3605 * @param x the default value to use for a substring in case an exception 3606 * occurs in getting the long integer value for that substring 3607 * @return the array of long integer values resulting from splitting string 3608 * <code>s</code> around comma characters, or an empty array if 3609 * <code>s</code> is <code>null</code> 3610 */ 3611 public static long[] split(String s, long x) { 3612 return split(s, StringPool.COMMA, x); 3613 } 3614 3615 /** 3616 * Splits the string <code>s</code> around comma characters returning the 3617 * short integer values of the substrings. 3618 * 3619 * @param s the string to split 3620 * @param x the default value to use for a substring in case an exception 3621 * occurs in getting the short integer value for that substring 3622 * @return the array of short integer values resulting from splitting string 3623 * <code>s</code> around comma characters, or an empty array if 3624 * <code>s</code> is <code>null</code> 3625 */ 3626 public static short[] split(String s, short x) { 3627 return split(s, StringPool.COMMA, x); 3628 } 3629 3630 /** 3631 * Splits the string <code>s</code> around the specified delimiter string. 3632 * 3633 * <p> 3634 * Example: 3635 * </p> 3636 * 3637 * <p> 3638 * <pre> 3639 * <code> 3640 * splitLines("oneandtwoandthreeandfour", "and") returns {"one","two","three","four"} 3641 * </code> 3642 * </pre> 3643 * </p> 3644 * 3645 * @param s the string to split 3646 * @param delimiter the delimiter 3647 * @return the array of strings resulting from splitting string 3648 * <code>s</code> around the specified delimiter string, or an empty 3649 * string array if <code>s</code> is <code>null</code> or equals the 3650 * delimiter 3651 */ 3652 public static String[] split(String s, String delimiter) { 3653 if (Validator.isNull(s) || (delimiter == null) || 3654 delimiter.equals(StringPool.BLANK)) { 3655 3656 return _emptyStringArray; 3657 } 3658 3659 s = s.trim(); 3660 3661 if (s.equals(delimiter)) { 3662 return _emptyStringArray; 3663 } 3664 3665 if (delimiter.length() == 1) { 3666 return split(s, delimiter.charAt(0)); 3667 } 3668 3669 List<String> nodeValues = new ArrayList<>(); 3670 3671 int offset = 0; 3672 int pos = s.indexOf(delimiter, offset); 3673 3674 while (pos != -1) { 3675 nodeValues.add(s.substring(offset, pos)); 3676 3677 offset = pos + delimiter.length(); 3678 pos = s.indexOf(delimiter, offset); 3679 } 3680 3681 if (offset < s.length()) { 3682 nodeValues.add(s.substring(offset)); 3683 } 3684 3685 return nodeValues.toArray(new String[nodeValues.size()]); 3686 } 3687 3688 /** 3689 * Splits the string <code>s</code> around the specified delimiter returning 3690 * the boolean values of the substrings. 3691 * 3692 * @param s the string to split 3693 * @param delimiter the delimiter 3694 * @param x the default value to use for a substring in case an exception 3695 * occurs in getting the boolean value for that substring 3696 * @return the array of booleans resulting from splitting string 3697 * <code>s</code> around the specified delimiter string, or an empty 3698 * array if <code>s</code> is <code>null</code> 3699 */ 3700 public static boolean[] split(String s, String delimiter, boolean x) { 3701 String[] array = split(s, delimiter); 3702 boolean[] newArray = new boolean[array.length]; 3703 3704 for (int i = 0; i < array.length; i++) { 3705 boolean value = x; 3706 3707 try { 3708 value = Boolean.valueOf(array[i]).booleanValue(); 3709 } 3710 catch (Exception e) { 3711 } 3712 3713 newArray[i] = value; 3714 } 3715 3716 return newArray; 3717 } 3718 3719 /** 3720 * Splits the string <code>s</code> around the specified delimiter returning 3721 * the double-precision decimal values of the substrings. 3722 * 3723 * @param s the string to split 3724 * @param delimiter the delimiter 3725 * @param x the default value to use for a substring in case an exception 3726 * occurs in getting the double-precision decimal value for that 3727 * substring 3728 * @return the array of double-precision decimal values resulting from 3729 * splitting string <code>s</code> around the specified delimiter 3730 * string, or an empty array if <code>s</code> is <code>null</code> 3731 */ 3732 public static double[] split(String s, String delimiter, double x) { 3733 String[] array = split(s, delimiter); 3734 double[] newArray = new double[array.length]; 3735 3736 for (int i = 0; i < array.length; i++) { 3737 double value = x; 3738 3739 try { 3740 value = Double.parseDouble(array[i]); 3741 } 3742 catch (Exception e) { 3743 } 3744 3745 newArray[i] = value; 3746 } 3747 3748 return newArray; 3749 } 3750 3751 /** 3752 * Splits the string <code>s</code> around the specified delimiter returning 3753 * the decimal values of the substrings. 3754 * 3755 * @param s the string to split 3756 * @param delimiter the delimiter 3757 * @param x the default value to use for a substring in case an exception 3758 * occurs in getting the decimal value for that substring 3759 * @return the array of decimal values resulting from splitting string 3760 * <code>s</code> around the specified delimiter string, or an empty 3761 * array if <code>s</code> is <code>null</code> 3762 */ 3763 public static float[] split(String s, String delimiter, float x) { 3764 String[] array = split(s, delimiter); 3765 float[] newArray = new float[array.length]; 3766 3767 for (int i = 0; i < array.length; i++) { 3768 float value = x; 3769 3770 try { 3771 value = Float.parseFloat(array[i]); 3772 } 3773 catch (Exception e) { 3774 } 3775 3776 newArray[i] = value; 3777 } 3778 3779 return newArray; 3780 } 3781 3782 /** 3783 * Splits the string <code>s</code> around the specified delimiter returning 3784 * the integer values of the substrings. 3785 * 3786 * @param s the string to split 3787 * @param delimiter the delimiter 3788 * @param x the default value to use for a substring in case an exception 3789 * occurs in getting the integer value for that substring 3790 * @return the array of integer values resulting from splitting string 3791 * <code>s</code> around the specified delimiter string, or an empty 3792 * array if <code>s</code> is <code>null</code> 3793 */ 3794 public static int[] split(String s, String delimiter, int x) { 3795 String[] array = split(s, delimiter); 3796 int[] newArray = new int[array.length]; 3797 3798 for (int i = 0; i < array.length; i++) { 3799 int value = x; 3800 3801 try { 3802 value = Integer.parseInt(array[i]); 3803 } 3804 catch (Exception e) { 3805 } 3806 3807 newArray[i] = value; 3808 } 3809 3810 return newArray; 3811 } 3812 3813 /** 3814 * Splits the string <code>s</code> around the specified delimiter returning 3815 * the long integer values of the substrings. 3816 * 3817 * @param s the string to split 3818 * @param delimiter the delimiter 3819 * @param x the default value to use for a substring in case an exception 3820 * occurs in getting the long integer value for that substring 3821 * @return the array of long integer values resulting from splitting string 3822 * <code>s</code> around the specified delimiter string, or an empty 3823 * array if <code>s</code> is <code>null</code> 3824 */ 3825 public static long[] split(String s, String delimiter, long x) { 3826 String[] array = split(s, delimiter); 3827 long[] newArray = new long[array.length]; 3828 3829 for (int i = 0; i < array.length; i++) { 3830 long value = x; 3831 3832 try { 3833 value = Long.parseLong(array[i]); 3834 } 3835 catch (Exception e) { 3836 } 3837 3838 newArray[i] = value; 3839 } 3840 3841 return newArray; 3842 } 3843 3844 /** 3845 * Splits the string <code>s</code> around the specified delimiter returning 3846 * the short integer values of the substrings. 3847 * 3848 * @param s the string to split 3849 * @param delimiter the delimiter 3850 * @param x the default value to use for a substring in case an exception 3851 * occurs in getting the short integer value for that substring 3852 * @return the array of short integer values resulting from splitting string 3853 * <code>s</code> around the specified delimiter string, or an empty 3854 * array if <code>s</code> is <code>null</code> 3855 */ 3856 public static short[] split(String s, String delimiter, short x) { 3857 String[] array = split(s, delimiter); 3858 short[] newArray = new short[array.length]; 3859 3860 for (int i = 0; i < array.length; i++) { 3861 short value = x; 3862 3863 try { 3864 value = Short.parseShort(array[i]); 3865 } 3866 catch (Exception e) { 3867 } 3868 3869 newArray[i] = value; 3870 } 3871 3872 return newArray; 3873 } 3874 3875 /** 3876 * Splits string <code>s</code> around return and newline characters. 3877 * 3878 * <p> 3879 * Example: 3880 * </p> 3881 * 3882 * <p> 3883 * <pre> 3884 * <code> 3885 * splitLines("Red\rBlue\nGreen") returns {"Red","Blue","Green"} 3886 * </code> 3887 * </pre> 3888 * </p> 3889 * 3890 * @param s the string to split 3891 * @return the array of strings resulting from splitting string 3892 * <code>s</code> around return and newline characters, or an empty 3893 * string array if string <code>s</code> is <code>null</code> 3894 */ 3895 public static String[] splitLines(String s) { 3896 if (Validator.isNull(s)) { 3897 return _emptyStringArray; 3898 } 3899 3900 s = s.trim(); 3901 3902 List<String> lines = new ArrayList<>(); 3903 3904 int lastIndex = 0; 3905 3906 while (true) { 3907 int returnIndex = s.indexOf(CharPool.RETURN, lastIndex); 3908 int newLineIndex = s.indexOf(CharPool.NEW_LINE, lastIndex); 3909 3910 if ((returnIndex == -1) && (newLineIndex == -1)) { 3911 break; 3912 } 3913 3914 if (returnIndex == -1) { 3915 lines.add(s.substring(lastIndex, newLineIndex)); 3916 3917 lastIndex = newLineIndex + 1; 3918 } 3919 else if (newLineIndex == -1) { 3920 lines.add(s.substring(lastIndex, returnIndex)); 3921 3922 lastIndex = returnIndex + 1; 3923 } 3924 else if (newLineIndex < returnIndex) { 3925 lines.add(s.substring(lastIndex, newLineIndex)); 3926 3927 lastIndex = newLineIndex + 1; 3928 } 3929 else { 3930 lines.add(s.substring(lastIndex, returnIndex)); 3931 3932 lastIndex = returnIndex + 1; 3933 3934 if (lastIndex == newLineIndex) { 3935 lastIndex++; 3936 } 3937 } 3938 } 3939 3940 if (lastIndex < s.length()) { 3941 lines.add(s.substring(lastIndex)); 3942 } 3943 3944 return lines.toArray(new String[lines.size()]); 3945 } 3946 3947 /** 3948 * Returns <code>true</code> if, ignoring case, the string starts with the 3949 * specified character. 3950 * 3951 * @param s the string 3952 * @param begin the character against which the initial character of the 3953 * string is to be compared 3954 * @return <code>true</code> if, ignoring case, the string starts with the 3955 * specified character; <code>false</code> otherwise 3956 */ 3957 public static boolean startsWith(String s, char begin) { 3958 return startsWith(s, (Character.valueOf(begin)).toString()); 3959 } 3960 3961 /** 3962 * Returns <code>true</code> if, ignoring case, the string starts with the 3963 * specified start string. 3964 * 3965 * @param s the original string 3966 * @param start the string against which the beginning of string 3967 * <code>s</code> are to be compared 3968 * @return <code>true</code> if, ignoring case, the string starts with the 3969 * specified start string; <code>false</code> otherwise 3970 */ 3971 public static boolean startsWith(String s, String start) { 3972 if ((s == null) || (start == null)) { 3973 return false; 3974 } 3975 3976 if (start.length() > s.length()) { 3977 return false; 3978 } 3979 3980 String temp = s.substring(0, start.length()); 3981 3982 if (equalsIgnoreCase(temp, start)) { 3983 return true; 3984 } 3985 else { 3986 return false; 3987 } 3988 } 3989 3990 /** 3991 * Returns the number of starting characters that <code>s1</code> and 3992 * <code>s2</code> have in common before their characters deviate. 3993 * 3994 * @param s1 string 1 3995 * @param s2 string 2 3996 * @return the number of starting characters that <code>s1</code> and 3997 * <code>s2</code> have in common before their characters deviate 3998 */ 3999 public static int startsWithWeight(String s1, String s2) { 4000 if ((s1 == null) || (s2 == null)) { 4001 return 0; 4002 } 4003 4004 char[] chars1 = s1.toCharArray(); 4005 char[] chars2 = s2.toCharArray(); 4006 4007 int i = 0; 4008 4009 for (; (i < chars1.length) && (i < chars2.length); i++) { 4010 if (chars1[i] != chars2[i]) { 4011 break; 4012 } 4013 } 4014 4015 return i; 4016 } 4017 4018 /** 4019 * Returns a string representing the string <code>s</code> with all 4020 * occurrences of the specified character removed. 4021 * 4022 * <p> 4023 * Example: 4024 * </p> 4025 * 4026 * <p> 4027 * <pre> 4028 * <code> 4029 * strip("Mississipi", 'i') returns "Mssssp" 4030 * </code> 4031 * </pre> 4032 * </p> 4033 * 4034 * @param s the string from which to strip all occurrences of the character 4035 * @param remove the character to strip from the string 4036 * @return a string representing the string <code>s</code> with all 4037 * occurrences of the specified character removed, or 4038 * <code>null</code> if <code>s</code> is <code>null</code> 4039 */ 4040 public static String strip(String s, char remove) { 4041 if (s == null) { 4042 return null; 4043 } 4044 4045 int x = s.indexOf(remove); 4046 4047 if (x < 0) { 4048 return s; 4049 } 4050 4051 int y = 0; 4052 4053 StringBundler sb = new StringBundler(s.length()); 4054 4055 while (x >= 0) { 4056 sb.append(s.subSequence(y, x)); 4057 4058 y = x + 1; 4059 4060 x = s.indexOf(remove, y); 4061 } 4062 4063 sb.append(s.substring(y)); 4064 4065 return sb.toString(); 4066 } 4067 4068 /** 4069 * Returns a string representing the string <code>s</code> with all 4070 * occurrences of the specified characters removed. 4071 * 4072 * <p> 4073 * Example: 4074 * </p> 4075 * 4076 * <p> 4077 * <pre> 4078 * <code> 4079 * strip("Hello World", {' ', 'l', 'd'}) returns "HeoWor" 4080 * </code> 4081 * </pre> 4082 * </p> 4083 * 4084 * @param s the string from which to strip all occurrences the characters 4085 * @param remove the characters to strip from the string 4086 * @return a string representing the string <code>s</code> with all 4087 * occurrences of the specified characters removed, or 4088 * <code>null</code> if <code>s</code> is <code>null</code> 4089 */ 4090 public static String strip(String s, char[] remove) { 4091 for (char c : remove) { 4092 s = strip(s, c); 4093 } 4094 4095 return s; 4096 } 4097 4098 /** 4099 * Returns a string representing the combination of the substring of 4100 * <code>s</code> up to but not including the string <code>begin</code> 4101 * concatenated with the substring of <code>s</code> after but not including 4102 * the string <code>end</code>. 4103 * 4104 * <p> 4105 * Example: 4106 * </p> 4107 * 4108 * <p> 4109 * <pre> 4110 * <code> 4111 * stripBetween("One small step for man, one giant leap for mankind", "step", "giant ") returns "One small leap for mankind" 4112 * </code> 4113 * </pre> 4114 * </p> 4115 * 4116 * @param s the string from which to strip a substring 4117 * @param begin the beginning characters of the substring to be removed 4118 * @param end the ending characters of the substring to be removed 4119 * @return a string representing the combination of the substring of 4120 * <code>s</code> up to but not including the string 4121 * <code>begin</code> concatenated with the substring of 4122 * <code>s</code> after but not including the string 4123 * <code>end</code>, or the original string if the value of 4124 * <code>s</code>, <code>begin</code>, or <code>end</code> are 4125 * <code>null</code> 4126 */ 4127 public static String stripBetween(String s, String begin, String end) { 4128 if (Validator.isBlank(s) || Validator.isBlank(begin) || 4129 Validator.isBlank(end)) { 4130 4131 return s; 4132 } 4133 4134 StringBundler sb = new StringBundler(s.length()); 4135 4136 int pos = 0; 4137 4138 while (true) { 4139 int x = s.indexOf(begin, pos); 4140 int y = s.indexOf(end, x + begin.length()); 4141 4142 if ((x == -1) || (y == -1)) { 4143 sb.append(s.substring(pos)); 4144 4145 break; 4146 } 4147 else { 4148 sb.append(s.substring(pos, x)); 4149 4150 pos = y + end.length(); 4151 } 4152 } 4153 4154 return sb.toString(); 4155 } 4156 4157 /** 4158 * Returns a string representing the string <code>s</code> with its 4159 * <code><![CDATA[]]></code> wrapper removed. 4160 * 4161 * <p> 4162 * Example: 4163 * </p> 4164 * 4165 * <p> 4166 * <pre> 4167 * <code> 4168 * stripCDATA("<![CDATA[One small step for man]]>") returns "One small step for man" 4169 * </code> 4170 * </pre> 4171 * </p> 4172 * 4173 * @param s the string from which to strip its CDATA wrapper 4174 * @return a string representing the string <code>s</code> with its 4175 * <code><![CDATA[]]></code> wrapper removed, or 4176 * <code>null</code> if <code>s</code> is <code>null</code> 4177 */ 4178 public static String stripCDATA(String s) { 4179 if (s == null) { 4180 return s; 4181 } 4182 4183 if (s.startsWith(StringPool.CDATA_OPEN) && 4184 s.endsWith(StringPool.CDATA_CLOSE)) { 4185 4186 s = s.substring( 4187 StringPool.CDATA_OPEN.length(), 4188 s.length() - StringPool.CDATA_CLOSE.length()); 4189 } 4190 4191 return s; 4192 } 4193 4194 /** 4195 * Returns a string representing the string <code>s</code> without an 4196 * appended parenthetical suffix. If there is not a space directly before 4197 * the opening parenthesis, the parenthetical suffix is not stripped. 4198 * 4199 * <p> 4200 * Examples: 4201 * </p> 4202 * 4203 * <p> 4204 * <pre> 4205 * <code> 4206 * stripParentheticalSuffix("file") returns "file" 4207 * stripParentheticalSuffix("file (0)") returns "file" 4208 * stripParentheticalSuffix("file (0 0)") returns "file" 4209 * stripParentheticalSuffix("file(0)") returns "file(0)" 4210 * </code> 4211 * </pre> 4212 * </p> 4213 * 4214 * @param s the string from which to strip its parenthetical suffix 4215 * @return a string representing the string <code>s</code> without an 4216 * appended parenthetical suffix 4217 */ 4218 public static String stripParentheticalSuffix(String s) { 4219 int x = s.lastIndexOf(StringPool.OPEN_PARENTHESIS); 4220 int y = s.lastIndexOf(StringPool.CLOSE_PARENTHESIS); 4221 4222 if ((x == -1) || (y == -1)) { 4223 return s; 4224 } 4225 4226 if ((x > y) || !s.endsWith(StringPool.CLOSE_PARENTHESIS)) { 4227 return s; 4228 } 4229 4230 if (s.charAt(x - 1) != CharPool.SPACE) { 4231 return s; 4232 } 4233 4234 return s.substring(0, x - 1).concat(s.substring(y + 1, s.length())); 4235 } 4236 4237 /** 4238 * Returns a string representing the Unicode character codes of the 4239 * characters comprising the string <code>s</code>. 4240 * 4241 * <p> 4242 * Examples: 4243 * </p> 4244 * 4245 * <p> 4246 * <pre> 4247 * <code> 4248 * toCharCode("a") returns "97" 4249 * toCharCode("b") returns "98" 4250 * toCharCode("c") returns "99" 4251 * toCharCode("What's for lunch?") returns "87104971163911532102111114321081171109910463" 4252 * </code> 4253 * </pre> 4254 * </p> 4255 * 4256 * @param s the string whose character codes are to be represented 4257 * @return a string representing the Unicode character codes of the 4258 * characters comprising the string <code>s</code> 4259 */ 4260 public static String toCharCode(String s) { 4261 StringBundler sb = new StringBundler(s.length()); 4262 4263 for (int i = 0; i < s.length(); i++) { 4264 sb.append(s.codePointAt(i)); 4265 } 4266 4267 return sb.toString(); 4268 } 4269 4270 /** 4271 * Returns a string representing the hexidecimal character code of the 4272 * integer. 4273 * 4274 * <p> 4275 * Examples: 4276 * </p> 4277 * 4278 * <p> 4279 * <pre> 4280 * <code> 4281 * toHexString(10) returns "a" 4282 * toHexString(15) returns "f" 4283 * toHexString(10995) returns "2af3" 4284 * </code> 4285 * </pre> 4286 * </p> 4287 * 4288 * @param i the integer to convert 4289 * @return a string representing the hexidecimal character code of the 4290 * integer 4291 */ 4292 public static String toHexString(int i) { 4293 char[] buffer = new char[8]; 4294 4295 int index = 8; 4296 4297 do { 4298 buffer[--index] = HEX_DIGITS[i & 15]; 4299 4300 i >>>= 4; 4301 } 4302 while (i != 0); 4303 4304 return new String(buffer, index, 8 - index); 4305 } 4306 4307 /** 4308 * Returns a string representing the hexidecimal character code of the long 4309 * integer. 4310 * 4311 * <p> 4312 * Example: 4313 * </p> 4314 * 4315 * <p> 4316 * <pre> 4317 * <code> 4318 * toHexString(12345678910L) returns "2dfdc1c3e" 4319 * </code> 4320 * </pre> 4321 * </p> 4322 * 4323 * @param l the long integer to convert 4324 * @return a string representing the hexidecimal character code of the long 4325 * integer 4326 */ 4327 public static String toHexString(long l) { 4328 char[] buffer = new char[16]; 4329 4330 int index = 16; 4331 4332 do { 4333 buffer[--index] = HEX_DIGITS[(int) (l & 15)]; 4334 4335 l >>>= 4; 4336 } 4337 while (l != 0); 4338 4339 return new String(buffer, index, 16 - index); 4340 } 4341 4342 /** 4343 * Returns a string representing the hexidecimal character code of the 4344 * <code>Integer</code> or <code>Long</code> object type. If the object is 4345 * not an instance of these types, the object's original value is returned. 4346 * 4347 * @param obj the object to convert 4348 * @return a string representing the hexidecimal character code of the 4349 * object 4350 */ 4351 public static String toHexString(Object obj) { 4352 if (obj instanceof Integer) { 4353 return toHexString(((Integer)obj).intValue()); 4354 } 4355 else if (obj instanceof Long) { 4356 return toHexString(((Long)obj).longValue()); 4357 } 4358 else { 4359 return String.valueOf(obj); 4360 } 4361 } 4362 4363 /** 4364 * Converts all of the characters in the string to lower case, based on the 4365 * portal instance's default locale. 4366 * 4367 * @param s the string to convert 4368 * @return the string, converted to lower case, or <code>null</code> if the 4369 * string is <code>null</code> 4370 */ 4371 public static String toLowerCase(String s) { 4372 return toLowerCase(s, null); 4373 } 4374 4375 /** 4376 * Converts all of the characters in the string to lower case, based on the 4377 * locale. 4378 * 4379 * @param s the string to convert 4380 * @param locale apply this locale's rules 4381 * @return the string, converted to lower case, or <code>null</code> if the 4382 * string is <code>null</code> 4383 * @see GetterUtil#_toLowerCase 4384 */ 4385 public static String toLowerCase(String s, Locale locale) { 4386 if (s == null) { 4387 return null; 4388 } 4389 4390 StringBuilder sb = null; 4391 4392 for (int i = 0; i < s.length(); i++) { 4393 char c = s.charAt(i); 4394 4395 if (c > 127) { 4396 4397 // Found non-ascii char, fallback to the slow unicode detection 4398 4399 if (locale == null) { 4400 locale = LocaleUtil.getDefault(); 4401 } 4402 4403 return s.toLowerCase(locale); 4404 } 4405 4406 if ((c >= 'A') && (c <= 'Z')) { 4407 if (sb == null) { 4408 sb = new StringBuilder(s); 4409 } 4410 4411 sb.setCharAt(i, (char)(c + 32)); 4412 } 4413 } 4414 4415 if (sb == null) { 4416 return s; 4417 } 4418 4419 return sb.toString(); 4420 } 4421 4422 /** 4423 * Converts all of the characters in the string to upper case, based on the 4424 * portal instance's default locale. 4425 * 4426 * @param s the string to convert 4427 * @return the string, converted to upper case, or <code>null</code> if the 4428 * string is <code>null</code> 4429 */ 4430 public static String toUpperCase(String s) { 4431 return toUpperCase(s, null); 4432 } 4433 4434 /** 4435 * Converts all of the characters in the string to upper case, based on the 4436 * locale. 4437 * 4438 * @param s the string to convert 4439 * @param locale apply this locale's rules 4440 * @return the string, converted to upper case, or <code>null</code> if the 4441 * string is <code>null</code> 4442 */ 4443 public static String toUpperCase(String s, Locale locale) { 4444 if (s == null) { 4445 return null; 4446 } 4447 4448 StringBuilder sb = null; 4449 4450 for (int i = 0; i < s.length(); i++) { 4451 char c = s.charAt(i); 4452 4453 if (c > 127) { 4454 4455 // Found non-ascii char, fallback to the slow unicode detection 4456 4457 if (locale == null) { 4458 locale = LocaleUtil.getDefault(); 4459 } 4460 4461 return s.toUpperCase(locale); 4462 } 4463 4464 if ((c >= 'a') && (c <= 'z')) { 4465 if (sb == null) { 4466 sb = new StringBuilder(s); 4467 } 4468 4469 sb.setCharAt(i, (char)(c - 32)); 4470 } 4471 } 4472 4473 if (sb == null) { 4474 return s; 4475 } 4476 4477 return sb.toString(); 4478 } 4479 4480 /** 4481 * Trims all leading and trailing whitespace from the string. 4482 * 4483 * @param s the original string 4484 * @return a string representing the original string with all leading and 4485 * trailing whitespace removed 4486 */ 4487 public static String trim(String s) { 4488 if (s == null) { 4489 return null; 4490 } 4491 4492 if (s.length() == 0) { 4493 return s; 4494 } 4495 4496 int len = s.length(); 4497 4498 int x = len; 4499 4500 for (int i = 0; i < len; i++) { 4501 char c = s.charAt(i); 4502 4503 if (!Character.isWhitespace(c)) { 4504 x = i; 4505 4506 break; 4507 } 4508 } 4509 4510 if (x == len) { 4511 return StringPool.BLANK; 4512 } 4513 4514 int y = x + 1; 4515 4516 for (int i = len - 1; i > x; i--) { 4517 char c = s.charAt(i); 4518 4519 if (!Character.isWhitespace(c)) { 4520 y = i + 1; 4521 4522 break; 4523 } 4524 } 4525 4526 if ((x == 0) && (y == len)) { 4527 return s; 4528 } 4529 4530 return s.substring(x, y); 4531 } 4532 4533 /** 4534 * Trims leading and trailing whitespace from the string, up to but not 4535 * including the whitespace character specified by <code>c</code>. 4536 * 4537 * <p> 4538 * Examples: 4539 * </p> 4540 * 4541 * <p> 4542 * <pre> 4543 * <code> 4544 * trim(" \tHey\t ", '\t') returns "\tHey\t" 4545 * trim(" \t Hey \t ", '\t') returns "\t Hey \t" 4546 * </code> 4547 * </pre> 4548 * </p> 4549 * 4550 * @param s the original string 4551 * @param c the whitespace character to limit trimming 4552 * @return a string representing the original string with leading and 4553 * trailing whitespace removed, up to but not including the 4554 * whitespace character specified by <code>c</code> 4555 */ 4556 public static String trim(String s, char c) { 4557 return trim(s, new char[] {c}); 4558 } 4559 4560 /** 4561 * Trims leading and trailing whitespace from the string, up to but not 4562 * including the whitespace characters specified by <code>exceptions</code>. 4563 * 4564 * @param s the original string 4565 * @param exceptions the whitespace characters to limit trimming 4566 * @return a string representing the original string with leading and 4567 * trailing whitespace removed, up to but not including the 4568 * whitespace characters specified by <code>exceptions</code> 4569 */ 4570 public static String trim(String s, char[] exceptions) { 4571 if (s == null) { 4572 return null; 4573 } 4574 4575 if (s.length() == 0) { 4576 return s; 4577 } 4578 4579 if (ArrayUtil.isEmpty(exceptions)) { 4580 return trim(s); 4581 } 4582 4583 int len = s.length(); 4584 int x = len; 4585 4586 for (int i = 0; i < len; i++) { 4587 char c = s.charAt(i); 4588 4589 if (!_isTrimable(c, exceptions)) { 4590 x = i; 4591 4592 break; 4593 } 4594 } 4595 4596 if (x == len) { 4597 return StringPool.BLANK; 4598 } 4599 4600 int y = x + 1; 4601 4602 for (int i = len - 1; i > x; i--) { 4603 char c = s.charAt(i); 4604 4605 if (!_isTrimable(c, exceptions)) { 4606 y = i + 1; 4607 4608 break; 4609 } 4610 } 4611 4612 if ((x == 0) && (y == len)) { 4613 return s; 4614 } 4615 else { 4616 return s.substring(x, y); 4617 } 4618 } 4619 4620 /** 4621 * Trims all leading whitespace from the string. 4622 * 4623 * @param s the original string 4624 * @return a string representing the original string with all leading 4625 * whitespace removed 4626 */ 4627 public static String trimLeading(String s) { 4628 if (s == null) { 4629 return null; 4630 } 4631 4632 if (s.length() == 0) { 4633 return s; 4634 } 4635 4636 int len = s.length(); 4637 int x = len; 4638 4639 for (int i = 0; i < len; i++) { 4640 char c = s.charAt(i); 4641 4642 if (!Character.isWhitespace(c)) { 4643 x = i; 4644 4645 break; 4646 } 4647 } 4648 4649 if (x == len) { 4650 return StringPool.BLANK; 4651 } 4652 else if (x == 0) { 4653 return s; 4654 } 4655 else { 4656 return s.substring(x); 4657 } 4658 } 4659 4660 /** 4661 * Trims leading whitespace from the string, up to but not including the 4662 * whitespace character specified by <code>c</code>. 4663 * 4664 * @param s the original string 4665 * @param c the whitespace character to limit trimming 4666 * @return a string representing the original string with leading whitespace 4667 * removed, up to but not including the whitespace character 4668 * specified by <code>c</code> 4669 */ 4670 public static String trimLeading(String s, char c) { 4671 return trimLeading(s, new char[] {c}); 4672 } 4673 4674 /** 4675 * Trims leading whitespace from the string, up to but not including the 4676 * whitespace characters specified by <code>exceptions</code>. 4677 * 4678 * @param s the original string 4679 * @param exceptions the whitespace characters to limit trimming 4680 * @return a string representing the original string with leading whitespace 4681 * removed, up to but not including the whitespace characters 4682 * specified by <code>exceptions</code> 4683 */ 4684 public static String trimLeading(String s, char[] exceptions) { 4685 if (s == null) { 4686 return null; 4687 } 4688 4689 if (s.length() == 0) { 4690 return s; 4691 } 4692 4693 if (ArrayUtil.isEmpty(exceptions)) { 4694 return trimLeading(s); 4695 } 4696 4697 int len = s.length(); 4698 int x = len; 4699 4700 for (int i = 0; i < len; i++) { 4701 char c = s.charAt(i); 4702 4703 if (!_isTrimable(c, exceptions)) { 4704 x = i; 4705 4706 break; 4707 } 4708 } 4709 4710 if (x == len) { 4711 return StringPool.BLANK; 4712 } 4713 else if (x == 0) { 4714 return s; 4715 } 4716 else { 4717 return s.substring(x); 4718 } 4719 } 4720 4721 /** 4722 * Trims all trailing whitespace from the string. 4723 * 4724 * @param s the original string 4725 * @return a string representing the original string with all trailing 4726 * whitespace removed 4727 */ 4728 public static String trimTrailing(String s) { 4729 if (s == null) { 4730 return null; 4731 } 4732 4733 if (s.length() == 0) { 4734 return s; 4735 } 4736 4737 int len = s.length(); 4738 int x = 0; 4739 4740 for (int i = len - 1; i >= 0; i--) { 4741 char c = s.charAt(i); 4742 4743 if (!Character.isWhitespace(c)) { 4744 x = i + 1; 4745 4746 break; 4747 } 4748 } 4749 4750 if (x == 0) { 4751 return StringPool.BLANK; 4752 } 4753 else if (x == len) { 4754 return s; 4755 } 4756 else { 4757 return s.substring(0, x); 4758 } 4759 } 4760 4761 /** 4762 * Trims trailing whitespace from the string, up to but not including the 4763 * whitespace character specified by <code>c</code>. 4764 * 4765 * @param s the original string 4766 * @param c the whitespace character to limit trimming 4767 * @return a string representing the original string with trailing 4768 * whitespace removed, up to but not including the whitespace 4769 * character specified by <code>c</code> 4770 */ 4771 public static String trimTrailing(String s, char c) { 4772 return trimTrailing(s, new char[] {c}); 4773 } 4774 4775 /** 4776 * Trims trailing whitespace from the string, up to but not including the 4777 * whitespace characters specified by <code>exceptions</code>. 4778 * 4779 * @param s the original string 4780 * @param exceptions the whitespace characters to limit trimming 4781 * @return a string representing the original string with trailing 4782 * whitespace removed, up to but not including the whitespace 4783 * characters specified by <code>exceptions</code> 4784 */ 4785 public static String trimTrailing(String s, char[] exceptions) { 4786 if (s == null) { 4787 return null; 4788 } 4789 4790 if (s.length() == 0) { 4791 return s; 4792 } 4793 4794 if (ArrayUtil.isEmpty(exceptions)) { 4795 return trimTrailing(s); 4796 } 4797 4798 int len = s.length(); 4799 int x = 0; 4800 4801 for (int i = len - 1; i >= 0; i--) { 4802 char c = s.charAt(i); 4803 4804 if (!_isTrimable(c, exceptions)) { 4805 x = i + 1; 4806 4807 break; 4808 } 4809 } 4810 4811 if (x == 0) { 4812 return StringPool.BLANK; 4813 } 4814 else if (x == len) { 4815 return s; 4816 } 4817 else { 4818 return s.substring(0, x); 4819 } 4820 } 4821 4822 /** 4823 * Removes leading and trailing double and single quotation marks from the 4824 * string. 4825 * 4826 * @param s the original string 4827 * @return a string representing the original string with leading and 4828 * trailing double and single quotation marks removed, or the 4829 * original string if the original string is a <code>null</code> or 4830 * empty 4831 */ 4832 public static String unquote(String s) { 4833 if (Validator.isNull(s)) { 4834 return s; 4835 } 4836 4837 if ((s.charAt(0) == CharPool.APOSTROPHE) && 4838 (s.charAt(s.length() - 1) == CharPool.APOSTROPHE)) { 4839 4840 return s.substring(1, s.length() - 1); 4841 } 4842 else if ((s.charAt(0) == CharPool.QUOTE) && 4843 (s.charAt(s.length() - 1) == CharPool.QUOTE)) { 4844 4845 return s.substring(1, s.length() - 1); 4846 } 4847 4848 return s; 4849 } 4850 4851 /** 4852 * Converts all of the characters in the string to upper case. 4853 * 4854 * @param s the string to convert 4855 * @return the string, converted to upper-case, or <code>null</code> if the 4856 * string is <code>null</code> 4857 * @see String#toUpperCase() 4858 */ 4859 public static String upperCase(String s) { 4860 return toUpperCase(s); 4861 } 4862 4863 /** 4864 * Converts the first character of the string to upper case. 4865 * 4866 * @param s the string whose first character is to be converted 4867 * @return the string, with its first character converted to upper-case 4868 */ 4869 public static String upperCaseFirstLetter(String s) { 4870 char[] chars = s.toCharArray(); 4871 4872 if ((chars[0] >= 97) && (chars[0] <= 122)) { 4873 chars[0] = (char)(chars[0] - 32); 4874 } 4875 4876 return new String(chars); 4877 } 4878 4879 /** 4880 * Returns the string value of the object. 4881 * 4882 * @param obj the object whose string value is to be returned 4883 * @return the string value of the object 4884 * @see String#valueOf(Object obj) 4885 */ 4886 public static String valueOf(Object obj) { 4887 return String.valueOf(obj); 4888 } 4889 4890 /** 4891 * Returns <code>true</code> if the string matches the wildcard pattern. 4892 * 4893 * <p> 4894 * For example, with the following initialized variables: 4895 * </p> 4896 * 4897 * <p> 4898 * <pre> 4899 * <code> 4900 * String s = "*master"; 4901 * String wildcard = "/*m?st*"; 4902 * char singleWildcardCharacter = '?'; 4903 * char multipleWildcardCharacter = '*'; 4904 * char escapeWildcardCharacter = '/'; 4905 * boolean caseSensitive = false; 4906 * </code> 4907 * </pre> 4908 * </p> 4909 * 4910 * <p> 4911 * <code>wildcardMatches(s, wildcard, singleWildcardCharacter, 4912 * multipleWildcardCharacter, escapeWildcardCharacter, caseSensitive)</code> 4913 * returns <code>true</code> 4914 * </p> 4915 * 4916 * @param s the string to be checked 4917 * @param wildcard the wildcard pattern to match 4918 * @param singleWildcardCharacter the char used to match exactly one 4919 * character 4920 * @param multipleWildcardCharacter the char used to match <code>0</code> 4921 * or more characters 4922 * @param escapeWildcardCharacter the char placed in front of a wildcard 4923 * character to indicate that it should be interpreted as a regular 4924 * character 4925 * @param caseSensitive whether to use case sensitivity 4926 * @return <code>true</code> if the string matches the wildcard pattern; 4927 * <code>false</code> otherwise 4928 */ 4929 public static boolean wildcardMatches( 4930 String s, String wildcard, char singleWildcardCharacter, 4931 char multipleWildcardCharacter, char escapeWildcardCharacter, 4932 boolean caseSensitive) { 4933 4934 if (!caseSensitive) { 4935 s = toLowerCase(s); 4936 wildcard = toLowerCase(wildcard); 4937 } 4938 4939 // Update the wildcard, single whildcard character, and multiple 4940 // wildcard character so that they no longer have escaped wildcard 4941 // characters 4942 4943 int index = wildcard.indexOf(escapeWildcardCharacter); 4944 4945 if (index != -1) { 4946 4947 // Search for safe wildcard replacement 4948 4949 char newSingleWildcardCharacter = 0; 4950 4951 while (wildcard.indexOf(newSingleWildcardCharacter) != -1) { 4952 newSingleWildcardCharacter++; 4953 } 4954 4955 char newMultipleWildcardCharacter = 4956 (char)(newSingleWildcardCharacter + 1); 4957 4958 while (wildcard.indexOf(newMultipleWildcardCharacter) != -1) { 4959 newMultipleWildcardCharacter++; 4960 } 4961 4962 // Purify 4963 4964 StringBuilder sb = new StringBuilder(wildcard); 4965 4966 for (int i = 0; i < sb.length(); i++) { 4967 char c = sb.charAt(i); 4968 4969 if (c == escapeWildcardCharacter) { 4970 sb.deleteCharAt(i); 4971 } 4972 else if (c == singleWildcardCharacter) { 4973 sb.setCharAt(i, newSingleWildcardCharacter); 4974 } 4975 else if (c == multipleWildcardCharacter) { 4976 sb.setCharAt(i, newMultipleWildcardCharacter); 4977 } 4978 } 4979 4980 wildcard = sb.toString(); 4981 4982 singleWildcardCharacter = newSingleWildcardCharacter; 4983 multipleWildcardCharacter = newMultipleWildcardCharacter; 4984 } 4985 4986 // Align head 4987 4988 for (index = 0; index < s.length(); index++) { 4989 if (index >= wildcard.length()) { 4990 return false; 4991 } 4992 4993 char c = wildcard.charAt(index); 4994 4995 if (c == multipleWildcardCharacter) { 4996 break; 4997 } 4998 4999 if ((s.charAt(index) != c) && (c != singleWildcardCharacter)) { 5000 return false; 5001 } 5002 } 5003 5004 // Match body 5005 5006 int sIndex = index; 5007 int wildcardIndex = index; 5008 5009 int matchPoint = 0; 5010 int comparePoint = 0; 5011 5012 while (sIndex < s.length()) { 5013 if (wildcardIndex == wildcard.length()) { 5014 5015 // Wildcard exhausted before s 5016 5017 return false; 5018 } 5019 5020 char c = wildcard.charAt(wildcardIndex); 5021 5022 if (c == multipleWildcardCharacter) { 5023 if (++wildcardIndex == wildcard.length()) { 5024 return true; 5025 } 5026 5027 matchPoint = wildcardIndex; 5028 comparePoint = sIndex + 1; 5029 } 5030 else if ((c == s.charAt(sIndex)) || 5031 (c == singleWildcardCharacter)) { 5032 5033 sIndex++; 5034 wildcardIndex++; 5035 } 5036 else { 5037 wildcardIndex = matchPoint; 5038 sIndex = comparePoint++; 5039 } 5040 } 5041 5042 // Match tail 5043 5044 while (wildcardIndex < wildcard.length()) { 5045 if (wildcard.charAt(wildcardIndex) != multipleWildcardCharacter) { 5046 break; 5047 } 5048 5049 wildcardIndex++; 5050 } 5051 5052 if (wildcardIndex == wildcard.length()) { 5053 return true; 5054 } 5055 else { 5056 return false; 5057 } 5058 } 5059 5060 /** 5061 * Wraps the text when it exceeds the <code>80</code> column width limit, 5062 * using a {@link StringPool#NEW_LINE} to break each wrapped line. 5063 * 5064 * @param text the text to wrap 5065 * @return the wrapped text following the column width limit, or 5066 * <code>null</code> if the text is <code>null</code> 5067 */ 5068 public static String wrap(String text) { 5069 return wrap(text, 80, StringPool.NEW_LINE); 5070 } 5071 5072 /** 5073 * Wraps the text when it exceeds the column width limit, using the line 5074 * separator to break each wrapped line. 5075 * 5076 * @param text the text to wrap 5077 * @param width the column width limit for the text 5078 * @param lineSeparator the string to use in breaking each wrapped line 5079 * @return the wrapped text and line separators, following the column width 5080 * limit, or <code>null</code> if the text is <code>null</code> 5081 */ 5082 public static String wrap(String text, int width, String lineSeparator) { 5083 try { 5084 return _wrap(text, width, lineSeparator); 5085 } 5086 catch (IOException ioe) { 5087 _log.error(ioe.getMessage()); 5088 5089 return text; 5090 } 5091 } 5092 5093 protected static final char[] HEX_DIGITS = { 5094 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 5095 'e', 'f' 5096 }; 5097 5098 /** 5099 * Returns <code>false</code> if the character is not whitespace or is equal 5100 * to any of the exception characters. 5101 * 5102 * @param c the character whose trim-ability is to be determined 5103 * @param exceptions the whitespace characters to exclude from trimming 5104 * @return <code>false</code> if the character is not whitespace or is equal 5105 * to any of the exception characters; <code>true</code> otherwise 5106 */ 5107 private static boolean _isTrimable(char c, char[] exceptions) { 5108 for (char exception : exceptions) { 5109 if (c == exception) { 5110 return false; 5111 } 5112 } 5113 5114 return Character.isWhitespace(c); 5115 } 5116 5117 private static String _wrap(String text, int width, String lineSeparator) 5118 throws IOException { 5119 5120 if (text == null) { 5121 return null; 5122 } 5123 5124 StringBundler sb = new StringBundler(); 5125 5126 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader( 5127 new UnsyncStringReader(text)); 5128 5129 String s = StringPool.BLANK; 5130 5131 while ((s = unsyncBufferedReader.readLine()) != null) { 5132 if (s.length() == 0) { 5133 sb.append(lineSeparator); 5134 5135 continue; 5136 } 5137 5138 int lineLength = 0; 5139 5140 String[] tokens = s.split(StringPool.SPACE); 5141 5142 for (String token : tokens) { 5143 if ((lineLength + token.length() + 1) > width) { 5144 if (lineLength > 0) { 5145 sb.append(lineSeparator); 5146 } 5147 5148 if (token.length() > width) { 5149 int pos = token.indexOf(CharPool.OPEN_PARENTHESIS); 5150 5151 if (pos != -1) { 5152 sb.append(token.substring(0, pos + 1)); 5153 sb.append(lineSeparator); 5154 5155 token = token.substring(pos + 1); 5156 5157 sb.append(token); 5158 5159 lineLength = token.length(); 5160 } 5161 else { 5162 sb.append(token); 5163 5164 lineLength = token.length(); 5165 } 5166 } 5167 else { 5168 sb.append(token); 5169 5170 lineLength = token.length(); 5171 } 5172 } 5173 else { 5174 if (lineLength > 0) { 5175 sb.append(StringPool.SPACE); 5176 5177 lineLength++; 5178 } 5179 5180 sb.append(token); 5181 5182 lineLength += token.length(); 5183 } 5184 } 5185 5186 sb.append(lineSeparator); 5187 } 5188 5189 return sb.toString(); 5190 } 5191 5192 private static final char[] _RANDOM_STRING_CHAR_TABLE = { 5193 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 5194 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 5195 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 5196 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 5197 'u', 'v', 'w', 'x', 'y', 'z' 5198 }; 5199 5200 private static final Log _log = LogFactoryUtil.getLog(StringUtil.class); 5201 5202 private static final String[] _emptyStringArray = new String[0]; 5203 5204 }