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