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