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