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    
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.InputStreamReader;
025    
026    import java.net.URL;
027    
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.Enumeration;
031    import java.util.List;
032    import java.util.Map;
033    import java.util.StringTokenizer;
034    import java.util.regex.Matcher;
035    import java.util.regex.Pattern;
036    
037    /**
038     * The String utility class.
039     *
040     * @author Brian Wing Shun Chan
041     * @author Sandeep Soni
042     * @author Ganesh Ram
043     * @author Shuyang Zhou
044     */
045    public class StringUtil {
046    
047            /**
048             * Adds string <code>add</code> to string <code>s</code> resulting in a
049             * comma delimited list of strings, disallowing duplicate strings in the
050             * list.
051             *
052             * <p>
053             * The resulting string ends with a comma even if the original string does
054             * not.
055             * </p>
056             *
057             * @param  s the original string, representing a comma delimited list of
058             *         strings
059             * @param  add the string to add to the original, representing the string to
060             *         add to the list
061             * @return a string that represents the original string and the added string
062             *         separated by a comma, or <code>null</code> if the string to add
063             *         is <code>null</code>
064             */
065            public static String add(String s, String add) {
066                    return add(s, add, StringPool.COMMA);
067            }
068    
069            /**
070             * Adds string <code>add</code> to string <code>s</code> that represents a
071             * delimited list of strings, using a specified delimiter and disallowing
072             * duplicate words.
073             *
074             * <p>
075             * The returned string ends with the delimiter even if the original string
076             * does not.
077             * </p>
078             *
079             * @param  s the original string, representing a delimited list of strings
080             * @param  add the string to add to the original, representing the string to
081             *         add to the list
082             * @param  delimiter the delimiter used to separate strings in the list
083             * @return a string that represents the original string and the added string
084             *         separated by the delimiter, or <code>null</code> if the string to
085             *         add or the delimiter string is <code>null</code>
086             */
087            public static String add(String s, String add, String delimiter) {
088                    return add(s, add, delimiter, false);
089            }
090    
091            /**
092             * Adds string <code>add</code> to string <code>s</code> that represents a
093             * delimited list of strings, using a specified delimiter and optionally
094             * allowing duplicate words.
095             *
096             * <p>
097             * The returned string ends with the delimiter even if the original string
098             * does not.
099             * </p>
100             *
101             * @param  s the original string, representing a delimited list of strings
102             * @param  add the string to add to the original, representing the string to
103             *         add to the list
104             * @param  delimiter the delimiter used to separate strings in the list
105             * @param  allowDuplicates whether to allow duplicate strings
106             * @return a string that represents the original string and the added string
107             *         separated by the delimiter, or <code>null</code> if the string to
108             *         add or the delimiter string is <code>null</code>
109             */
110            public static String add(
111                    String s, String add, String delimiter, boolean allowDuplicates) {
112    
113                    if ((add == null) || (delimiter == null)) {
114                            return null;
115                    }
116    
117                    if (s == null) {
118                            s = StringPool.BLANK;
119                    }
120    
121                    if (allowDuplicates || !contains(s, add, delimiter)) {
122                            StringBundler sb = new StringBundler();
123    
124                            sb.append(s);
125    
126                            if (Validator.isNull(s) || s.endsWith(delimiter)) {
127                                    sb.append(add);
128                                    sb.append(delimiter);
129                            }
130                            else {
131                                    sb.append(delimiter);
132                                    sb.append(add);
133                                    sb.append(delimiter);
134                            }
135    
136                            s = sb.toString();
137                    }
138    
139                    return s;
140            }
141    
142            /**
143             * Returns the original string with an appended space followed by the string
144             * value of the suffix surrounded by parentheses.
145             *
146             * <p>
147             * If the original string ends with a numerical parenthetical suffix having
148             * an integer value equal to <code>suffix - 1</code>, then the existing
149             * parenthetical suffix is replaced by the new one.
150             * </p>
151             *
152             * <p>
153             * Examples:
154             * </p>
155             *
156             * <p>
157             * <pre>
158             * <code>
159             * appendParentheticalSuffix("file", 0) returns "file (0)"
160             * appendParentheticalSuffix("file (0)", 0) returns "file (0) (0)"
161             * appendParentheticalSuffix("file (0)", 1) returns "file (1)"
162             * appendParentheticalSuffix("file (0)", 2) returns "file (0) (2)"
163             * </code>
164             * </pre>
165             * </p>
166             *
167             * @param  s the original string
168             * @param  suffix the suffix to be appended
169             * @return the resultant string whose characters equal those of the original
170             *         string, followed by a space, followed by the specified suffix
171             *         enclosed in parentheses, or, if the difference between the
172             *         provided suffix and the existing suffix is 1, the existing suffix
173             *         is incremented by 1
174             */
175            public static String appendParentheticalSuffix(String s, int suffix) {
176                    if (Pattern.matches(".* \\(" + String.valueOf(suffix - 1) + "\\)", s)) {
177                            int pos = s.lastIndexOf(" (");
178    
179                            s = s.substring(0, pos);
180                    }
181    
182                    return appendParentheticalSuffix(s, String.valueOf(suffix));
183            }
184    
185            /**
186             * Returns the original string with an appended space followed by the suffix
187             * surrounded by parentheses.
188             *
189             * <p>
190             * Example:
191             * </p>
192             *
193             * <p>
194             * <pre>
195             * <code>
196             * appendParentheticalSuffix("Java", "EE") returns "Java (EE)"
197             * </code>
198             * </pre>
199             * </p>
200             *
201             * @param  s the original string
202             * @param  suffix the suffix to be appended
203             * @return a string that represents the original string, followed by a
204             *         space, followed by the suffix enclosed in parentheses
205             */
206            public static String appendParentheticalSuffix(String s, String suffix) {
207                    StringBundler sb = new StringBundler(5);
208    
209                    sb.append(s);
210                    sb.append(StringPool.SPACE);
211                    sb.append(StringPool.OPEN_PARENTHESIS);
212                    sb.append(suffix);
213                    sb.append(StringPool.CLOSE_PARENTHESIS);
214    
215                    return sb.toString();
216            }
217    
218            /**
219             * Converts an array of bytes to a string representing the bytes in
220             * hexadecimal form.
221             *
222             * @param  bytes the array of bytes to be converted
223             * @return the string representing the bytes in hexadecimal form
224             */
225            public static String bytesToHexString(byte[] bytes) {
226                    StringBundler sb = new StringBundler(bytes.length * 2);
227    
228                    for (byte b : bytes) {
229                            String hex = Integer.toHexString(
230                                    0x0100 + (b & 0x00FF)).substring(1);
231    
232                            if (hex.length() < 2) {
233                                    sb.append("0");
234                            }
235    
236                            sb.append(hex);
237                    }
238    
239                    return sb.toString();
240            }
241    
242            /**
243             * Returns <code>true</code> if the string contains the text as a comma
244             * delimited list entry.
245             *
246             * <p>
247             * Example:
248             * </p>
249             *
250             * <p>
251             * <pre>
252             * <code>
253             * contains("one,two,three", "two") returns true
254             * contains("one,two,three", "thr") returns false
255             * </code>
256             * </pre>
257             * </p>
258             *
259             * @param  s the string in which to search
260             * @param  text the text to search for in the string
261             * @return <code>true</code> if the string contains the text as a comma
262             *         delimited list entry; <code>false</code> otherwise
263             */
264            public static boolean contains(String s, String text) {
265                    return contains(s, text, StringPool.COMMA);
266            }
267    
268            /**
269             * Returns <code>true</code> if the string contains the text as a delimited
270             * list entry.
271             *
272             * <p>
273             * Examples:
274             * </p>
275             *
276             * <p>
277             * <pre>
278             * <code>
279             * contains("three...two...one", "two", "...") returns true
280             * contains("three...two...one", "thr", "...") returns false
281             * </code>
282             * </pre>
283             * </p>
284             *
285             * @param  s the string in which to search
286             * @param  text the text to search for in the string
287             * @param  delimiter the delimiter
288             * @return <code>true</code> if the string contains the text as a delimited
289             *         list entry; <code>false</code> otherwise
290             */
291            public static boolean contains(String s, String text, String delimiter) {
292                    if ((s == null) || (text == null) || (delimiter == null)) {
293                            return false;
294                    }
295    
296                    if (!s.endsWith(delimiter)) {
297                            s = s.concat(delimiter);
298                    }
299    
300                    String dtd = delimiter.concat(text).concat(delimiter);
301    
302                    int pos = s.indexOf(dtd);
303    
304                    if (pos == -1) {
305                            String td = text.concat(delimiter);
306    
307                            if (s.startsWith(td)) {
308                                    return true;
309                            }
310    
311                            return false;
312                    }
313    
314                    return true;
315            }
316    
317            /**
318             * Returns the number of times the text appears in the string.
319             *
320             * @param  s the string in which to search
321             * @param  text the text to search for in the string
322             * @return the number of times the text appears in the string
323             */
324            public static int count(String s, String text) {
325                    if ((s == null) || (s.length() == 0) || (text == null) ||
326                            (text.length() == 0)) {
327    
328                            return 0;
329                    }
330    
331                    int count = 0;
332    
333                    int pos = s.indexOf(text);
334    
335                    while (pos != -1) {
336                            pos = s.indexOf(text, pos + text.length());
337    
338                            count++;
339                    }
340    
341                    return count;
342            }
343    
344            /**
345             * Returns <code>true</code> if the string ends with the specified
346             * character.
347             *
348             * @param  s the string in which to search
349             * @param  end the character to search for at the end of the string
350             * @return <code>true</code> if the string ends with the specified
351             *         character; <code>false</code> otherwise
352             */
353            public static boolean endsWith(String s, char end) {
354                    return endsWith(s, (new Character(end)).toString());
355            }
356    
357            /**
358             * Returns <code>true</code> if the string ends with the string
359             * <code>end</code>.
360             *
361             * @param  s the string in which to search
362             * @param  end the string to check for at the end of the string
363             * @return <code>true</code> if the string ends with the string
364             *         <code>end</code>; <code>false</code> otherwise
365             */
366            public static boolean endsWith(String s, String end) {
367                    if ((s == null) || (end == null)) {
368                            return false;
369                    }
370    
371                    if (end.length() > s.length()) {
372                            return false;
373                    }
374    
375                    String temp = s.substring(s.length() - end.length());
376    
377                    if (temp.equalsIgnoreCase(end)) {
378                            return true;
379                    }
380                    else {
381                            return false;
382                    }
383            }
384    
385            /**
386             * Returns the substring of each character instance in string <code>s</code>
387             * that is found in the character array <code>chars</code>. The substring of
388             * characters returned maintain their original order.
389             *
390             * @param  s the string from which to extract characters
391             * @param  chars the characters to extract from the string
392             * @return the substring of each character instance in string <code>s</code>
393             *         that is found in the character array <code>chars</code>, or an
394             *         empty string if the given string is <code>null</code>
395             */
396            public static String extract(String s, char[] chars) {
397                    if (s == null) {
398                            return StringPool.BLANK;
399                    }
400    
401                    StringBundler sb = new StringBundler();
402    
403                    for (char c1 : s.toCharArray()) {
404                            for (char c2 : chars) {
405                                    if (c1 == c2) {
406                                            sb.append(c1);
407    
408                                            break;
409                                    }
410                            }
411                    }
412    
413                    return sb.toString();
414            }
415    
416            /**
417             * Returns the substring of English characters from the string.
418             *
419             * @param  s the string from which to extract characters
420             * @return the substring of English characters from the string, or an empty
421             *         string if the given string is <code>null</code>
422             */
423            public static String extractChars(String s) {
424                    if (s == null) {
425                            return StringPool.BLANK;
426                    }
427    
428                    StringBundler sb = new StringBundler();
429    
430                    char[] chars = s.toCharArray();
431    
432                    for (char c : chars) {
433                            if (Validator.isChar(c)) {
434                                    sb.append(c);
435                            }
436                    }
437    
438                    return sb.toString();
439            }
440    
441            /**
442             * Returns a string consisting of all of the digits extracted from the
443             * string.
444             *
445             * @param  s the string from which to extract digits
446             * @return a string consisting of all of the digits extracted from the
447             *         string
448             */
449            public static String extractDigits(String s) {
450                    if (s == null) {
451                            return StringPool.BLANK;
452                    }
453    
454                    StringBundler sb = new StringBundler();
455    
456                    char[] chars = s.toCharArray();
457    
458                    for (char c : chars) {
459                            if (Validator.isDigit(c)) {
460                                    sb.append(c);
461                            }
462                    }
463    
464                    return sb.toString();
465            }
466    
467            /**
468             * Returns the substring of <code>s</code> up to but not including the first
469             * occurrence of the delimiter.
470             *
471             * @param  s the string from which to extract a substring
472             * @param  delimiter the character whose index in the string marks where to
473             *         end the substring
474             * @return the substring of <code>s</code> up to but not including the first
475             *         occurrence of the delimiter, <code>null</code> if the string is
476             *         <code>null</code> or the delimiter does not occur in the string
477             */
478            public static String extractFirst(String s, char delimiter) {
479                    if (s == null) {
480                            return null;
481                    }
482                    else {
483                            int index = s.indexOf(delimiter);
484    
485                            if (index < 0) {
486                                    return null;
487                            }
488                            else {
489                                    return s.substring(0, index);
490                            }
491                    }
492            }
493    
494            /**
495             * Returns the substring of <code>s</code> up to but not including the first
496             * occurrence of the delimiter.
497             *
498             * @param  s the string from which to extract a substring
499             * @param  delimiter the smaller string whose index in the larger string
500             *         marks where to end the substring
501             * @return the substring of <code>s</code> up to but not including the first
502             *         occurrence of the delimiter, <code>null</code> if the string is
503             *         <code>null</code> or the delimiter does not occur in the string
504             */
505            public static String extractFirst(String s, String delimiter) {
506                    if (s == null) {
507                            return null;
508                    }
509                    else {
510                            int index = s.indexOf(delimiter);
511    
512                            if (index < 0) {
513                                    return null;
514                            }
515                            else {
516                                    return s.substring(0, index);
517                            }
518                    }
519            }
520    
521            /**
522             * Returns the substring of <code>s</code> after but not including the last
523             * occurrence of the delimiter.
524             *
525             * @param  s the string from which to extract the substring
526             * @param  delimiter the character whose last index in the string marks
527             *         where to begin the substring
528             * @return the substring of <code>s</code> after but not including the last
529             *         occurrence of the delimiter, <code>null</code> if the string is
530             *         <code>null</code> or the delimiter does not occur in the string
531             */
532            public static String extractLast(String s, char delimiter) {
533                    if (s == null) {
534                            return null;
535                    }
536                    else {
537                            int index = s.lastIndexOf(delimiter);
538    
539                            if (index < 0) {
540                                    return null;
541                            }
542                            else {
543                                    return s.substring(index + 1);
544                            }
545                    }
546            }
547    
548            /**
549             * Returns the substring of <code>s</code> after but not including the last
550             * occurrence of the delimiter.
551             *
552             * @param  s the string from which to extract the substring
553             * @param  delimiter the string whose last index in the string marks where
554             *         to begin the substring
555             * @return the substring of <code>s</code> after but not including the last
556             *         occurrence of the delimiter, <code>null</code> if the string is
557             *         <code>null</code> or the delimiter does not occur in the string
558             */
559            public static String extractLast(String s, String delimiter) {
560                    if (s == null) {
561                            return null;
562                    }
563                    else {
564                            int index = s.lastIndexOf(delimiter);
565    
566                            if (index < 0) {
567                                    return null;
568                            }
569                            else {
570                                    return s.substring(index + delimiter.length());
571                            }
572                    }
573            }
574    
575            public static String extractLeadingDigits(String s) {
576                    if (s == null) {
577                            return StringPool.BLANK;
578                    }
579    
580                    StringBundler sb = new StringBundler();
581    
582                    char[] chars = s.toCharArray();
583    
584                    for (char c : chars) {
585                            if (Validator.isDigit(c)) {
586                                    sb.append(c);
587                            }
588                            else {
589                                    return sb.toString();
590                            }
591                    }
592    
593                    return sb.toString();
594            }
595    
596            /**
597             * @deprecated
598             */
599            public static String highlight(String s, String keywords) {
600                    return highlight(s, keywords, "<span class=\"highlight\">", "</span>");
601            }
602    
603            /**
604             * @deprecated
605             */
606            public static String highlight(
607                    String s, String keywords, String highlight1, String highlight2) {
608    
609                    if (Validator.isNull(s) || Validator.isNull(keywords)) {
610                            return s;
611                    }
612    
613                    Pattern pattern = Pattern.compile(
614                            Pattern.quote(keywords), Pattern.CASE_INSENSITIVE);
615    
616                    return _highlight(s, pattern, highlight1, highlight2);
617            }
618    
619            public static String highlight(String s, String[] queryTerms) {
620                    return highlight(
621                            s, queryTerms, "<span class=\"highlight\">", "</span>");
622            }
623    
624            public static String highlight(
625                    String s, String[] queryTerms, String highlight1, String highlight2) {
626    
627                    if (Validator.isNull(s) || Validator.isNull(queryTerms)) {
628                            return s;
629                    }
630    
631                    if (queryTerms.length == 0) {
632                            return StringPool.BLANK;
633                    }
634    
635                    StringBundler sb = new StringBundler(2 * queryTerms.length - 1);
636    
637                    for (int i = 0; i < queryTerms.length; i++) {
638                            sb.append(Pattern.quote(queryTerms[i].trim()));
639    
640                            if ((i + 1) < queryTerms.length) {
641                                    sb.append(StringPool.PIPE);
642                            }
643                    }
644    
645                    int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
646    
647                    Pattern pattern = Pattern.compile(sb.toString(), flags);
648    
649                    return _highlight(s, pattern, highlight1, highlight2);
650            }
651    
652            /**
653             * Inserts one string into the other at the specified offset index.
654             *
655             * @param  s the original string
656             * @param  insert the string to be inserted into the original string
657             * @param  offset the index of the original string where the insertion
658             *         should take place
659             * @return a string representing the original string with the other string
660             *         inserted at the specified offset index, or <code>null</code> if
661             *         the original string is <code>null</code>
662             */
663            public static String insert(String s, String insert, int offset) {
664                    if (s == null) {
665                            return null;
666                    }
667    
668                    if (insert == null) {
669                            return s;
670                    }
671    
672                    if (offset > s.length()) {
673                            return s.concat(insert);
674                    }
675                    else {
676                            String prefix = s.substring(0, offset);
677                            String postfix = s.substring(offset);
678    
679                            return prefix.concat(insert).concat(postfix);
680                    }
681            }
682    
683            /**
684             * Converts all of the characters in the string to lower case.
685             *
686             * @param  s the string to convert
687             * @return the string, converted to lowercase, or <code>null</code> if the
688             *         string is <code>null</code>
689             * @see    {@link String#toLowerCase()}
690             */
691            public static String lowerCase(String s) {
692                    if (s == null) {
693                            return null;
694                    }
695                    else {
696                            return s.toLowerCase();
697                    }
698            }
699    
700            public static void lowerCase(String... array) {
701                    if (array != null) {
702                            for (int i = 0; i < array.length; i++) {
703                                    array[i] = array[i].toLowerCase();
704                            }
705                    }
706            }
707    
708            /**
709             * Returns <code>true</code> if the specified pattern occurs at any position
710             * in the string.
711             *
712             * @param  s the string
713             * @param  pattern the pattern to search for in the string
714             * @return <code>true</code> if the specified pattern occurs at any position
715             *         in the string
716             */
717            public static boolean matches(String s, String pattern) {
718                    String[] array = pattern.split("\\*");
719    
720                    for (String element : array) {
721                            int pos = s.indexOf(element);
722    
723                            if (pos == -1) {
724                                    return false;
725                            }
726    
727                            s = s.substring(pos + element.length());
728                    }
729    
730                    return true;
731            }
732    
733            /**
734             * Returns <code>true</code> if the specified pattern occurs at any position
735             * in the string, ignoring case.
736             *
737             * @param  s the string
738             * @param  pattern the pattern to search for in the string
739             * @return <code>true</code> if the specified pattern occurs at any position
740             *         in the string
741             */
742            public static boolean matchesIgnoreCase(String s, String pattern) {
743                    return matches(lowerCase(s), lowerCase(pattern));
744            }
745    
746            /**
747             * Merges the elements of the boolean array into a string representing a
748             * comma delimited list of its values.
749             *
750             * @param  array the boolean values to merge
751             * @return a string representing a comma delimited list of the values of the
752             *         boolean array, an empty string if the array is empty, or
753             *         <code>null</code> if the array is <code>null</code>
754             */
755            public static String merge(boolean[] array) {
756                    return merge(array, StringPool.COMMA);
757            }
758    
759            /**
760             * Merges the elements of the boolean array into a string representing a
761             * delimited list of its values.
762             *
763             * @param  array the boolean values to merge
764             * @param  delimiter the delimiter
765             * @return a string representing a comma delimited list of the values of the
766             *         boolean array, an empty string if the array is empty, or
767             *         <code>null</code> if the array is <code>null</code>
768             */
769            public static String merge(boolean[] array, String delimiter) {
770                    if (array == null) {
771                            return null;
772                    }
773    
774                    if (array.length == 0) {
775                            return StringPool.BLANK;
776                    }
777    
778                    StringBundler sb = new StringBundler(2 * array.length - 1);
779    
780                    for (int i = 0; i < array.length; i++) {
781                            sb.append(String.valueOf(array[i]).trim());
782    
783                            if ((i + 1) != array.length) {
784                                    sb.append(delimiter);
785                            }
786                    }
787    
788                    return sb.toString();
789            }
790    
791            /**
792             * Merges the elements of the character array into a string representing a
793             * comma delimited list of its values.
794             *
795             * @param  array the characters to merge
796             * @return a string representing a comma delimited list of the values of the
797             *         character array, an empty string if the array is empty, or
798             *         <code>null</code> if the array is <code>null</code>
799             */
800            public static String merge(char[] array) {
801                    return merge(array, StringPool.COMMA);
802            }
803    
804            /**
805             * Merges the elements of the character array into a string representing a
806             * delimited list of its values.
807             *
808             * @param  array the characters to merge
809             * @param  delimiter the delimiter
810             * @return a string representing a delimited list of the values of the
811             *         character array, an empty string if the array is empty, or
812             *         <code>null</code> if the array is <code>null</code>
813             */
814            public static String merge(char[] array, String delimiter) {
815                    if (array == null) {
816                            return null;
817                    }
818    
819                    if (array.length == 0) {
820                            return StringPool.BLANK;
821                    }
822    
823                    StringBundler sb = new StringBundler(2 * array.length - 1);
824    
825                    for (int i = 0; i < array.length; i++) {
826                            sb.append(String.valueOf(array[i]).trim());
827    
828                            if ((i + 1) != array.length) {
829                                    sb.append(delimiter);
830                            }
831                    }
832    
833                    return sb.toString();
834            }
835    
836            public static String merge(Collection<?> col) {
837                    return merge(col, StringPool.COMMA);
838            }
839    
840            public static String merge(Collection<?> col, String delimiter) {
841                    if (col == null) {
842                            return null;
843                    }
844    
845                    return merge(col.toArray(new Object[col.size()]), delimiter);
846            }
847    
848            /**
849             * Merges the elements of an array of double-precision decimal numbers by
850             * returning a string representing a comma delimited list of its values.
851             *
852             * @param  array the doubles to merge
853             * @return a string representing a comma delimited list of the values of the
854             *         array of double-precision decimal numbers, an empty string if the
855             *         array is empty, or <code>null</code> if the array is
856             *         <code>null</code>
857             */
858            public static String merge(double[] array) {
859                    return merge(array, StringPool.COMMA);
860            }
861    
862            /**
863             * Merges the elements of an array of double-precision decimal numbers by
864             * returning a string representing a delimited list of its values.
865             *
866             * @param  array the doubles to merge
867             * @param  delimiter the delimiter
868             * @return a string representing a delimited list of the values of the array
869             *         of double-precision decimal numbers, an empty string if the array
870             *         is empty, or <code>null</code> if the array is <code>null</code>
871             */
872            public static String merge(double[] array, String delimiter) {
873                    if (array == null) {
874                            return null;
875                    }
876    
877                    if (array.length == 0) {
878                            return StringPool.BLANK;
879                    }
880    
881                    StringBundler sb = new StringBundler(2 * array.length - 1);
882    
883                    for (int i = 0; i < array.length; i++) {
884                            sb.append(String.valueOf(array[i]).trim());
885    
886                            if ((i + 1) != array.length) {
887                                    sb.append(delimiter);
888                            }
889                    }
890    
891                    return sb.toString();
892            }
893    
894            /**
895             * Merges the elements of an array of decimal numbers into a string
896             * representing a comma delimited list of its values.
897             *
898             * @param  array the floats to merge
899             * @return a string representing a comma delimited list of the values of the
900             *         array of decimal numbers, an empty string if the array is empty,
901             *         or <code>null</code> if the array is <code>null</code>
902             */
903            public static String merge(float[] array) {
904                    return merge(array, StringPool.COMMA);
905            }
906    
907            /**
908             * Merges the elements of an array of decimal numbers into a string
909             * representing a delimited list of its values.
910             *
911             * @param  array the floats to merge
912             * @param  delimiter the delimiter
913             * @return a string representing a delimited list of the values of the array
914             *         of decimal numbers, an empty string if the array is empty, or
915             *         <code>null</code> if the array is <code>null</code>
916             */
917            public static String merge(float[] array, String delimiter) {
918                    if (array == null) {
919                            return null;
920                    }
921    
922                    if (array.length == 0) {
923                            return StringPool.BLANK;
924                    }
925    
926                    StringBundler sb = new StringBundler(2 * array.length - 1);
927    
928                    for (int i = 0; i < array.length; i++) {
929                            sb.append(String.valueOf(array[i]).trim());
930    
931                            if ((i + 1) != array.length) {
932                                    sb.append(delimiter);
933                            }
934                    }
935    
936                    return sb.toString();
937            }
938    
939            /**
940             * Merges the elements of an array of integers into a string representing a
941             * comma delimited list of its values.
942             *
943             * @param  array the integers to merge
944             * @return a string representing a comma delimited list of the values of the
945             *         array of integers, an empty string if the array is empty, or
946             *         <code>null</code> if the array is <code>null</code>
947             */
948            public static String merge(int[] array) {
949                    return merge(array, StringPool.COMMA);
950            }
951    
952            /**
953             * Merges the elements of an array of integers into a string representing a
954             * delimited list of its values.
955             *
956             * @param  array the integers to merge
957             * @param  delimiter the delimiter
958             * @return a string representing a delimited list of the values of the array
959             *         of integers, an empty string if the array is empty, or
960             *         <code>null</code> if the array is <code>null</code>
961             */
962            public static String merge(int[] array, String delimiter) {
963                    if (array == null) {
964                            return null;
965                    }
966    
967                    if (array.length == 0) {
968                            return StringPool.BLANK;
969                    }
970    
971                    StringBundler sb = new StringBundler(2 * array.length - 1);
972    
973                    for (int i = 0; i < array.length; i++) {
974                            sb.append(String.valueOf(array[i]).trim());
975    
976                            if ((i + 1) != array.length) {
977                                    sb.append(delimiter);
978                            }
979                    }
980    
981                    return sb.toString();
982            }
983    
984            /**
985             * Merges the elements of an array of long integers by returning a string
986             * representing a comma delimited list of its values.
987             *
988             * @param  array the long integers to merge
989             * @return a string representing a comma delimited list of the values of the
990             *         array of long integers, an empty string if the array is empty, or
991             *         <code>null</code> if the array is <code>null</code>
992             */
993            public static String merge(long[] array) {
994                    return merge(array, StringPool.COMMA);
995            }
996    
997            /**
998             * Merges the elements of an array of long integers by returning a string
999             * representing a delimited list of its values.
1000             *
1001             * @param  array the long integers to merge
1002             * @param  delimiter the delimiter
1003             * @return a string representing a delimited list of the values of the array
1004             *         of long integers, an empty string if the array is empty, or
1005             *         <code>null</code> if the array is <code>null</code>
1006             */
1007            public static String merge(long[] array, String delimiter) {
1008                    if (array == null) {
1009                            return null;
1010                    }
1011    
1012                    if (array.length == 0) {
1013                            return StringPool.BLANK;
1014                    }
1015    
1016                    StringBundler sb = new StringBundler(2 * array.length - 1);
1017    
1018                    for (int i = 0; i < array.length; i++) {
1019                            sb.append(String.valueOf(array[i]).trim());
1020    
1021                            if ((i + 1) != array.length) {
1022                                    sb.append(delimiter);
1023                            }
1024                    }
1025    
1026                    return sb.toString();
1027            }
1028    
1029            /**
1030             * Merges the elements of an array of objects into a string representing a
1031             * comma delimited list of the objects.
1032             *
1033             * @param  array the objects to merge
1034             * @return a string representing a comma delimited list of the objects, an
1035             *         empty string if the array is empty, or <code>null</code> if the
1036             *         array is <code>null</code>
1037             */
1038            public static String merge(Object[] array) {
1039                    return merge(array, StringPool.COMMA);
1040            }
1041    
1042            /**
1043             * Merges the elements of an array of objects into a string representing a
1044             * delimited list of the objects.
1045             *
1046             * @param  array the objects to merge
1047             * @param  delimiter the delimiter
1048             * @return a string representing a delimited list of the objects, an empty
1049             *         string if the array is empty, or <code>null</code> if the array
1050             *         is <code>null</code>
1051             */
1052            public static String merge(Object[] array, String delimiter) {
1053                    if (array == null) {
1054                            return null;
1055                    }
1056    
1057                    if (array.length == 0) {
1058                            return StringPool.BLANK;
1059                    }
1060    
1061                    StringBundler sb = new StringBundler(2 * array.length - 1);
1062    
1063                    for (int i = 0; i < array.length; i++) {
1064                            sb.append(String.valueOf(array[i]).trim());
1065    
1066                            if ((i + 1) != array.length) {
1067                                    sb.append(delimiter);
1068                            }
1069                    }
1070    
1071                    return sb.toString();
1072            }
1073    
1074            /**
1075             * Merges the elements of an array of short integers by returning a string
1076             * representing a comma delimited list of its values.
1077             *
1078             * @param  array the short integers to merge
1079             * @return a string representing a comma delimited list of the values of the
1080             *         array of short integers, an empty string if the array is empty,
1081             *         or <code>null</code> if the array is <code>null</code>
1082             */
1083            public static String merge(short[] array) {
1084                    return merge(array, StringPool.COMMA);
1085            }
1086    
1087            /**
1088             * Merges the elements of an array of short integers by returning a string
1089             * representing a delimited list of its values.
1090             *
1091             * @param  array the short integers to merge
1092             * @param  delimiter the delimiter
1093             * @return a string representing a delimited list of the values of the array
1094             *         of short integers, an empty string if the array is empty, or
1095             *         <code>null</code> if the array is <code>null</code>
1096             */
1097            public static String merge(short[] array, String delimiter) {
1098                    if (array == null) {
1099                            return null;
1100                    }
1101    
1102                    if (array.length == 0) {
1103                            return StringPool.BLANK;
1104                    }
1105    
1106                    StringBundler sb = new StringBundler(2 * array.length - 1);
1107    
1108                    for (int i = 0; i < array.length; i++) {
1109                            sb.append(String.valueOf(array[i]).trim());
1110    
1111                            if ((i + 1) != array.length) {
1112                                    sb.append(delimiter);
1113                            }
1114                    }
1115    
1116                    return sb.toString();
1117            }
1118    
1119            /**
1120             * Returns the string enclosed by apostrophes.
1121             *
1122             * <p>
1123             * Example:
1124             * </p>
1125             *
1126             * <p>
1127             * <pre>
1128             * <code>
1129             * quote("Hello, World!") returns "'Hello, World!'"
1130             * </code>
1131             * </pre>
1132             * </p>
1133             *
1134             * @param  s the string to enclose in apostrophes
1135             * @return the string enclosed by apostrophes, or <code>null</code> if the
1136             *         string is <code>null</code>
1137             */
1138            public static String quote(String s) {
1139                    return quote(s, CharPool.APOSTROPHE);
1140            }
1141    
1142            /**
1143             * Returns the string enclosed by the quote character.
1144             *
1145             * <p>
1146             * Example:
1147             * </p>
1148             *
1149             * <p>
1150             * <pre>
1151             * <code>
1152             * quote("PATH", '%') returns "%PATH%"
1153             * </code>
1154             * </pre>
1155             * </p>
1156             *
1157             * @param  s the string to enclose in quotes
1158             * @param  quote the character to insert to insert to the beginning of and
1159             *         append to the end of the string
1160             * @return the string enclosed in the quote characters, or <code>null</code>
1161             *         if the string is <code>null</code>
1162             */
1163            public static String quote(String s, char quote) {
1164                    if (s == null) {
1165                            return null;
1166                    }
1167    
1168                    return quote(s, String.valueOf(quote));
1169            }
1170    
1171            /**
1172             * Returns the string enclosed by the quote strings.
1173             *
1174             * <p>
1175             * Example:
1176             * </p>
1177             *
1178             * <p>
1179             * <pre>
1180             * <code>
1181             * quote("WARNING", "!!!") returns "!!!WARNING!!!"
1182             * </code>
1183             * </pre>
1184             * </p>
1185             *
1186             * @param  s the string to enclose in quotes
1187             * @param  quote the quote string to insert to insert to the beginning of
1188             *         and append to the end of the string
1189             * @return the string enclosed in the quote strings, or <code>null</code> if
1190             *         the string is <code>null</code>
1191             */
1192            public static String quote(String s, String quote) {
1193                    if (s == null) {
1194                            return null;
1195                    }
1196    
1197                    return quote.concat(s).concat(quote);
1198            }
1199    
1200            /**
1201             * Pseudorandomly permutes the characters of the string.
1202             *
1203             * @param  s the string whose characters are to be randomized
1204             * @return a string of the same length as the string whose characters
1205             *         represent a pseudorandom permutation of the characters of the
1206             *         string
1207             */
1208            public static String randomize(String s) {
1209                    return Randomizer.getInstance().randomize(s);
1210            }
1211    
1212            public static String read(ClassLoader classLoader, String name)
1213                    throws IOException {
1214    
1215                    return read(classLoader, name, false);
1216            }
1217    
1218            public static String read(ClassLoader classLoader, String name, boolean all)
1219                    throws IOException {
1220    
1221                    if (all) {
1222                            StringBundler sb = new StringBundler();
1223    
1224                            Enumeration<URL> enu = classLoader.getResources(name);
1225    
1226                            while (enu.hasMoreElements()) {
1227                                    URL url = enu.nextElement();
1228    
1229                                    InputStream is = url.openStream();
1230    
1231                                    if (is == null) {
1232                                            throw new IOException(
1233                                                    "Unable to open resource at " + url.toString());
1234                                    }
1235    
1236                                    String s = read(is);
1237    
1238                                    if (s != null) {
1239                                            sb.append(s);
1240                                            sb.append(StringPool.NEW_LINE);
1241                                    }
1242    
1243                                    is.close();
1244                            }
1245    
1246                            return sb.toString().trim();
1247                    }
1248                    else {
1249                            InputStream is = classLoader.getResourceAsStream(name);
1250    
1251                            if (is == null) {
1252                                    throw new IOException(
1253                                            "Unable to open resource in class loader " + name);
1254                            }
1255    
1256                            String s = read(is);
1257    
1258                            is.close();
1259    
1260                            return s;
1261                    }
1262            }
1263    
1264            public static String read(InputStream is) throws IOException {
1265                    StringBundler sb = new StringBundler();
1266    
1267                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
1268                            new InputStreamReader(is));
1269    
1270                    String line = null;
1271    
1272                    while ((line = unsyncBufferedReader.readLine()) != null) {
1273                            sb.append(line);
1274                            sb.append(CharPool.NEW_LINE);
1275                    }
1276    
1277                    unsyncBufferedReader.close();
1278    
1279                    return sb.toString().trim();
1280            }
1281    
1282            public static void readLines(InputStream is, Collection<String> lines)
1283                    throws IOException {
1284    
1285                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
1286                            new InputStreamReader(is));
1287    
1288                    String line = null;
1289    
1290                    while ((line = unsyncBufferedReader.readLine()) != null) {
1291                            lines.add(line);
1292                    }
1293    
1294                    unsyncBufferedReader.close();
1295            }
1296    
1297            /**
1298             * Removes the <code>remove</code> string from string <code>s</code> that
1299             * represents a list of comma delimited strings.
1300             *
1301             * <p>
1302             * The resulting string ends with a comma even if the original string does
1303             * not.
1304             * </p>
1305             *
1306             * <p>
1307             * Examples:
1308             * </p>
1309             *
1310             * <p>
1311             * <pre>
1312             * <code>
1313             * remove("red,blue,green,yellow", "blue") returns "red,green,yellow,"
1314             * remove("blue", "blue") returns ""
1315             * remove("blue,", "blue") returns ""
1316             * </code>
1317             * </pre>
1318             * </p>
1319             *
1320             * @param  s the string representing the list of comma delimited strings
1321             * @param  remove the string to remove
1322             * @return a string representing the list of comma delimited strings with
1323             *         the <code>remove</code> string removed, or <code>null</code> if
1324             *         the original string, the string to remove, or the delimiter is
1325             *         <code>null</code>
1326             */
1327            public static String remove(String s, String remove) {
1328                    return remove(s, remove, StringPool.COMMA);
1329            }
1330    
1331            /**
1332             * Removes the <code>remove</code> string from string <code>s</code> that
1333             * represents a list of delimited strings.
1334             *
1335             * <p>
1336             * The resulting string ends with the delimiter even if the original string
1337             * does not.
1338             * </p>
1339             *
1340             * <p>
1341             * Examples:
1342             * </p>
1343             *
1344             * <p>
1345             * <pre>
1346             * <code>
1347             * remove("red;blue;green;yellow", "blue", ";") returns "red;green;yellow;"
1348             * remove("blue", "blue", ";") returns ""
1349             * remove("blue;", "blue", ";") returns ""
1350             * </code>
1351             * </pre>
1352             * </p>
1353             *
1354             * @param  s the string representing the list of delimited strings
1355             * @param  remove the string to remove
1356             * @param  delimiter the delimiter
1357             * @return a string representing the list of delimited strings with the
1358             *         <code>remove</code> string removed, or <code>null</code> if the
1359             *         original string, the string to remove, or the delimiter is
1360             *         <code>null</code>
1361             */
1362            public static String remove(String s, String remove, String delimiter) {
1363                    if ((s == null) || (remove == null) || (delimiter == null)) {
1364                            return null;
1365                    }
1366    
1367                    if (Validator.isNotNull(s) && !s.endsWith(delimiter)) {
1368                            s += delimiter;
1369                    }
1370    
1371                    String drd = delimiter.concat(remove).concat(delimiter);
1372    
1373                    String rd = remove.concat(delimiter);
1374    
1375                    while (contains(s, remove, delimiter)) {
1376                            int pos = s.indexOf(drd);
1377    
1378                            if (pos == -1) {
1379                                    if (s.startsWith(rd)) {
1380                                            int x = remove.length() + delimiter.length();
1381                                            int y = s.length();
1382    
1383                                            s = s.substring(x, y);
1384                                    }
1385                            }
1386                            else {
1387                                    int x = pos + remove.length() + delimiter.length();
1388                                    int y = s.length();
1389    
1390                                    String temp = s.substring(0, pos);
1391    
1392                                    s = temp.concat(s.substring(x, y));
1393                            }
1394                    }
1395    
1396                    return s;
1397            }
1398    
1399            /**
1400             * Replaces all occurrences of the character with the new character.
1401             *
1402             * @param  s the original string
1403             * @param  oldSub the character to be searched for and replaced in the
1404             *         original string
1405             * @param  newSub the character with which to replace the
1406             *         <code>oldSub</code> character
1407             * @return a string representing the original string with all occurrences of
1408             *         the <code>oldSub</code> character replaced with the
1409             *         <code>newSub</code> character, or <code>null</code> if the
1410             *         original string is <code>null</code>
1411             */
1412            public static String replace(String s, char oldSub, char newSub) {
1413                    if (s == null) {
1414                            return null;
1415                    }
1416    
1417                    return s.replace(oldSub, newSub);
1418            }
1419    
1420            /**
1421             * Replaces all occurrences of the character with the new string.
1422             *
1423             * @param  s the original string
1424             * @param  oldSub the character to be searched for and replaced in the
1425             *         original string
1426             * @param  newSub the string with which to replace the <code>oldSub</code>
1427             *         character
1428             * @return a string representing the original string with all occurrences of
1429             *         the <code>oldSub</code> character replaced with the string
1430             *         <code>newSub</code>, or <code>null</code> if the original string
1431             *         is <code>null</code>
1432             */
1433            public static String replace(String s, char oldSub, String newSub) {
1434                    if ((s == null) || (newSub == null)) {
1435                            return null;
1436                    }
1437    
1438                    // The number 5 is arbitrary and is used as extra padding to reduce
1439                    // buffer expansion
1440    
1441                    StringBundler sb = new StringBundler(s.length() + 5 * newSub.length());
1442    
1443                    char[] chars = s.toCharArray();
1444    
1445                    for (char c : chars) {
1446                            if (c == oldSub) {
1447                                    sb.append(newSub);
1448                            }
1449                            else {
1450                                    sb.append(c);
1451                            }
1452                    }
1453    
1454                    return sb.toString();
1455            }
1456    
1457            /**
1458             * Replaces all occurrences of the string with the new string.
1459             *
1460             * @param  s the original string
1461             * @param  oldSub the string to be searched for and replaced in the original
1462             *         string
1463             * @param  newSub the string with which to replace the <code>oldSub</code>
1464             *         string
1465             * @return a string representing the original string with all occurrences of
1466             *         the <code>oldSub</code> string replaced with the string
1467             *         <code>newSub</code>, or <code>null</code> if the original string
1468             *         is <code>null</code>
1469             */
1470            public static String replace(String s, String oldSub, String newSub) {
1471                    return replace(s, oldSub, newSub, 0);
1472            }
1473    
1474            /**
1475             * Replaces all occurrences of the string with the new string, starting from
1476             * the specified index.
1477             *
1478             * @param  s the original string
1479             * @param  oldSub the string to be searched for and replaced in the original
1480             *         string
1481             * @param  newSub the string with which to replace the <code>oldSub</code>
1482             *         string
1483             * @param  fromIndex the index of the original string from which to begin
1484             *         searching
1485             * @return a string representing the original string with all occurrences of
1486             *         the <code>oldSub</code> string occurring after the specified
1487             *         index replaced with the string <code>newSub</code>, or
1488             *         <code>null</code> if the original string is <code>null</code>
1489             */
1490            public static String replace(
1491                    String s, String oldSub, String newSub, int fromIndex) {
1492    
1493                    if (s == null) {
1494                            return null;
1495                    }
1496    
1497                    if ((oldSub == null) || oldSub.equals(StringPool.BLANK)) {
1498                            return s;
1499                    }
1500    
1501                    if (newSub == null) {
1502                            newSub = StringPool.BLANK;
1503                    }
1504    
1505                    int y = s.indexOf(oldSub, fromIndex);
1506    
1507                    if (y >= 0) {
1508                            StringBundler sb = new StringBundler();
1509    
1510                            int length = oldSub.length();
1511                            int x = 0;
1512    
1513                            while (x <= y) {
1514                                    sb.append(s.substring(x, y));
1515                                    sb.append(newSub);
1516    
1517                                    x = y + length;
1518                                    y = s.indexOf(oldSub, x);
1519                            }
1520    
1521                            sb.append(s.substring(x));
1522    
1523                            return sb.toString();
1524                    }
1525                    else {
1526                            return s;
1527                    }
1528            }
1529    
1530            public static String replace(
1531                    String s, String begin, String end, Map<String, String> values) {
1532    
1533                    StringBundler sb = replaceToStringBundler(s, begin, end, values);
1534    
1535                    return sb.toString();
1536            }
1537    
1538            /**
1539             * Replaces all occurrences of the elements of the string array with the
1540             * corresponding elements of the new string array.
1541             *
1542             * @param  s the original string
1543             * @param  oldSubs the strings to be searched for and replaced in the
1544             *         original string
1545             * @param  newSubs the strings with which to replace the
1546             *         <code>oldSubs</code> strings
1547             * @return a string representing the original string with all occurrences of
1548             *         the <code>oldSubs</code> strings replaced with the corresponding
1549             *         <code>newSubs</code> strings, or <code>null</code> if the
1550             *         original string, the <code>oldSubs</code> array, or the
1551             *         <code>newSubs</code> is <code>null</code>
1552             */
1553            public static String replace(String s, String[] oldSubs, String[] newSubs) {
1554                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
1555                            return null;
1556                    }
1557    
1558                    if (oldSubs.length != newSubs.length) {
1559                            return s;
1560                    }
1561    
1562                    for (int i = 0; i < oldSubs.length; i++) {
1563                            s = replace(s, oldSubs[i], newSubs[i]);
1564                    }
1565    
1566                    return s;
1567            }
1568    
1569            /**
1570             * Replaces all occurrences of the elements of the string array with the
1571             * corresponding elements of the new string array, optionally replacing only
1572             * substrings that are surrounded by word boundaries.
1573             *
1574             * <p>
1575             * Examples:
1576             * </p>
1577             *
1578             * <p>
1579             * <pre>
1580             * <code>
1581             * replace("redorangeyellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "REDORANGEYELLOW"
1582             * replace("redorangeyellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, true) returns "redorangeyellow"
1583             * replace("redorange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "REDORANGE YELLOW"
1584             * replace("redorange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, true) returns "redorange YELLOW"
1585             * replace("red orange yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", "YELLOW"}, false) returns "RED ORANGE YELLOW"
1586             * replace("redorange.yellow", {"red", "orange", "yellow"}, {"RED","ORANGE", * "YELLOW"}, true) returns "redorange.YELLOW"
1587             * </code>
1588             * </pre>
1589             * </p>
1590             *
1591             * @param  s the original string
1592             * @param  oldSubs the strings to be searched for and replaced in the
1593             *         original string
1594             * @param  newSubs the strings with which to replace the
1595             *         <code>oldSubs</code> strings
1596             * @param  exactMatch whether or not to replace only substrings of
1597             *         <code>s</code> that are surrounded by word boundaries
1598             * @return if <code>exactMatch</code> is <code>true</code>, a string
1599             *         representing the original string with all occurrences of the
1600             *         <code>oldSubs</code> strings that are surrounded by word
1601             *         boundaries replaced with the corresponding <code>newSubs</code>
1602             *         strings, or else a string representing the original string with
1603             *         all occurrences of the <code>oldSubs</code> strings replaced with
1604             *         the corresponding <code>newSubs</code> strings, or
1605             *         <code>null</code> if the original string, the
1606             *         <code>oldSubs</code> array, or the <code>newSubs</code is
1607             *         <code>null</code>
1608             */
1609            public static String replace(
1610                    String s, String[] oldSubs, String[] newSubs, boolean exactMatch) {
1611    
1612                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
1613                            return null;
1614                    }
1615    
1616                    if (oldSubs.length != newSubs.length) {
1617                            return s;
1618                    }
1619    
1620                    if (!exactMatch) {
1621                            return replace(s, oldSubs, newSubs);
1622                    }
1623    
1624                    for (int i = 0; i < oldSubs.length; i++) {
1625                            s = s.replaceAll("\\b" + oldSubs[i] + "\\b", newSubs[i]);
1626                    }
1627    
1628                    return s;
1629            }
1630    
1631            /**
1632             * Replaces the first occurrence of the character with the new character.
1633             *
1634             * @param  s the original string
1635             * @param  oldSub the character whose first occurrence in the original
1636             *         string is to be searched for and replaced
1637             * @param  newSub the character with which to replace the first occurrence
1638             *         of the <code>oldSub</code> character
1639             * @return a string representing the original string except with the first
1640             *         occurrence of the character <code>oldSub</code> replaced with the
1641             *         character <code>newSub</code>
1642             */
1643            public static String replaceFirst(String s, char oldSub, char newSub) {
1644                    if (s == null) {
1645                            return null;
1646                    }
1647    
1648                    return replaceFirst(s, String.valueOf(oldSub), String.valueOf(newSub));
1649            }
1650    
1651            /**
1652             * Replaces the first occurrence of the character with the new string.
1653             *
1654             * @param  s the original string
1655             * @param  oldSub the character whose first occurrence in the original
1656             *         string is to be searched for and replaced
1657             * @param  newSub the string with which to replace the first occurrence of
1658             *         the <code>oldSub</code> character
1659             * @return a string representing the original string except with the first
1660             *         occurrence of the character <code>oldSub</code> replaced with the
1661             *         string <code>newSub</code>
1662             */
1663            public static String replaceFirst(String s, char oldSub, String newSub) {
1664                    if ((s == null) || (newSub == null)) {
1665                            return null;
1666                    }
1667    
1668                    return replaceFirst(s, String.valueOf(oldSub), newSub);
1669            }
1670    
1671            /**
1672             * Replaces the first occurrence of the string with the new string.
1673             *
1674             * @param  s the original string
1675             * @param  oldSub the string whose first occurrence in the original string
1676             *         is to be searched for and replaced
1677             * @param  newSub the string with which to replace the first occurrence of
1678             *         the <code>oldSub</code> string
1679             * @return a string representing the original string except with the first
1680             *         occurrence of the string <code>oldSub</code> replaced with the
1681             *         string <code>newSub</code>
1682             */
1683            public static String replaceFirst(String s, String oldSub, String newSub) {
1684                    if ((s == null) || (oldSub == null) || (newSub == null)) {
1685                            return null;
1686                    }
1687    
1688                    if (oldSub.equals(newSub)) {
1689                            return s;
1690                    }
1691    
1692                    int y = s.indexOf(oldSub);
1693    
1694                    if (y >= 0) {
1695                            return s.substring(0, y).concat(newSub).concat(
1696                                    s.substring(y + oldSub.length()));
1697                    }
1698                    else {
1699                            return s;
1700                    }
1701            }
1702    
1703            /**
1704             * Replaces the first occurrences of the elements of the string array with
1705             * the corresponding elements of the new string array.
1706             *
1707             * @param  s the original string
1708             * @param  oldSubs the strings whose first occurrences are to be searched
1709             *         for and replaced in the original string
1710             * @param  newSubs the strings with which to replace the first occurrences
1711             *         of the <code>oldSubs</code> strings
1712             * @return a string representing the original string with the first
1713             *         occurrences of the <code>oldSubs</code> strings replaced with the
1714             *         corresponding <code>newSubs</code> strings, or <code>null</code>
1715             *         if the original string, the <code>oldSubs</code> array, or the
1716             *         <code>newSubs</code is <code>null</code>
1717             */
1718            public static String replaceFirst(
1719                    String s, String[] oldSubs, String[] newSubs) {
1720    
1721                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
1722                            return null;
1723                    }
1724    
1725                    if (oldSubs.length != newSubs.length) {
1726                            return s;
1727                    }
1728    
1729                    for (int i = 0; i < oldSubs.length; i++) {
1730                            s = replaceFirst(s, oldSubs[i], newSubs[i]);
1731                    }
1732    
1733                    return s;
1734            }
1735    
1736            /**
1737             * Replaces the last occurrence of the character with the new character.
1738             *
1739             * @param  s the original string
1740             * @param  oldSub the character whose last occurrence in the original string
1741             *         is to be searched for and replaced
1742             * @param  newSub the character with which to replace the last occurrence of
1743             *         the <code>oldSub</code> character
1744             * @return a string representing the original string except with the first
1745             *         occurrence of the character <code>oldSub</code> replaced with the
1746             *         character <code>newSub</code>
1747             */
1748            public static String replaceLast(String s, char oldSub, char newSub) {
1749                    if (s == null) {
1750                            return null;
1751                    }
1752    
1753                    return replaceLast(s, String.valueOf(oldSub), String.valueOf(newSub));
1754            }
1755    
1756            /**
1757             * Replaces the last occurrence of the character with the new string.
1758             *
1759             * @param  s the original string
1760             * @param  oldSub the character whose last occurrence in the original string
1761             *         is to be searched for and replaced
1762             * @param  newSub the string with which to replace the last occurrence of
1763             *         the <code>oldSub</code> character
1764             * @return a string representing the original string except with the last
1765             *         occurrence of the character <code>oldSub</code> replaced with the
1766             *         string <code>newSub</code>
1767             */
1768            public static String replaceLast(String s, char oldSub, String newSub) {
1769                    if ((s == null) || (newSub == null)) {
1770                            return null;
1771                    }
1772    
1773                    return replaceLast(s, String.valueOf(oldSub), newSub);
1774            }
1775    
1776            /**
1777             * Replaces the last occurrence of the string <code>oldSub</code> in the
1778             * string <code>s</code> with the string <code>newSub</code>.
1779             *
1780             * @param  s the original string
1781             * @param  oldSub the string whose last occurrence in the original string is
1782             *         to be searched for and replaced
1783             * @param  newSub the string with which to replace the last occurrence of
1784             *         the <code>oldSub</code> string
1785             * @return a string representing the original string except with the last
1786             *         occurrence of the string <code>oldSub</code> replaced with the
1787             *         string <code>newSub</code>
1788             */
1789            public static String replaceLast(String s, String oldSub, String newSub) {
1790                    if ((s == null) || (oldSub == null) || (newSub == null)) {
1791                            return null;
1792                    }
1793    
1794                    if (oldSub.equals(newSub)) {
1795                            return s;
1796                    }
1797    
1798                    int y = s.lastIndexOf(oldSub);
1799    
1800                    if (y >= 0) {
1801                            return s.substring(0, y).concat(newSub).concat(
1802                                    s.substring(y + oldSub.length()));
1803                    }
1804                    else {
1805                            return s;
1806                    }
1807            }
1808    
1809            /**
1810             * Replaces the last occurrences of the elements of the string array with
1811             * the corresponding elements of the new string array.
1812             *
1813             * @param  s the original string
1814             * @param  oldSubs the strings whose last occurrences are to be searched for
1815             *         and replaced in the original string
1816             * @param  newSubs the strings with which to replace the last occurrences of
1817             *         the <code>oldSubs</code> strings
1818             * @return a string representing the original string with the last
1819             *         occurrences of the <code>oldSubs</code> strings replaced with the
1820             *         corresponding <code>newSubs</code> strings, or <code>null</code>
1821             *         if the original string, the <code>oldSubs</code> array, or the
1822             *         <code>newSubs</code is <code>null</code>
1823             */
1824            public static String replaceLast(
1825                    String s, String[] oldSubs, String[] newSubs) {
1826    
1827                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
1828                            return null;
1829                    }
1830    
1831                    if (oldSubs.length != newSubs.length) {
1832                            return s;
1833                    }
1834    
1835                    for (int i = 0; i < oldSubs.length; i++) {
1836                            s = replaceLast(s, oldSubs[i], newSubs[i]);
1837                    }
1838    
1839                    return s;
1840            }
1841    
1842            public static StringBundler replaceToStringBundler(
1843                    String s, String begin, String end, Map<String, String> values) {
1844    
1845                    if ((s == null) || (begin == null) || (end == null) ||
1846                            (values == null) || (values.size() == 0)) {
1847    
1848                            return new StringBundler(s);
1849                    }
1850    
1851                    StringBundler sb = new StringBundler(values.size() * 2 + 1);
1852    
1853                    int pos = 0;
1854    
1855                    while (true) {
1856                            int x = s.indexOf(begin, pos);
1857                            int y = s.indexOf(end, x + begin.length());
1858    
1859                            if ((x == -1) || (y == -1)) {
1860                                    sb.append(s.substring(pos));
1861    
1862                                    break;
1863                            }
1864                            else {
1865                                    sb.append(s.substring(pos, x));
1866    
1867                                    String oldValue = s.substring(x + begin.length(), y);
1868    
1869                                    String newValue = values.get(oldValue);
1870    
1871                                    if (newValue == null) {
1872                                            newValue = oldValue;
1873                                    }
1874    
1875                                    sb.append(newValue);
1876    
1877                                    pos = y + end.length();
1878                            }
1879                    }
1880    
1881                    return sb;
1882            }
1883    
1884            public static StringBundler replaceWithStringBundler(
1885                    String s, String begin, String end, Map<String, StringBundler> values) {
1886    
1887                    if ((s == null) || (begin == null) || (end == null) ||
1888                            (values == null) || (values.size() == 0)) {
1889    
1890                            return new StringBundler(s);
1891                    }
1892    
1893                    int size = values.size() + 1;
1894    
1895                    for (StringBundler valueSB : values.values()) {
1896                            size += valueSB.index();
1897                    }
1898    
1899                    StringBundler sb = new StringBundler(size);
1900    
1901                    int pos = 0;
1902    
1903                    while (true) {
1904                            int x = s.indexOf(begin, pos);
1905                            int y = s.indexOf(end, x + begin.length());
1906    
1907                            if ((x == -1) || (y == -1)) {
1908                                    sb.append(s.substring(pos));
1909    
1910                                    break;
1911                            }
1912                            else {
1913                                    sb.append(s.substring(pos, x));
1914    
1915                                    String oldValue = s.substring(x + begin.length(), y);
1916    
1917                                    StringBundler newValue = values.get(oldValue);
1918    
1919                                    if (newValue == null) {
1920                                            sb.append(oldValue);
1921                                    }
1922                                    else {
1923                                            sb.append(newValue);
1924                                    }
1925    
1926                                    pos = y + end.length();
1927                            }
1928                    }
1929    
1930                    return sb;
1931            }
1932    
1933            /**
1934             * Reverses the order of the characters of the string.
1935             *
1936             * @param  s the original string
1937             * @return a string representing the original string with characters in
1938             *         reverse order
1939             */
1940            public static String reverse(String s) {
1941                    if (s == null) {
1942                            return null;
1943                    }
1944    
1945                    char[] chars = s.toCharArray();
1946                    char[] reverse = new char[chars.length];
1947    
1948                    for (int i = 0; i < chars.length; i++) {
1949                            reverse[i] = chars[chars.length - i - 1];
1950                    }
1951    
1952                    return new String(reverse);
1953            }
1954    
1955            /**
1956             * Replaces all double slashes of the string with single slashes.
1957             *
1958             * <p>
1959             * Example:
1960             * </p>
1961             *
1962             * <p>
1963             * <pre>
1964             * <code>
1965             * safePath("http://www.liferay.com") returns "http:/www.liferay.com"
1966             * </code>
1967             * </pre>
1968             * </p>
1969             *
1970             * @param  path the original string
1971             * @return a string representing the original string with all double slashes
1972             *         replaced with single slashes
1973             */
1974            public static String safePath(String path) {
1975                    return replace(path, StringPool.DOUBLE_SLASH, StringPool.SLASH);
1976            }
1977    
1978            /**
1979             * Returns a string representing the original string appended with suffix
1980             * "..." and then shortened to 20 characters.
1981             *
1982             * <p>
1983             * The suffix is only added if the original string exceeds 20 characters. If
1984             * the original string exceeds 20 characters and it contains whitespace, the
1985             * string is shortened at the first whitespace character.
1986             * </p>
1987             *
1988             * <p>
1989             * Examples:
1990             * </p>
1991             *
1992             * <p>
1993             * <pre>
1994             * <code>
1995             * shorten("12345678901234567890xyz") returns "12345678901234567..."
1996             * shorten("1 345678901234567890xyz") returns "1..."
1997             * shorten(" 2345678901234567890xyz") returns "..."
1998             * shorten("12345678901234567890") returns "12345678901234567890"
1999             * shorten(" 2345678901234567890") returns " 2345678901234567890"
2000             * </code>
2001             * </pre>
2002             * </p>
2003             *
2004             * @param  s the original string
2005             * @return a string representing the original string shortened to 20
2006             *         characters, with suffix "..." appended to it
2007             */
2008            public static String shorten(String s) {
2009                    return shorten(s, 20);
2010            }
2011    
2012            /**
2013             * Returns a string representing the original string appended with suffix
2014             * "..." and then shortened to the specified length.
2015             *
2016             * <p>
2017             * The suffix is only added if the original string exceeds the specified
2018             * length. If the original string exceeds the specified length and it
2019             * contains whitespace, the string is shortened at the first whitespace
2020             * character.
2021             * </p>
2022             *
2023             * <p>
2024             * Examples:
2025             * </p>
2026             *
2027             * <p>
2028             * <pre>
2029             * <code>
2030             * shorten("123456789", 8) returns "12345..."
2031             * shorten("1 3456789", 8) returns "1..."
2032             * shorten(" 23456789", 8) returns "..."
2033             * shorten("12345678", 8) returns "12345678"
2034             * shorten(" 1234567", 8) returns " 1234567"
2035             * </code>
2036             * </pre>
2037             * </p>
2038             *
2039             * @param  s the original string
2040             * @param  length the number of characters to limit from the original string
2041             * @return a string representing the original string shortened to the
2042             *         specified length, with suffix "..." appended to it
2043             */
2044            public static String shorten(String s, int length) {
2045                    return shorten(s, length, "...");
2046            }
2047    
2048            /**
2049             * Returns a string representing the original string appended with the
2050             * specified suffix and then shortened to the specified length.
2051             *
2052             * <p>
2053             * The suffix is only added if the original string exceeds the specified
2054             * length. If the original string exceeds the specified length and it
2055             * contains whitespace, the string is shortened at the first whitespace
2056             * character.
2057             * </p>
2058             *
2059             * <p>
2060             * Examples:
2061             * </p>
2062             *
2063             * <p>
2064             * <pre>
2065             * <code>
2066             * shorten("12345678901234", 13, "... etc.") returns "12345... etc."
2067             * shorten("1 345678901234", 13, "... etc.") returns "1... etc."
2068             * shorten(" 2345678901234", 13, "... etc.") returns "... etc."
2069             * shorten("1234567890123", 13, "... etc.") returns "1234567890123"
2070             * shorten(" 123456789012", 13, "... etc.") returns " 123456789012"
2071             * </code>
2072             * </pre>
2073             * </p>
2074             *
2075             * @param  s the original string
2076             * @param  length the number of characters to limit from the original string
2077             * @param  suffix the suffix to append
2078             * @return a string representing the original string shortened to the
2079             *         specified length, with the specified suffix appended to it
2080             */
2081            public static String shorten(String s, int length, String suffix) {
2082                    if ((s == null) || (suffix == null)) {
2083                            return null;
2084                    }
2085    
2086                    if (s.length() <= length) {
2087                            return s;
2088                    }
2089    
2090                    if (length < suffix.length()) {
2091                            return s.substring(0, length);
2092                    }
2093    
2094                    int curLength = length;
2095    
2096                    for (int j = (curLength - suffix.length()); j >= 0; j--) {
2097                            if (Character.isWhitespace(s.charAt(j))) {
2098                                    curLength = j;
2099    
2100                                    break;
2101                            }
2102                    }
2103    
2104                    if (curLength == length) {
2105                            curLength = length - suffix.length();
2106                    }
2107    
2108                    String temp = s.substring(0, curLength);
2109    
2110                    return temp.concat(suffix);
2111            }
2112    
2113            /**
2114             * Returns a string representing the original string appended with the
2115             * specified suffix and then shortened to 20 characters.
2116             *
2117             * <p>
2118             * The suffix is only added if the original string exceeds 20 characters. If
2119             * the original string exceeds 20 characters and it contains whitespace, the
2120             * string is shortened at the first whitespace character.
2121             * </p>
2122             *
2123             * <p>
2124             * Examples:
2125             * </p>
2126             *
2127             * <p>
2128             * <pre>
2129             * <code>
2130             * shorten("12345678901234567890xyz", "... etc.") returns "123456789012... etc."
2131             * shorten("1 345678901234567890xyz", "... etc.") returns "1... etc."
2132             * shorten(" 2345678901234567890xyz", "... etc.") returns "... etc."
2133             * shorten("12345678901234567890", "... etc.") returns "12345678901234567890"
2134             * shorten(" 2345678901234567890", "... etc.") returns " 2345678901234567890"
2135             * </code>
2136             * </pre>
2137             * </p>
2138             *
2139             * @param  s the original string
2140             * @param  suffix the suffix to append
2141             * @return a string representing the original string shortened to 20
2142             *         characters, with the specified suffix appended to it
2143             */
2144            public static String shorten(String s, String suffix) {
2145                    return shorten(s, 20, suffix);
2146            }
2147    
2148            /**
2149             * Splits string <code>s</code> around comma characters.
2150             *
2151             * <p>
2152             * Example:
2153             * </p>
2154             *
2155             * <p>
2156             * <pre>
2157             * <code>
2158             * split("Alice,Bob,Charlie") returns {"Alice", "Bob", "Charlie"}
2159             * split("Alice, Bob, Charlie") returns {"Alice", " Bob", " Charlie"}
2160             * </code>
2161             * </pre>
2162             * </p>
2163             *
2164             * @param  s the string to split
2165             * @return the array of strings resulting from splitting string
2166             *         <code>s</code> around comma characters, or an empty string array
2167             *         if <code>s</code> is <code>null</code> or <code>s</code> is empty
2168             */
2169            public static String[] split(String s) {
2170                    return split(s, CharPool.COMMA);
2171            }
2172    
2173            /**
2174             * Splits the string <code>s</code> around comma characters returning the
2175             * boolean values of the substrings.
2176             *
2177             * @param  s the string to split
2178             * @param  x the default value to use for a substring in case an exception
2179             *         occurs in getting the boolean value for that substring
2180             * @return the array of boolean values resulting from splitting string
2181             *         <code>s</code> around comma characters, or an empty array if
2182             *         <code>s</code> is <code>null</code>
2183             */
2184            public static boolean[] split(String s, boolean x) {
2185                    return split(s, StringPool.COMMA, x);
2186            }
2187    
2188            /**
2189             * Splits the string <code>s</code> around the specified delimiter.
2190             *
2191             * <p>
2192             * Example:
2193             * </p>
2194             *
2195             * <p>
2196             * <pre>
2197             * <code>
2198             * splitLines("First;Second;Third", ';') returns {"First","Second","Third"}
2199             * </code>
2200             * </pre>
2201             * </p>
2202             *
2203             * @param  s the string to split
2204             * @param  delimiter the delimiter
2205             * @return the array of strings resulting from splitting string
2206             *         <code>s</code> around the specified delimiter character, or an
2207             *         empty string array if <code>s</code> is <code>null</code> or if
2208             *         <code>s</code> is empty
2209             */
2210            public static String[] split(String s, char delimiter) {
2211                    if (Validator.isNull(s)) {
2212                            return _emptyStringArray;
2213                    }
2214    
2215                    s = s.trim();
2216    
2217                    if (s.length() == 0) {
2218                            return _emptyStringArray;
2219                    }
2220    
2221                    if ((delimiter == CharPool.RETURN) ||
2222                            (delimiter == CharPool.NEW_LINE)) {
2223    
2224                            return splitLines(s);
2225                    }
2226    
2227                    List<String> nodeValues = new ArrayList<String>();
2228    
2229                    int offset = 0;
2230                    int pos = s.indexOf(delimiter, offset);
2231    
2232                    while (pos != -1) {
2233                            nodeValues.add(s.substring(offset, pos));
2234    
2235                            offset = pos + 1;
2236                            pos = s.indexOf(delimiter, offset);
2237                    }
2238    
2239                    if (offset < s.length()) {
2240                            nodeValues.add(s.substring(offset));
2241                    }
2242    
2243                    return nodeValues.toArray(new String[nodeValues.size()]);
2244            }
2245    
2246            /**
2247             * Splits the string <code>s</code> around comma characters returning the
2248             * double-precision decimal values of the substrings.
2249             *
2250             * @param  s the string to split
2251             * @param  x the default value to use for a substring in case an exception
2252             *         occurs in getting the double-precision decimal value for that
2253             *         substring
2254             * @return the array of double-precision decimal values resulting from
2255             *         splitting string <code>s</code> around comma characters, or an
2256             *         empty array if <code>s</code> is <code>null</code>
2257             */
2258            public static double[] split(String s, double x) {
2259                    return split(s, StringPool.COMMA, x);
2260            }
2261    
2262            /**
2263             * Splits the string <code>s</code> around comma characters returning the
2264             * decimal values of the substrings.
2265             *
2266             * @param  s the string to split
2267             * @param  x the default value to use for a substring in case an exception
2268             *         occurs in getting the decimal value for that substring
2269             * @return the array of decimal values resulting from splitting string
2270             *         <code>s</code> around comma characters, or an empty array if
2271             *         <code>s</code> is <code>null</code>
2272             */
2273            public static float[] split(String s, float x) {
2274                    return split(s, StringPool.COMMA, x);
2275            }
2276    
2277            /**
2278             * Splits the string <code>s</code> around comma characters returning the
2279             * integer values of the substrings.
2280             *
2281             * @param  s the string to split
2282             * @param  x the default value to use for a substring in case an exception
2283             *         occurs in getting the integer value for that substring
2284             * @return the array of integer values resulting from splitting string
2285             *         <code>s</code> around comma characters, or an empty array if
2286             *         <code>s</code> is <code>null</code>
2287             */
2288            public static int[] split(String s, int x) {
2289                    return split(s, StringPool.COMMA, x);
2290            }
2291    
2292            /**
2293             * Splits the string <code>s</code> around comma characters returning the
2294             * long integer values of the substrings.
2295             *
2296             * @param  s the string to split
2297             * @param  x the default value to use for a substring in case an exception
2298             *         occurs in getting the long integer value for that substring
2299             * @return the array of long integer values resulting from splitting string
2300             *         <code>s</code> around comma characters, or an empty array if
2301             *         <code>s</code> is <code>null</code>
2302             */
2303            public static long[] split(String s, long x) {
2304                    return split(s, StringPool.COMMA, x);
2305            }
2306    
2307            /**
2308             * Splits the string <code>s</code> around comma characters returning the
2309             * short integer values of the substrings.
2310             *
2311             * @param  s the string to split
2312             * @param  x the default value to use for a substring in case an exception
2313             *         occurs in getting the short integer value for that substring
2314             * @return the array of short integer values resulting from splitting string
2315             *         <code>s</code> around comma characters, or an empty array if
2316             *         <code>s</code> is <code>null</code>
2317             */
2318            public static short[] split(String s, short x) {
2319                    return split(s, StringPool.COMMA, x);
2320            }
2321    
2322            /**
2323             * Splits the string <code>s</code> around the specified delimiter string.
2324             *
2325             * <p>
2326             * Example:
2327             * </p>
2328             *
2329             * <p>
2330             * <pre>
2331             * <code>
2332             * splitLines("oneandtwoandthreeandfour", "and") returns {"one","two","three","four"}
2333             * </code>
2334             * </pre>
2335             * </p>
2336             *
2337             * @param  s the string to split
2338             * @param  delimiter the delimiter
2339             * @return the array of strings resulting from splitting string
2340             *         <code>s</code> around the specified delimiter string, or an empty
2341             *         string array if <code>s</code> is <code>null</code> or equals the
2342             *         delimiter
2343             */
2344            public static String[] split(String s, String delimiter) {
2345                    if (Validator.isNull(s) || (delimiter == null) ||
2346                            delimiter.equals(StringPool.BLANK)) {
2347    
2348                            return _emptyStringArray;
2349                    }
2350    
2351                    s = s.trim();
2352    
2353                    if (s.equals(delimiter)) {
2354                            return _emptyStringArray;
2355                    }
2356    
2357                    if (delimiter.length() == 1) {
2358                            return split(s, delimiter.charAt(0));
2359                    }
2360    
2361                    List<String> nodeValues = new ArrayList<String>();
2362    
2363                    int offset = 0;
2364                    int pos = s.indexOf(delimiter, offset);
2365    
2366                    while (pos != -1) {
2367                            nodeValues.add(s.substring(offset, pos));
2368    
2369                            offset = pos + delimiter.length();
2370                            pos = s.indexOf(delimiter, offset);
2371                    }
2372    
2373                    if (offset < s.length()) {
2374                            nodeValues.add(s.substring(offset));
2375                    }
2376    
2377                    return nodeValues.toArray(new String[nodeValues.size()]);
2378            }
2379    
2380            /**
2381             * Splits the string <code>s</code> around the specified delimiter returning
2382             * the boolean values of the substrings.
2383             *
2384             * @param  s the string to split
2385             * @param  delimiter the delimiter
2386             * @param  x the default value to use for a substring in case an exception
2387             *         occurs in getting the boolean value for that substring
2388             * @return the array of booleans resulting from splitting string
2389             *         <code>s</code> around the specified delimiter string, or an empty
2390             *         array if <code>s</code> is <code>null</code>
2391             */
2392            public static boolean[] split(String s, String delimiter, boolean x) {
2393                    String[] array = split(s, delimiter);
2394                    boolean[] newArray = new boolean[array.length];
2395    
2396                    for (int i = 0; i < array.length; i++) {
2397                            boolean value = x;
2398    
2399                            try {
2400                                    value = Boolean.valueOf(array[i]).booleanValue();
2401                            }
2402                            catch (Exception e) {
2403                            }
2404    
2405                            newArray[i] = value;
2406                    }
2407    
2408                    return newArray;
2409            }
2410    
2411            /**
2412             * Splits the string <code>s</code> around the specified delimiter returning
2413             * the double-precision decimal values of the substrings.
2414             *
2415             * @param  s the string to split
2416             * @param  delimiter the delimiter
2417             * @param  x the default value to use for a substring in case an exception
2418             *         occurs in getting the double-precision decimal value for that
2419             *         substring
2420             * @return the array of double-precision decimal values resulting from
2421             *         splitting string <code>s</code> around the specified delimiter
2422             *         string, or an empty array if <code>s</code> is <code>null</code>
2423             */
2424            public static double[] split(String s, String delimiter, double x) {
2425                    String[] array = split(s, delimiter);
2426                    double[] newArray = new double[array.length];
2427    
2428                    for (int i = 0; i < array.length; i++) {
2429                            double value = x;
2430    
2431                            try {
2432                                    value = Double.parseDouble(array[i]);
2433                            }
2434                            catch (Exception e) {
2435                            }
2436    
2437                            newArray[i] = value;
2438                    }
2439    
2440                    return newArray;
2441            }
2442    
2443            /**
2444             * Splits the string <code>s</code> around the specified delimiter returning
2445             * the decimal values of the substrings.
2446             *
2447             * @param  s the string to split
2448             * @param  delimiter the delimiter
2449             * @param  x the default value to use for a substring in case an exception
2450             *         occurs in getting the decimal value for that substring
2451             * @return the array of decimal values resulting from splitting string
2452             *         <code>s</code> around the specified delimiter string, or an empty
2453             *         array if <code>s</code> is <code>null</code>
2454             */
2455            public static float[] split(String s, String delimiter, float x) {
2456                    String[] array = split(s, delimiter);
2457                    float[] newArray = new float[array.length];
2458    
2459                    for (int i = 0; i < array.length; i++) {
2460                            float value = x;
2461    
2462                            try {
2463                                    value = Float.parseFloat(array[i]);
2464                            }
2465                            catch (Exception e) {
2466                            }
2467    
2468                            newArray[i] = value;
2469                    }
2470    
2471                    return newArray;
2472            }
2473    
2474            /**
2475             * Splits the string <code>s</code> around the specified delimiter returning
2476             * the integer values of the substrings.
2477             *
2478             * @param  s the string to split
2479             * @param  delimiter the delimiter
2480             * @param  x the default value to use for a substring in case an exception
2481             *         occurs in getting the integer value for that substring
2482             * @return the array of integer values resulting from splitting string
2483             *         <code>s</code> around the specified delimiter string, or an empty
2484             *         array if <code>s</code> is <code>null</code>
2485             */
2486            public static int[] split(String s, String delimiter, int x) {
2487                    String[] array = split(s, delimiter);
2488                    int[] newArray = new int[array.length];
2489    
2490                    for (int i = 0; i < array.length; i++) {
2491                            int value = x;
2492    
2493                            try {
2494                                    value = Integer.parseInt(array[i]);
2495                            }
2496                            catch (Exception e) {
2497                            }
2498    
2499                            newArray[i] = value;
2500                    }
2501    
2502                    return newArray;
2503            }
2504    
2505            /**
2506             * Splits the string <code>s</code> around the specified delimiter returning
2507             * the long integer values of the substrings.
2508             *
2509             * @param  s the string to split
2510             * @param  delimiter the delimiter
2511             * @param  x the default value to use for a substring in case an exception
2512             *         occurs in getting the long integer value for that substring
2513             * @return the array of long integer values resulting from splitting string
2514             *         <code>s</code> around the specified delimiter string, or an empty
2515             *         array if <code>s</code> is <code>null</code>
2516             */
2517            public static long[] split(String s, String delimiter, long x) {
2518                    String[] array = split(s, delimiter);
2519                    long[] newArray = new long[array.length];
2520    
2521                    for (int i = 0; i < array.length; i++) {
2522                            long value = x;
2523    
2524                            try {
2525                                    value = Long.parseLong(array[i]);
2526                            }
2527                            catch (Exception e) {
2528                            }
2529    
2530                            newArray[i] = value;
2531                    }
2532    
2533                    return newArray;
2534            }
2535    
2536            /**
2537             * Splits the string <code>s</code> around the specified delimiter returning
2538             * the short integer values of the substrings.
2539             *
2540             * @param  s the string to split
2541             * @param  delimiter the delimiter
2542             * @param  x the default value to use for a substring in case an exception
2543             *         occurs in getting the short integer value for that substring
2544             * @return the array of short integer values resulting from splitting string
2545             *         <code>s</code> around the specified delimiter string, or an empty
2546             *         array if <code>s</code> is <code>null</code>
2547             */
2548            public static short[] split(String s, String delimiter, short x) {
2549                    String[] array = split(s, delimiter);
2550                    short[] newArray = new short[array.length];
2551    
2552                    for (int i = 0; i < array.length; i++) {
2553                            short value = x;
2554    
2555                            try {
2556                                    value = Short.parseShort(array[i]);
2557                            }
2558                            catch (Exception e) {
2559                            }
2560    
2561                            newArray[i] = value;
2562                    }
2563    
2564                    return newArray;
2565            }
2566    
2567            /**
2568             * Splits string <code>s</code> around return and newline characters.
2569             *
2570             * <p>
2571             * Example:
2572             * </p>
2573             *
2574             * <p>
2575             * <pre>
2576             * <code>
2577             * splitLines("Red\rBlue\nGreen") returns {"Red","Blue","Green"}
2578             * </code>
2579             * </pre>
2580             * </p>
2581             *
2582             * @param  s the string to split
2583             * @return the array of strings resulting from splitting string
2584             *         <code>s</code> around return and newline characters, or an empty
2585             *         string array if string <code>s</code> is <code>null</code>
2586             */
2587            public static String[] splitLines(String s) {
2588                    if (Validator.isNull(s)) {
2589                            return _emptyStringArray;
2590                    }
2591    
2592                    s = s.trim();
2593    
2594                    List<String> lines = new ArrayList<String>();
2595    
2596                    int lastIndex = 0;
2597    
2598                    while (true) {
2599                            int returnIndex = s.indexOf(CharPool.RETURN, lastIndex);
2600                            int newLineIndex = s.indexOf(CharPool.NEW_LINE, lastIndex);
2601    
2602                            if ((returnIndex == -1) && (newLineIndex == -1)) {
2603                                    break;
2604                            }
2605    
2606                            if (returnIndex == -1) {
2607                                    lines.add(s.substring(lastIndex, newLineIndex));
2608    
2609                                    lastIndex = newLineIndex + 1;
2610                            }
2611                            else if (newLineIndex == -1) {
2612                                    lines.add(s.substring(lastIndex, returnIndex));
2613    
2614                                    lastIndex = returnIndex + 1;
2615                            }
2616                            else if (newLineIndex < returnIndex) {
2617                                    lines.add(s.substring(lastIndex, newLineIndex));
2618    
2619                                    lastIndex = newLineIndex + 1;
2620                            }
2621                            else {
2622                                    lines.add(s.substring(lastIndex, returnIndex));
2623    
2624                                    lastIndex = returnIndex + 1;
2625    
2626                                    if (lastIndex == newLineIndex) {
2627                                            lastIndex++;
2628                                    }
2629                            }
2630                    }
2631    
2632                    if (lastIndex < s.length()) {
2633                            lines.add(s.substring(lastIndex));
2634                    }
2635    
2636                    return lines.toArray(new String[lines.size()]);
2637            }
2638    
2639            /**
2640             * Returns <code>true</code> if, ignoring case, the string starts with the
2641             * specified character.
2642             *
2643             * @param  s the string
2644             * @param  begin the character against which the initial character of the
2645             *         string is to be compared
2646             * @return <code>true</code> if, ignoring case, the string starts with the
2647             *         specified character; <code>false</code> otherwise
2648             */
2649            public static boolean startsWith(String s, char begin) {
2650                    return startsWith(s, (new Character(begin)).toString());
2651            }
2652    
2653            /**
2654             * Returns <code>true</code> if, ignoring case, the string starts with the
2655             * specified start string.
2656             *
2657             * @param  s the original string
2658             * @param  start the string against which the beginning of string
2659             *         <code>s</code> are to be compared
2660             * @return <code>true</code> if, ignoring case, the string starts with the
2661             *         specified start string; <code>false</code> otherwise
2662             */
2663            public static boolean startsWith(String s, String start) {
2664                    if ((s == null) || (start == null)) {
2665                            return false;
2666                    }
2667    
2668                    if (start.length() > s.length()) {
2669                            return false;
2670                    }
2671    
2672                    String temp = s.substring(0, start.length());
2673    
2674                    if (temp.equalsIgnoreCase(start)) {
2675                            return true;
2676                    }
2677                    else {
2678                            return false;
2679                    }
2680            }
2681    
2682            /**
2683             * Returns the number of starting characters that <code>s1</code> and
2684             * <code>s2</code> have in common before their characters deviate.
2685             *
2686             * @param  s1 string 1
2687             * @param  s2 string 2
2688             * @return the number of starting characters that <code>s1</code> and
2689             *         <code>s2</code> have in common before their characters deviate
2690             */
2691            public static int startsWithWeight(String s1, String s2) {
2692                    if ((s1 == null) || (s2 == null)) {
2693                            return 0;
2694                    }
2695    
2696                    char[] chars1 = s1.toCharArray();
2697                    char[] chars2 = s2.toCharArray();
2698    
2699                    int i = 0;
2700    
2701                    for (; (i < chars1.length) && (i < chars2.length); i++) {
2702                            if (chars1[i] != chars2[i]) {
2703                                    break;
2704                            }
2705                    }
2706    
2707                    return i;
2708            }
2709    
2710            /**
2711             * Returns a string representing the string <code>s</code> with all
2712             * occurrences of the specified character removed.
2713             *
2714             * <p>
2715             * Example:
2716             * </p>
2717             *
2718             * <p>
2719             * <pre>
2720             * <code>
2721             * strip("Mississipi", 'i') returns "Mssssp"
2722             * </code>
2723             * </pre>
2724             * </p>
2725             *
2726             * @param  s the string from which to strip all occurrences the character
2727             * @param  remove the character to strip from the string
2728             * @return a string representing the string <code>s</code> with all
2729             *         occurrences of the specified character removed, or
2730             *         <code>null</code> if <code>s</code> is <code>null</code>
2731             */
2732            public static String strip(String s, char remove) {
2733                    if (s == null) {
2734                            return null;
2735                    }
2736    
2737                    int x = s.indexOf(remove);
2738    
2739                    if (x < 0) {
2740                            return s;
2741                    }
2742    
2743                    int y = 0;
2744    
2745                    StringBundler sb = new StringBundler(s.length());
2746    
2747                    while (x >= 0) {
2748                            sb.append(s.subSequence(y, x));
2749    
2750                            y = x + 1;
2751    
2752                            x = s.indexOf(remove, y);
2753                    }
2754    
2755                    sb.append(s.substring(y));
2756    
2757                    return sb.toString();
2758            }
2759    
2760            /**
2761             * Returns a string representing the combination of the substring of
2762             * <code>s</code> up to but not including the string <code>begin</code>
2763             * concatenated with the substring of <code>s</code> after but not including
2764             * the string <code>end</code>.
2765             *
2766             * <p>
2767             * Example:
2768             * <p>
2769             *
2770             * <p>
2771             * <pre>
2772             * <code>
2773             * stripBetween("One small step for man, one giant leap for mankind", "step", "giant ") returns "One small leap for mankind"
2774             * </code>
2775             * </pre>
2776             * </p>
2777             *
2778             * @param  s the from which to strip a substring
2779             * @param  begin the beginning characters of the substring to be removed
2780             * @param  end the ending characters of the substring to be removed
2781             * @return a string representing the combination of the substring of
2782             *         <code>s</code> up to but not including the string
2783             *         <code>begin</code> concatenated with the substring of
2784             *         <code>s</code> after but not including the string
2785             *         <code>end</code>, or the original string if the value of
2786             *         <code>s</code>, <code>begin</code>, or <code>end</code> are
2787             *         <code>null</code>
2788             */
2789            public static String stripBetween(String s, String begin, String end) {
2790                    if ((s == null) || (begin == null) || (end == null)) {
2791                            return s;
2792                    }
2793    
2794                    StringBundler sb = new StringBundler(s.length());
2795    
2796                    int pos = 0;
2797    
2798                    while (true) {
2799                            int x = s.indexOf(begin, pos);
2800                            int y = s.indexOf(end, x + begin.length());
2801    
2802                            if ((x == -1) || (y == -1)) {
2803                                    sb.append(s.substring(pos));
2804    
2805                                    break;
2806                            }
2807                            else {
2808                                    sb.append(s.substring(pos, x));
2809    
2810                                    pos = y + end.length();
2811                            }
2812                    }
2813    
2814                    return sb.toString();
2815            }
2816    
2817            /**
2818             * Returns a string representing the Unicode character codes of the
2819             * characters comprising the string <code>s</code>.
2820             *
2821             * <p>
2822             * Example:
2823             * </p>
2824             *
2825             * <p>
2826             * <pre>
2827             * <code>
2828             * toCharCode("a") returns "97"
2829             * toCharCode("b") returns "98"
2830             * toCharCode("c") returns "99"
2831             * toCharCode("What's for lunch?") returns "87104971163911532102111114321081171109910463"
2832             * </code>
2833             * </pre>
2834             * </p>
2835             *
2836             * @param  s the string whose character codes are to be represented
2837             * @return a string representing the Unicode character codes of the
2838             *         characters comprising the string <code>s</code>
2839             */
2840            public static String toCharCode(String s) {
2841                    StringBundler sb = new StringBundler(s.length());
2842    
2843                    for (int i = 0; i < s.length(); i++) {
2844                            sb.append(s.codePointAt(i));
2845                    }
2846    
2847                    return sb.toString();
2848            }
2849    
2850            public static String toHexString(int i) {
2851                    char[] buffer = new char[8];
2852    
2853                    int index = 8;
2854    
2855                    do {
2856                            buffer[--index] = _HEX_DIGITS[i & 15];
2857    
2858                            i >>>= 4;
2859                    }
2860                    while (i != 0);
2861    
2862                    return new String(buffer, index, 8 - index);
2863            }
2864    
2865            public static String toHexString(long l) {
2866                    char[] buffer = new char[16];
2867    
2868                    int index = 16;
2869    
2870                    do {
2871                            buffer[--index] = _HEX_DIGITS[(int) (l & 15)];
2872    
2873                            l >>>= 4;
2874                    }
2875                    while (l != 0);
2876    
2877                    return new String(buffer, index, 16 - index);
2878            }
2879    
2880            public static String toHexString(Object obj) {
2881                    if (obj instanceof Integer) {
2882                            return toHexString(((Integer)obj).intValue());
2883                    }
2884                    else if (obj instanceof Long) {
2885                            return toHexString(((Long)obj).longValue());
2886                    }
2887                    else {
2888                            return String.valueOf(obj);
2889                    }
2890            }
2891    
2892            /**
2893             * Trims all leading and trailing whitespace from the string.
2894             *
2895             * @param  s the original string
2896             * @return a string representing the original string with all leading and
2897             *         trailing whitespace removed
2898             */
2899            public static String trim(String s) {
2900                    if (s == null) {
2901                            return null;
2902                    }
2903    
2904                    if (s.length() == 0) {
2905                            return s;
2906                    }
2907    
2908                    int len = s.length();
2909    
2910                    int x = len;
2911    
2912                    for (int i = 0; i < len; i++) {
2913                            char c = s.charAt(i);
2914    
2915                            if (!Character.isWhitespace(c)) {
2916                                    x = i;
2917    
2918                                    break;
2919                            }
2920                    }
2921    
2922                    if (x == len) {
2923                            return StringPool.BLANK;
2924                    }
2925    
2926                    int y = x + 1;
2927    
2928                    for (int i = len - 1; i > x; i--) {
2929                            char c = s.charAt(i);
2930    
2931                            if (!Character.isWhitespace(c)) {
2932                                    y = i + 1;
2933    
2934                                    break;
2935                            }
2936                    }
2937    
2938                    if ((x == 0) && (y == len)) {
2939                            return s;
2940                    }
2941    
2942                    return s.substring(x, y);
2943            }
2944    
2945            /**
2946             * Trims leading and trailing whitespace from the string, up to but not
2947             * including the whitespace character specified by <code>c</code>.
2948             *
2949             * <p>
2950             * Examples:
2951             * </p>
2952             *
2953             * <p>
2954             * <pre>
2955             * <code>
2956             * trim(" \tHey\t ", '\t') returns "\tHey\t"
2957             * trim(" \t Hey \t ", '\t') returns "\t Hey \t"
2958             * </code>
2959             * </pre>
2960             * </p>
2961             *
2962             * @param  s the original string
2963             * @param  c the whitespace character to limit trimming
2964             * @return a string representing the original string with leading and
2965             *         trailing whitespace removed, up to but not including the
2966             *         whitespace character specified by <code>c</code>
2967             */
2968            public static String trim(String s, char c) {
2969                    return trim(s, new char[] {c});
2970            }
2971    
2972            /**
2973             * Trims leading and trailing whitespace from the string, up to but not
2974             * including the whitespace characters specified by <code>exceptions</code>.
2975             *
2976             * @param  s the original string
2977             * @param  exceptions the whitespace characters to limit trimming
2978             * @return a string representing the original string with leading and
2979             *         trailing whitespace removed, up to but not including the
2980             *         whitespace characters specified by <code>exceptions</code>
2981             */
2982            public static String trim(String s, char[] exceptions) {
2983                    if (s == null) {
2984                            return null;
2985                    }
2986    
2987                    if (s.length() == 0) {
2988                            return s;
2989                    }
2990    
2991                    if ((exceptions == null) || (exceptions.length == 0)) {
2992                            return trim(s);
2993                    }
2994    
2995                    int len = s.length();
2996                    int x = len;
2997    
2998                    for (int i = 0; i < len; i++) {
2999                            char c = s.charAt(i);
3000    
3001                            if (!_isTrimable(c, exceptions)) {
3002                                    x = i;
3003    
3004                                    break;
3005                            }
3006                    }
3007    
3008                    if (x == len) {
3009                            return StringPool.BLANK;
3010                    }
3011    
3012                    int y = x + 1;
3013    
3014                    for (int i = len - 1; i > x; i--) {
3015                            char c = s.charAt(i);
3016    
3017                            if (!_isTrimable(c, exceptions)) {
3018                                    y = i + 1;
3019    
3020                                    break;
3021                            }
3022                    }
3023    
3024                    if ((x == 0) && (y == len)) {
3025                            return s;
3026                    }
3027                    else {
3028                            return s.substring(x, y);
3029                    }
3030            }
3031    
3032            /**
3033             * Trims all leading whitespace from the string.
3034             *
3035             * @param  s the original string
3036             * @return a string representing the original string with all leading
3037             *         whitespace removed
3038             */
3039            public static String trimLeading(String s) {
3040                    if (s == null) {
3041                            return null;
3042                    }
3043    
3044                    if (s.length() == 0) {
3045                            return s;
3046                    }
3047    
3048                    int len = s.length();
3049                    int x = len;
3050    
3051                    for (int i = 0; i < len; i++) {
3052                            char c = s.charAt(i);
3053    
3054                            if (!Character.isWhitespace(c)) {
3055                                    x = i;
3056    
3057                                    break;
3058                            }
3059                    }
3060    
3061                    if (x == len) {
3062                            return StringPool.BLANK;
3063                    }
3064                    else if (x == 0) {
3065                            return s;
3066                    }
3067                    else {
3068                            return s.substring(x);
3069                    }
3070            }
3071    
3072            /**
3073             * Trims leading whitespace from the string, up to but not including the
3074             * whitespace character specified by <code>c</code>.
3075             *
3076             * @param  s the original string
3077             * @param  c the whitespace character to limit trimming
3078             * @return a string representing the original string with leading whitespace
3079             *         removed, up to but not including the whitespace character
3080             *         specified by <code>c</code>
3081             */
3082            public static String trimLeading(String s, char c) {
3083                    return trimLeading(s, new char[] {c});
3084            }
3085    
3086            /**
3087             * Trims leading whitespace from the string, up to but not including the
3088             * whitespace characters specified by <code>exceptions</code>.
3089             *
3090             * @param  s the original string
3091             * @param  exceptions the whitespace characters to limit trimming
3092             * @return a string representing the original string with leading whitespace
3093             *         removed, up to but not including the whitespace characters
3094             *         specified by <code>exceptions</code>
3095             */
3096            public static String trimLeading(String s, char[] exceptions) {
3097                    if (s == null) {
3098                            return null;
3099                    }
3100    
3101                    if (s.length() == 0) {
3102                            return s;
3103                    }
3104    
3105                    if ((exceptions == null) || (exceptions.length == 0)) {
3106                            return trimLeading(s);
3107                    }
3108    
3109                    int len = s.length();
3110                    int x = len;
3111    
3112                    for (int i = 0; i < len; i++) {
3113                            char c = s.charAt(i);
3114    
3115                            if (!_isTrimable(c, exceptions)) {
3116                                    x = i;
3117    
3118                                    break;
3119                            }
3120                    }
3121    
3122                    if (x == len) {
3123                            return StringPool.BLANK;
3124                    }
3125                    else if (x == 0) {
3126                            return s;
3127                    }
3128                    else {
3129                            return s.substring(x);
3130                    }
3131            }
3132    
3133            /**
3134             * Trims all trailing whitespace from the string.
3135             *
3136             * @param  s the original string
3137             * @return a string representing the original string with all trailing
3138             *         whitespace removed
3139             */
3140            public static String trimTrailing(String s) {
3141                    if (s == null) {
3142                            return null;
3143                    }
3144    
3145                    if (s.length() == 0) {
3146                            return s;
3147                    }
3148    
3149                    int len = s.length();
3150                    int x = 0;
3151    
3152                    for (int i = len - 1; i >= 0; i--) {
3153                            char c = s.charAt(i);
3154    
3155                            if (!Character.isWhitespace(c)) {
3156                                    x = i + 1;
3157    
3158                                    break;
3159                            }
3160                    }
3161    
3162                    if (x == 0) {
3163                            return StringPool.BLANK;
3164                    }
3165                    else if (x == len) {
3166                            return s;
3167                    }
3168                    else {
3169                            return s.substring(0, x);
3170                    }
3171            }
3172    
3173            /**
3174             * Trims trailing whitespace from the string, up to but not including the
3175             * whitespace character specified by <code>c</code>.
3176             *
3177             * @param  s the original string
3178             * @param  c the whitespace character to limit trimming
3179             * @return a string representing the original string with trailing
3180             *         whitespace removed, up to but not including the whitespace
3181             *         character specified by <code>c</code>
3182             */
3183            public static String trimTrailing(String s, char c) {
3184                    return trimTrailing(s, new char[] {c});
3185            }
3186    
3187            /**
3188             * Trims trailing whitespace from the string, up to but not including the
3189             * whitespace characters specified by <code>exceptions</code>.
3190             *
3191             * @param  s the original string
3192             * @param  exceptions the whitespace characters to limit trimming
3193             * @return a string representing the original string with trailing
3194             *         whitespace removed, up to but not including the whitespace
3195             *         characters specified by <code>exceptions</code>
3196             */
3197            public static String trimTrailing(String s, char[] exceptions) {
3198                    if (s == null) {
3199                            return null;
3200                    }
3201    
3202                    if (s.length() == 0) {
3203                            return s;
3204                    }
3205    
3206                    if ((exceptions == null) || (exceptions.length == 0)) {
3207                            return trimTrailing(s);
3208                    }
3209    
3210                    int len = s.length();
3211                    int x = 0;
3212    
3213                    for (int i = len - 1; i >= 0; i--) {
3214                            char c = s.charAt(i);
3215    
3216                            if (!_isTrimable(c, exceptions)) {
3217                                    x = i + 1;
3218    
3219                                    break;
3220                            }
3221                    }
3222    
3223                    if (x == 0) {
3224                            return StringPool.BLANK;
3225                    }
3226                    else if (x == len) {
3227                            return s;
3228                    }
3229                    else {
3230                            return s.substring(0, x);
3231                    }
3232            }
3233    
3234            /**
3235             * Removes leading and trailing double and single quotation marks from the
3236             * string.
3237             *
3238             * @param  s the original string
3239             * @return a string representing the original string with leading and
3240             *         trailing double and single quotation marks removed, or the
3241             *         original string if the original string is a <code>null</code> or
3242             *         empty
3243             */
3244            public static String unquote(String s) {
3245                    if (Validator.isNull(s)) {
3246                            return s;
3247                    }
3248    
3249                    if ((s.charAt(0) == CharPool.APOSTROPHE) &&
3250                            (s.charAt(s.length() - 1) == CharPool.APOSTROPHE)) {
3251    
3252                            return s.substring(1, s.length() - 1);
3253                    }
3254                    else if ((s.charAt(0) == CharPool.QUOTE) &&
3255                                     (s.charAt(s.length() - 1) == CharPool.QUOTE)) {
3256    
3257                            return s.substring(1, s.length() - 1);
3258                    }
3259    
3260                    return s;
3261            }
3262    
3263            /**
3264             * Converts all of the characters in the string to upper case.
3265             *
3266             * @param  s the string to convert
3267             * @return the string, converted to upper-case, or <code>null</code> if the
3268             *         string is <code>null</code>
3269             * @see    String#toUpperCase()
3270             */
3271            public static String upperCase(String s) {
3272                    if (s == null) {
3273                            return null;
3274                    }
3275                    else {
3276                            return s.toUpperCase();
3277                    }
3278            }
3279    
3280            /**
3281             * Converts the first character of the string to upper case.
3282             *
3283             * @param  s the string whose first character is to be converted
3284             * @return the string, with its first character converted to upper-case
3285             */
3286            public static String upperCaseFirstLetter(String s) {
3287                    char[] chars = s.toCharArray();
3288    
3289                    if ((chars[0] >= 97) && (chars[0] <= 122)) {
3290                            chars[0] = (char)(chars[0] - 32);
3291                    }
3292    
3293                    return new String(chars);
3294            }
3295    
3296            /**
3297             * Returns the string value of the object.
3298             *
3299             * @param  obj the object whose string value is to be returned
3300             * @return the string value of the object
3301             * @see    String#valueOf(Object obj)
3302             */
3303            public static String valueOf(Object obj) {
3304                    return String.valueOf(obj);
3305            }
3306    
3307            public static String wrap(String text) {
3308                    return wrap(text, 80, StringPool.NEW_LINE);
3309            }
3310    
3311            public static String wrap(String text, int width, String lineSeparator) {
3312                    try {
3313                            return _wrap(text, width, lineSeparator);
3314                    }
3315                    catch (IOException ioe) {
3316                            _log.error(ioe.getMessage());
3317    
3318                            return text;
3319                    }
3320            }
3321    
3322            private static String _highlight(
3323                    String s, Pattern pattern, String highlight1, String highlight2) {
3324    
3325                    StringTokenizer st = new StringTokenizer(s);
3326    
3327                    if (st.countTokens() == 0) {
3328                            return StringPool.BLANK;
3329                    }
3330    
3331                    StringBundler sb = new StringBundler(2 * st.countTokens() - 1);
3332    
3333                    while (st.hasMoreTokens()) {
3334                            String token = st.nextToken();
3335    
3336                            Matcher matcher = pattern.matcher(token);
3337    
3338                            if (matcher.find()) {
3339                                    StringBuffer hightlighted = new StringBuffer();
3340    
3341                                    do {
3342                                            matcher.appendReplacement(
3343                                                    hightlighted, highlight1 + matcher.group() +
3344                                                    highlight2);
3345                                    }
3346                                    while (matcher.find());
3347    
3348                                    matcher.appendTail(hightlighted);
3349    
3350                                    sb.append(hightlighted);
3351                            }
3352                            else {
3353                                    sb.append(token);
3354                            }
3355    
3356                            if (st.hasMoreTokens()) {
3357                                    sb.append(StringPool.SPACE);
3358                            }
3359                    }
3360    
3361                    return sb.toString();
3362            }
3363    
3364            /**
3365             * Returns <code>false</code> if the character is not whitespace or is equal
3366             * to any of the exception characters.
3367             *
3368             * @param  c the character whose trim-ability is to be determined
3369             * @param  exceptions the whitespace characters to exclude from trimming
3370             * @return <code>false</code> if the character is not whitespace or is equal
3371             *         to any of the exception characters; <code>true</code> otherwise
3372             */
3373            private static boolean _isTrimable(char c, char[] exceptions) {
3374                    for (char exception : exceptions) {
3375                            if (c == exception) {
3376                                    return false;
3377                            }
3378                    }
3379    
3380                    return Character.isWhitespace(c);
3381            }
3382    
3383            private static String _wrap(String text, int width, String lineSeparator)
3384                    throws IOException {
3385    
3386                    if (text == null) {
3387                            return null;
3388                    }
3389    
3390                    StringBundler sb = new StringBundler();
3391    
3392                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
3393                            new UnsyncStringReader(text));
3394    
3395                    String s = StringPool.BLANK;
3396    
3397                    while ((s = unsyncBufferedReader.readLine()) != null) {
3398                            if (s.length() == 0) {
3399                                    sb.append(lineSeparator);
3400    
3401                                    continue;
3402                            }
3403    
3404                            int lineLength = 0;
3405    
3406                            String[] tokens = s.split(StringPool.SPACE);
3407    
3408                            for (String token : tokens) {
3409                                    if ((lineLength + token.length() + 1) > width) {
3410                                            if (lineLength > 0) {
3411                                                    sb.append(lineSeparator);
3412                                            }
3413    
3414                                            if (token.length() > width) {
3415                                                    int pos = token.indexOf(CharPool.OPEN_PARENTHESIS);
3416    
3417                                                    if (pos != -1) {
3418                                                            sb.append(token.substring(0, pos + 1));
3419                                                            sb.append(lineSeparator);
3420    
3421                                                            token = token.substring(pos + 1);
3422    
3423                                                            sb.append(token);
3424    
3425                                                            lineLength = token.length();
3426                                                    }
3427                                                    else {
3428                                                            sb.append(token);
3429    
3430                                                            lineLength = token.length();
3431                                                    }
3432                                            }
3433                                            else {
3434                                                    sb.append(token);
3435    
3436                                                    lineLength = token.length();
3437                                            }
3438                                    }
3439                                    else {
3440                                            if (lineLength > 0) {
3441                                                    sb.append(StringPool.SPACE);
3442    
3443                                                    lineLength++;
3444                                            }
3445    
3446                                            sb.append(token);
3447    
3448                                            lineLength += token.length();
3449                                    }
3450                            }
3451    
3452                            sb.append(lineSeparator);
3453                    }
3454    
3455                    return sb.toString();
3456            }
3457    
3458            private static final char[] _HEX_DIGITS = {
3459                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
3460                    'e', 'f'
3461            };
3462    
3463            private static Log _log = LogFactoryUtil.getLog(StringUtil.class);
3464    
3465            private static String[] _emptyStringArray = new String[0];
3466    
3467    }