001    /**
002     * Copyright (c) 2000-2011 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     * @author Brian Wing Shun Chan
039     * @author Sandeep Soni
040     * @author Ganesh Ram
041     */
042    public class StringUtil {
043    
044            public static String add(String s, String add) {
045                    return add(s, add, StringPool.COMMA);
046            }
047    
048            public static String add(String s, String add, String delimiter) {
049                    return add(s, add, delimiter, false);
050            }
051    
052            public static String add(
053                    String s, String add, String delimiter, boolean allowDuplicates) {
054    
055                    if ((add == null) || (delimiter == null)) {
056                            return null;
057                    }
058    
059                    if (s == null) {
060                            s = StringPool.BLANK;
061                    }
062    
063                    if (allowDuplicates || !contains(s, add, delimiter)) {
064                            StringBundler sb = new StringBundler();
065    
066                            sb.append(s);
067    
068                            if (Validator.isNull(s) || s.endsWith(delimiter)) {
069                                    sb.append(add);
070                                    sb.append(delimiter);
071                            }
072                            else {
073                                    sb.append(delimiter);
074                                    sb.append(add);
075                                    sb.append(delimiter);
076                            }
077    
078                            s = sb.toString();
079                    }
080    
081                    return s;
082            }
083    
084            public static String bytesToHexString(byte[] bytes) {
085                    StringBuilder sb = new StringBuilder(bytes.length * 2);
086    
087                    for (int i = 0; i < bytes.length; i++) {
088                            String hex = Integer.toHexString(
089                                    0x0100 + (bytes[i] & 0x00FF)).substring(1);
090    
091                            if (hex.length() < 2) {
092                                    sb.append("0");
093                            }
094    
095                            sb.append(hex);
096                    }
097    
098                    return sb.toString();
099            }
100    
101            public static boolean contains(String s, String text) {
102                    return contains(s, text, StringPool.COMMA);
103            }
104    
105            public static boolean contains(String s, String text, String delimiter) {
106                    if ((s == null) || (text == null) || (delimiter == null)) {
107                            return false;
108                    }
109    
110                    if (!s.endsWith(delimiter)) {
111                            s = s.concat(delimiter);
112                    }
113    
114                    String dtd = delimiter.concat(text).concat(delimiter);
115    
116                    int pos = s.indexOf(dtd);
117    
118                    if (pos == -1) {
119                            String td = text.concat(delimiter);
120    
121                            if (s.startsWith(td)) {
122                                    return true;
123                            }
124    
125                            return false;
126                    }
127    
128                    return true;
129            }
130    
131            public static int count(String s, String text) {
132                    if ((s == null) || (text == null)) {
133                            return 0;
134                    }
135    
136                    int count = 0;
137    
138                    int pos = s.indexOf(text);
139    
140                    while (pos != -1) {
141                            pos = s.indexOf(text, pos + text.length());
142    
143                            count++;
144                    }
145    
146                    return count;
147            }
148    
149            public static boolean endsWith(String s, char end) {
150                    return endsWith(s, (new Character(end)).toString());
151            }
152    
153            public static boolean endsWith(String s, String end) {
154                    if ((s == null) || (end == null)) {
155                            return false;
156                    }
157    
158                    if (end.length() > s.length()) {
159                            return false;
160                    }
161    
162                    String temp = s.substring(s.length() - end.length(), s.length());
163    
164                    if (temp.equalsIgnoreCase(end)) {
165                            return true;
166                    }
167                    else {
168                            return false;
169                    }
170            }
171    
172            public static String extractChars(String s) {
173                    if (s == null) {
174                            return StringPool.BLANK;
175                    }
176    
177                    StringBuilder sb = new StringBuilder();
178    
179                    char[] chars = s.toCharArray();
180    
181                    for (int i = 0; i < chars.length; i++) {
182                            if (Validator.isChar(chars[i])) {
183                                    sb.append(chars[i]);
184                            }
185                    }
186    
187                    return sb.toString();
188            }
189    
190            public static String extractDigits(String s) {
191                    if (s == null) {
192                            return StringPool.BLANK;
193                    }
194    
195                    StringBuilder sb = new StringBuilder();
196    
197                    char[] chars = s.toCharArray();
198    
199                    for (int i = 0; i < chars.length; i++) {
200                            if (Validator.isDigit(chars[i])) {
201                                    sb.append(chars[i]);
202                            }
203                    }
204    
205                    return sb.toString();
206            }
207    
208            public static String extractFirst(String s, String delimiter) {
209                    if (s == null) {
210                            return null;
211                    }
212                    else {
213                            String[] array = split(s, delimiter);
214    
215                            if (array.length > 0) {
216                                    return array[0];
217                            }
218                            else {
219                                    return null;
220                            }
221                    }
222            }
223    
224            public static String extractLast(String s, String delimiter) {
225                    if (s == null) {
226                            return null;
227                    }
228                    else {
229                            String[] array = split(s, delimiter);
230    
231                            if (array.length > 0) {
232                                    return array[array.length - 1];
233                            }
234                            else {
235                                    return null;
236                            }
237                    }
238            }
239    
240            /**
241             * @deprecated
242             */
243            public static String highlight(String s, String keywords) {
244                    return highlight(s, keywords, "<span class=\"highlight\">", "</span>");
245            }
246    
247            /**
248             * @deprecated
249             */
250            public static String highlight(
251                    String s, String keywords, String highlight1, String highlight2) {
252    
253                    if (Validator.isNull(s) || Validator.isNull(keywords)) {
254                            return s;
255                    }
256    
257                    Pattern pattern = Pattern.compile(
258                            Pattern.quote(keywords), Pattern.CASE_INSENSITIVE);
259    
260                    return _highlight(s, pattern, highlight1, highlight2);
261            }
262    
263            public static String highlight(String s, String[] queryTerms) {
264                    return highlight(
265                            s, queryTerms, "<span class=\"highlight\">", "</span>");
266            }
267    
268            public static String highlight(
269                    String s, String[] queryTerms, String highlight1, String highlight2) {
270    
271                    if (Validator.isNull(s) || Validator.isNull(queryTerms)) {
272                            return s;
273                    }
274    
275                    StringBundler sb = null;
276    
277                    if (queryTerms.length == 0) {
278                            sb = new StringBundler();
279                    }
280                    else {
281                            sb = new StringBundler(2 * queryTerms.length - 1);
282                    }
283    
284                    for (int i = 0; i < queryTerms.length; i++) {
285                            sb.append(Pattern.quote(queryTerms[i].trim()));
286    
287                            if ((i + 1) < queryTerms.length) {
288                                    sb.append(StringPool.PIPE);
289                            }
290                    }
291    
292                    int flags =
293                            Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
294    
295                    Pattern pattern = Pattern.compile(sb.toString(), flags);
296    
297                    return _highlight(s, pattern, highlight1, highlight2);
298            }
299    
300            public static String insert(String s, String insert, int offset) {
301                    if (s == null) {
302                            return null;
303                    }
304    
305                    if (insert == null) {
306                            return s;
307                    }
308    
309                    if (offset > s.length()) {
310                            offset = s.length();
311                    }
312    
313                    StringBuilder sb = new StringBuilder(s);
314    
315                    sb.insert(offset, insert);
316    
317                    return sb.toString();
318            }
319    
320            public static String lowerCase(String s) {
321                    if (s == null) {
322                            return null;
323                    }
324                    else {
325                            return s.toLowerCase();
326                    }
327            }
328    
329            public static boolean matches(String s, String pattern) {
330                    String[] array = pattern.split("\\*");
331    
332                    for (int i = 0; i < array.length; i++) {
333                            int pos = s.indexOf(array[i]);
334    
335                            if (pos == -1) {
336                                    return false;
337                            }
338    
339                            s = s.substring(pos + array[i].length());
340                    }
341    
342                    return true;
343            }
344    
345            public static String merge(boolean[] array) {
346                    return merge(array, StringPool.COMMA);
347            }
348    
349            public static String merge(boolean[] array, String delimiter) {
350                    if (array == null) {
351                            return null;
352                    }
353    
354                    StringBundler sb = null;
355    
356                    if (array.length == 0) {
357                            sb = new StringBundler();
358                    }
359                    else {
360                            sb = new StringBundler(2 * array.length - 1);
361                    }
362    
363                    for (int i = 0; i < array.length; i++) {
364                            sb.append(String.valueOf(array[i]).trim());
365    
366                            if ((i + 1) != array.length) {
367                                    sb.append(delimiter);
368                            }
369                    }
370    
371                    return sb.toString();
372            }
373    
374            public static String merge(Collection<?> col) {
375                    return merge(col, StringPool.COMMA);
376            }
377    
378            public static String merge(Collection<?> col, String delimiter) {
379                    if (col == null) {
380                            return null;
381                    }
382    
383                    return merge(col.toArray(new Object[col.size()]), delimiter);
384            }
385    
386            public static String merge(double[] array) {
387                    return merge(array, StringPool.COMMA);
388            }
389    
390            public static String merge(double[] array, String delimiter) {
391                    if (array == null) {
392                            return null;
393                    }
394    
395                    StringBundler sb = null;
396    
397                    if (array.length == 0) {
398                            sb = new StringBundler();
399                    }
400                    else {
401                            sb = new StringBundler(2 * array.length - 1);
402                    }
403    
404                    for (int i = 0; i < array.length; i++) {
405                            sb.append(String.valueOf(array[i]).trim());
406    
407                            if ((i + 1) != array.length) {
408                                    sb.append(delimiter);
409                            }
410                    }
411    
412                    return sb.toString();
413            }
414    
415            public static String merge(float[] array) {
416                    return merge(array, StringPool.COMMA);
417            }
418    
419            public static String merge(float[] array, String delimiter) {
420                    if (array == null) {
421                            return null;
422                    }
423    
424                    StringBundler sb = null;
425    
426                    if (array.length == 0) {
427                            sb = new StringBundler();
428                    }
429                    else {
430                            sb = new StringBundler(2 * array.length - 1);
431                    }
432    
433                    for (int i = 0; i < array.length; i++) {
434                            sb.append(String.valueOf(array[i]).trim());
435    
436                            if ((i + 1) != array.length) {
437                                    sb.append(delimiter);
438                            }
439                    }
440    
441                    return sb.toString();
442            }
443    
444            public static String merge(int[] array) {
445                    return merge(array, StringPool.COMMA);
446            }
447    
448            public static String merge(int[] array, String delimiter) {
449                    if (array == null) {
450                            return null;
451                    }
452    
453                    StringBundler sb = null;
454    
455                    if (array.length == 0){
456                            sb = new StringBundler();
457                    }
458                    else {
459                            sb = new StringBundler(2 * array.length - 1);
460                    }
461    
462                    for (int i = 0; i < array.length; i++) {
463                            sb.append(String.valueOf(array[i]).trim());
464    
465                            if ((i + 1) != array.length) {
466                                    sb.append(delimiter);
467                            }
468                    }
469    
470                    return sb.toString();
471            }
472    
473            public static String merge(long[] array) {
474                    return merge(array, StringPool.COMMA);
475            }
476    
477            public static String merge(long[] array, String delimiter) {
478                    if (array == null) {
479                            return null;
480                    }
481    
482                    StringBundler sb = null;
483    
484                    if (array.length == 0) {
485                            sb = new StringBundler();
486                    }
487                    else {
488                            sb = new StringBundler(2 * array.length - 1);
489                    }
490    
491                    for (int i = 0; i < array.length; i++) {
492                            sb.append(String.valueOf(array[i]).trim());
493    
494                            if ((i + 1) != array.length) {
495                                    sb.append(delimiter);
496                            }
497                    }
498    
499                    return sb.toString();
500            }
501    
502            public static String merge(Object[] array) {
503                    return merge(array, StringPool.COMMA);
504            }
505    
506            public static String merge(Object[] array, String delimiter) {
507                    if (array == null) {
508                            return null;
509                    }
510    
511                    StringBundler sb = null;
512    
513                    if (array.length == 0) {
514                            sb = new StringBundler();
515                    }
516                    else {
517                            sb = new StringBundler(2 * array.length - 1);
518                    }
519    
520                    for (int i = 0; i < array.length; i++) {
521                            sb.append(String.valueOf(array[i]).trim());
522    
523                            if ((i + 1) != array.length) {
524                                    sb.append(delimiter);
525                            }
526                    }
527    
528                    return sb.toString();
529            }
530    
531            public static String merge(short[] array) {
532                    return merge(array, StringPool.COMMA);
533            }
534    
535            public static String merge(short[] array, String delimiter) {
536                    if (array == null) {
537                            return null;
538                    }
539    
540                    StringBundler sb = null;
541    
542                    if (array.length == 0) {
543                            sb = new StringBundler();
544                    }
545                    else {
546                            sb = new StringBundler(2 * array.length - 1);
547                    }
548    
549                    for (int i = 0; i < array.length; i++) {
550                            sb.append(String.valueOf(array[i]).trim());
551    
552                            if ((i + 1) != array.length) {
553                                    sb.append(delimiter);
554                            }
555                    }
556    
557                    return sb.toString();
558            }
559    
560            public static String randomize(String s) {
561                    return Randomizer.getInstance().randomize(s);
562            }
563    
564            public static String read(ClassLoader classLoader, String name)
565                    throws IOException {
566    
567                    return read(classLoader, name, false);
568            }
569    
570            public static String read(ClassLoader classLoader, String name, boolean all)
571                    throws IOException {
572    
573                    if (all) {
574                            StringBundler sb = new StringBundler();
575    
576                            Enumeration<URL> enu = classLoader.getResources(name);
577    
578                            while (enu.hasMoreElements()) {
579                                    URL url = enu.nextElement();
580    
581                                    InputStream is = url.openStream();
582    
583                                    if (is == null) {
584                                            throw new IOException(
585                                                    "Unable to open resource at " + url.toString());
586                                    }
587    
588                                    String s = read(is);
589    
590                                    if (s != null) {
591                                            sb.append(s);
592                                            sb.append(StringPool.NEW_LINE);
593                                    }
594    
595                                    is.close();
596                            }
597    
598                            return sb.toString().trim();
599                    }
600                    else {
601                            InputStream is = classLoader.getResourceAsStream(name);
602    
603                            if (is == null) {
604                                    throw new IOException(
605                                            "Unable to open resource in class loader " + name);
606                            }
607    
608                            String s = read(is);
609    
610                            is.close();
611    
612                            return s;
613                    }
614            }
615    
616            public static String read(InputStream is) throws IOException {
617                    StringBundler sb = new StringBundler();
618    
619                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
620                            new InputStreamReader(is));
621    
622                    String line = null;
623    
624                    while ((line = unsyncBufferedReader.readLine()) != null) {
625                            sb.append(line);
626                            sb.append(CharPool.NEW_LINE);
627                    }
628    
629                    unsyncBufferedReader.close();
630    
631                    return sb.toString().trim();
632            }
633    
634            public static void readLines(InputStream is, Collection<String> lines)
635                    throws IOException {
636    
637                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
638                            new InputStreamReader(is));
639    
640                    String line = null;
641    
642                    while ((line = unsyncBufferedReader.readLine()) != null) {
643                            lines.add(line);
644                    }
645    
646                    unsyncBufferedReader.close();
647            }
648    
649            public static String remove(String s, String remove) {
650                    return remove(s, remove, StringPool.COMMA);
651            }
652    
653            public static String remove(String s, String remove, String delimiter) {
654                    if ((s == null) || (remove == null) || (delimiter == null)) {
655                            return null;
656                    }
657    
658                    if (Validator.isNotNull(s) && !s.endsWith(delimiter)) {
659                            s += delimiter;
660                    }
661    
662                    String drd = delimiter.concat(remove).concat(delimiter);
663    
664                    String rd = remove.concat(delimiter);
665    
666                    while (contains(s, remove, delimiter)) {
667                            int pos = s.indexOf(drd);
668    
669                            if (pos == -1) {
670                                    if (s.startsWith(rd)) {
671                                            int x = remove.length() + delimiter.length();
672                                            int y = s.length();
673    
674                                            s = s.substring(x, y);
675                                    }
676                            }
677                            else {
678                                    int x = pos + remove.length() + delimiter.length();
679                                    int y = s.length();
680    
681                                    String temp = s.substring(0, pos);
682    
683                                    s = temp.concat(s.substring(x, y));
684                            }
685                    }
686    
687                    return s;
688            }
689    
690            public static String replace(String s, char oldSub, char newSub) {
691                    if (s == null) {
692                            return null;
693                    }
694    
695                    return s.replace(oldSub, newSub);
696            }
697    
698            public static String replace(String s, char oldSub, String newSub) {
699                    if ((s == null) || (newSub == null)) {
700                            return null;
701                    }
702    
703                    // The number 5 is arbitrary and is used as extra padding to reduce
704                    // buffer expansion
705    
706                    StringBuilder sb = new StringBuilder(s.length() + 5 * newSub.length());
707    
708                    char[] chars = s.toCharArray();
709    
710                    for (char c : chars) {
711                            if (c == oldSub) {
712                                    sb.append(newSub);
713                            }
714                            else {
715                                    sb.append(c);
716                            }
717                    }
718    
719                    return sb.toString();
720            }
721    
722            public static String replace(String s, String oldSub, String newSub) {
723                    return replace(s, oldSub, newSub, 0);
724            }
725    
726            public static String replace(
727                    String s, String oldSub, String newSub, int fromIndex) {
728    
729                    if ((s == null) || (oldSub == null) || (newSub == null)) {
730                            return null;
731                    }
732    
733                    if (oldSub.equals(StringPool.BLANK)) {
734                            return s;
735                    }
736    
737                    int y = s.indexOf(oldSub, fromIndex);
738    
739                    if (y >= 0) {
740                            StringBundler sb = new StringBundler();
741    
742                            int length = oldSub.length();
743                            int x = 0;
744    
745                            while (x <= y) {
746                                    sb.append(s.substring(x, y));
747                                    sb.append(newSub);
748    
749                                    x = y + length;
750                                    y = s.indexOf(oldSub, x);
751                            }
752    
753                            sb.append(s.substring(x));
754    
755                            return sb.toString();
756                    }
757                    else {
758                            return s;
759                    }
760            }
761    
762            public static String replace(
763                    String s, String begin, String end, Map<String, String> values) {
764    
765                    StringBundler sb = replaceToStringBundler(s, begin, end, values);
766    
767                    return sb.toString();
768            }
769    
770            public static String replace(String s, String[] oldSubs, String[] newSubs) {
771                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
772                            return null;
773                    }
774    
775                    if (oldSubs.length != newSubs.length) {
776                            return s;
777                    }
778    
779                    for (int i = 0; i < oldSubs.length; i++) {
780                            s = replace(s, oldSubs[i], newSubs[i]);
781                    }
782    
783                    return s;
784            }
785    
786            public static String replace(
787                    String s, String[] oldSubs, String[] newSubs, boolean exactMatch) {
788    
789                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
790                            return null;
791                    }
792    
793                    if (oldSubs.length != newSubs.length) {
794                            return s;
795                    }
796    
797                    if (!exactMatch) {
798                            replace(s, oldSubs, newSubs);
799                    }
800                    else {
801                            for (int i = 0; i < oldSubs.length; i++) {
802                                    s = s.replaceAll("\\b" + oldSubs[i] + "\\b" , newSubs[i]);
803                            }
804                    }
805    
806                    return s;
807            }
808    
809            public static String replaceFirst(String s, char oldSub, char newSub) {
810                    if (s == null) {
811                            return null;
812                    }
813    
814                    return replaceFirst(s, String.valueOf(oldSub), String.valueOf(newSub));
815            }
816    
817            public static String replaceFirst(String s, char oldSub, String newSub) {
818                    if ((s == null) || (newSub == null)) {
819                            return null;
820                    }
821    
822                    return replaceFirst(s, String.valueOf(oldSub), newSub);
823            }
824    
825            public static String replaceFirst(String s, String oldSub, String newSub) {
826                    if ((s == null) || (oldSub == null) || (newSub == null)) {
827                            return null;
828                    }
829    
830                    if (oldSub.equals(newSub)) {
831                            return s;
832                    }
833    
834                    int y = s.indexOf(oldSub);
835    
836                    if (y >= 0) {
837                            return s.substring(0, y).concat(newSub).concat(
838                                    s.substring(y + oldSub.length()));
839                    }
840                    else {
841                            return s;
842                    }
843            }
844    
845            public static String replaceFirst(
846                    String s, String[] oldSubs, String[] newSubs) {
847    
848                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
849                            return null;
850                    }
851    
852                    if (oldSubs.length != newSubs.length) {
853                            return s;
854                    }
855    
856                    for (int i = 0; i < oldSubs.length; i++) {
857                            s = replaceFirst(s, oldSubs[i], newSubs[i]);
858                    }
859    
860                    return s;
861            }
862    
863            public static String replaceLast(String s, char oldSub, char newSub) {
864                    if (s == null) {
865                            return null;
866                    }
867    
868                    return replaceLast(s, String.valueOf(oldSub), String.valueOf(newSub));
869            }
870    
871            public static String replaceLast(String s, char oldSub, String newSub) {
872                    if ((s == null) || (newSub == null)) {
873                            return null;
874                    }
875    
876                    return replaceLast(s, String.valueOf(oldSub), newSub);
877            }
878    
879            public static String replaceLast(String s, String oldSub, String newSub) {
880                    if ((s == null) || (oldSub == null) || (newSub == null)) {
881                            return null;
882                    }
883    
884                    if (oldSub.equals(newSub)) {
885                            return s;
886                    }
887    
888                    int y = s.lastIndexOf(oldSub);
889    
890                    if (y >= 0) {
891                            return s.substring(0, y).concat(newSub).concat(
892                                    s.substring(y + oldSub.length()));
893                    }
894                    else {
895                            return s;
896                    }
897            }
898    
899            public static String replaceLast(
900                    String s, String[] oldSubs, String[] newSubs) {
901    
902                    if ((s == null) || (oldSubs == null) || (newSubs == null)) {
903                            return null;
904                    }
905    
906                    if (oldSubs.length != newSubs.length) {
907                            return s;
908                    }
909    
910                    for (int i = 0; i < oldSubs.length; i++) {
911                            s = replaceLast(s, oldSubs[i], newSubs[i]);
912                    }
913    
914                    return s;
915            }
916    
917            public static StringBundler replaceToStringBundler(
918                    String s, String begin, String end, Map<String, String> values) {
919    
920                    if ((s == null) || (begin == null) || (end == null) ||
921                            (values == null) || (values.size() == 0)) {
922    
923                            return new StringBundler(s);
924                    }
925    
926                    StringBundler sb = new StringBundler(values.size() * 2 + 1);
927    
928                    int pos = 0;
929    
930                    while (true) {
931                            int x = s.indexOf(begin, pos);
932                            int y = s.indexOf(end, x + begin.length());
933    
934                            if ((x == -1) || (y == -1)) {
935                                    sb.append(s.substring(pos, s.length()));
936    
937                                    break;
938                            }
939                            else {
940                                    sb.append(s.substring(pos, x));
941    
942                                    String oldValue = s.substring(x + begin.length(), y);
943    
944                                    String newValue = values.get(oldValue);
945    
946                                    if (newValue == null) {
947                                            newValue = oldValue;
948                                    }
949    
950                                    sb.append(newValue);
951    
952                                    pos = y + end.length();
953                            }
954                    }
955    
956                    return sb;
957            }
958    
959            public static StringBundler replaceWithStringBundler(
960                    String s, String begin, String end, Map<String, StringBundler> values) {
961    
962                    if ((s == null) || (begin == null) || (end == null) ||
963                            (values == null) || (values.size() == 0)) {
964    
965                            return new StringBundler(s);
966                    }
967    
968                    int size = values.size() + 1;
969    
970                    for (StringBundler valueSB : values.values()) {
971                            size += valueSB.index();
972                    }
973    
974                    StringBundler sb = new StringBundler(size);
975    
976                    int pos = 0;
977    
978                    while (true) {
979                            int x = s.indexOf(begin, pos);
980                            int y = s.indexOf(end, x + begin.length());
981    
982                            if ((x == -1) || (y == -1)) {
983                                    sb.append(s.substring(pos, s.length()));
984    
985                                    break;
986                            }
987                            else {
988                                    sb.append(s.substring(pos, x));
989    
990                                    String oldValue = s.substring(x + begin.length(), y);
991    
992                                    StringBundler newValue = values.get(oldValue);
993    
994                                    if (newValue == null) {
995                                            sb.append(oldValue);
996                                    }
997                                    else {
998                                            sb.append(newValue);
999                                    }
1000    
1001                                    pos = y + end.length();
1002                            }
1003                    }
1004    
1005                    return sb;
1006            }
1007    
1008            public static String reverse(String s) {
1009                    if (s == null) {
1010                            return null;
1011                    }
1012    
1013                    char[] chars = s.toCharArray();
1014                    char[] reverse = new char[chars.length];
1015    
1016                    for (int i = 0; i < chars.length; i++) {
1017                            reverse[i] = chars[chars.length - i - 1];
1018                    }
1019    
1020                    return new String(reverse);
1021            }
1022    
1023            public static String safePath(String path) {
1024                    return replace(path, StringPool.DOUBLE_SLASH, StringPool.SLASH);
1025            }
1026    
1027            public static String shorten(String s) {
1028                    return shorten(s, 20);
1029            }
1030    
1031            public static String shorten(String s, int length) {
1032                    return shorten(s, length, "...");
1033            }
1034    
1035            public static String shorten(String s, int length, String suffix) {
1036                    if ((s == null) || (suffix == null)) {
1037                            return null;
1038                    }
1039    
1040                    if (s.length() > length) {
1041                            for (int j = length; j >= 0; j--) {
1042                                    if (Character.isWhitespace(s.charAt(j))) {
1043                                            length = j;
1044    
1045                                            break;
1046                                    }
1047                            }
1048    
1049                            String temp = s.substring(0, length);
1050    
1051                            s = temp.concat(suffix);
1052                    }
1053    
1054                    return s;
1055            }
1056    
1057            public static String shorten(String s, String suffix) {
1058                    return shorten(s, 20, suffix);
1059            }
1060    
1061            public static String[] split(String s) {
1062                    return split(s, StringPool.COMMA);
1063            }
1064    
1065            public static boolean[] split(String s, boolean x) {
1066                    return split(s, StringPool.COMMA, x);
1067            }
1068    
1069            public static double[] split(String s, double x) {
1070                    return split(s, StringPool.COMMA, x);
1071            }
1072    
1073            public static float[] split(String s, float x) {
1074                    return split(s, StringPool.COMMA, x);
1075            }
1076    
1077            public static int[] split(String s, int x) {
1078                    return split(s, StringPool.COMMA, x);
1079            }
1080    
1081            public static long[] split(String s, long x) {
1082                    return split(s, StringPool.COMMA, x);
1083            }
1084    
1085            public static short[] split(String s, short x) {
1086                    return split(s, StringPool.COMMA, x);
1087            }
1088    
1089            public static String[] split(String s, String delimiter) {
1090                    if ((Validator.isNull(s)) || (delimiter == null) ||
1091                            (delimiter.equals(StringPool.BLANK))) {
1092    
1093                            return new String[0];
1094                    }
1095    
1096                    s = s.trim();
1097    
1098                    if (s.equals(delimiter)) {
1099                            return new String[0];
1100                    }
1101    
1102                    List<String> nodeValues = new ArrayList<String>();
1103    
1104                    if (delimiter.equals(StringPool.NEW_LINE) ||
1105                            delimiter.equals(StringPool.RETURN)) {
1106    
1107                            try {
1108                                    UnsyncBufferedReader unsyncBufferedReader =
1109                                            new UnsyncBufferedReader(new UnsyncStringReader(s));
1110    
1111                                    String line = null;
1112    
1113                                    while ((line = unsyncBufferedReader.readLine()) != null) {
1114                                            nodeValues.add(line);
1115                                    }
1116    
1117                                    unsyncBufferedReader.close();
1118                            }
1119                            catch (IOException ioe) {
1120                                    _log.error(ioe.getMessage());
1121                            }
1122                    }
1123                    else {
1124                            int offset = 0;
1125                            int pos = s.indexOf(delimiter, offset);
1126    
1127                            while (pos != -1) {
1128                                    nodeValues.add(s.substring(offset, pos));
1129    
1130                                    offset = pos + delimiter.length();
1131                                    pos = s.indexOf(delimiter, offset);
1132                            }
1133    
1134                            if (offset < s.length()) {
1135                                    nodeValues.add(s.substring(offset));
1136                            }
1137                    }
1138    
1139                    return nodeValues.toArray(new String[nodeValues.size()]);
1140            }
1141    
1142            public static boolean[] split(String s, String delimiter, boolean x) {
1143                    String[] array = split(s, delimiter);
1144                    boolean[] newArray = new boolean[array.length];
1145    
1146                    for (int i = 0; i < array.length; i++) {
1147                            boolean value = x;
1148    
1149                            try {
1150                                    value = Boolean.valueOf(array[i]).booleanValue();
1151                            }
1152                            catch (Exception e) {
1153                            }
1154    
1155                            newArray[i] = value;
1156                    }
1157    
1158                    return newArray;
1159            }
1160    
1161            public static double[] split(String s, String delimiter, double x) {
1162                    String[] array = split(s, delimiter);
1163                    double[] newArray = new double[array.length];
1164    
1165                    for (int i = 0; i < array.length; i++) {
1166                            double value = x;
1167    
1168                            try {
1169                                    value = Double.parseDouble(array[i]);
1170                            }
1171                            catch (Exception e) {
1172                            }
1173    
1174                            newArray[i] = value;
1175                    }
1176    
1177                    return newArray;
1178            }
1179    
1180            public static float[] split(String s, String delimiter, float x) {
1181                    String[] array = split(s, delimiter);
1182                    float[] newArray = new float[array.length];
1183    
1184                    for (int i = 0; i < array.length; i++) {
1185                            float value = x;
1186    
1187                            try {
1188                                    value = Float.parseFloat(array[i]);
1189                            }
1190                            catch (Exception e) {
1191                            }
1192    
1193                            newArray[i] = value;
1194                    }
1195    
1196                    return newArray;
1197            }
1198    
1199            public static int[] split(String s, String delimiter, int x) {
1200                    String[] array = split(s, delimiter);
1201                    int[] newArray = new int[array.length];
1202    
1203                    for (int i = 0; i < array.length; i++) {
1204                            int value = x;
1205    
1206                            try {
1207                                    value = Integer.parseInt(array[i]);
1208                            }
1209                            catch (Exception e) {
1210                            }
1211    
1212                            newArray[i] = value;
1213                    }
1214    
1215                    return newArray;
1216            }
1217    
1218            public static long[] split(String s, String delimiter, long x) {
1219                    String[] array = split(s, delimiter);
1220                    long[] newArray = new long[array.length];
1221    
1222                    for (int i = 0; i < array.length; i++) {
1223                            long value = x;
1224    
1225                            try {
1226                                    value = Long.parseLong(array[i]);
1227                            }
1228                            catch (Exception e) {
1229                            }
1230    
1231                            newArray[i] = value;
1232                    }
1233    
1234                    return newArray;
1235            }
1236    
1237            public static short[] split(String s, String delimiter, short x) {
1238                    String[] array = split(s, delimiter);
1239                    short[] newArray = new short[array.length];
1240    
1241                    for (int i = 0; i < array.length; i++) {
1242                            short value = x;
1243    
1244                            try {
1245                                    value = Short.parseShort(array[i]);
1246                            }
1247                            catch (Exception e) {
1248                            }
1249    
1250                            newArray[i] = value;
1251                    }
1252    
1253                    return newArray;
1254            }
1255    
1256            public static boolean startsWith(String s, char begin) {
1257                    return startsWith(s, (new Character(begin)).toString());
1258            }
1259    
1260            public static boolean startsWith(String s, String start) {
1261                    if ((s == null) || (start == null)) {
1262                            return false;
1263                    }
1264    
1265                    if (start.length() > s.length()) {
1266                            return false;
1267                    }
1268    
1269                    String temp = s.substring(0, start.length());
1270    
1271                    if (temp.equalsIgnoreCase(start)) {
1272                            return true;
1273                    }
1274                    else {
1275                            return false;
1276                    }
1277            }
1278    
1279            /**
1280             * Return the number of starting letters that s1 and s2 have in common
1281             * before they deviate.
1282             *
1283             * @return the number of starting letters that s1 and s2 have in common
1284             *         before they deviate
1285             */
1286            public static int startsWithWeight(String s1, String s2) {
1287                    if ((s1 == null) || (s2 == null)) {
1288                            return 0;
1289                    }
1290    
1291                    char[] chars1 = s1.toCharArray();
1292                    char[] chars2 = s2.toCharArray();
1293    
1294                    int i = 0;
1295    
1296                    for (; (i < chars1.length) && (i < chars2.length); i++) {
1297                            if (chars1[i] != chars2[i]) {
1298                                    break;
1299                            }
1300                    }
1301    
1302                    return i;
1303            }
1304    
1305            public static String strip(String s, char remove) {
1306                    if (s == null) {
1307                            return null;
1308                    }
1309    
1310                    int x = s.indexOf(remove);
1311    
1312                    if (x < 0) {
1313                            return s;
1314                    }
1315    
1316                    int y = 0;
1317    
1318                    StringBuilder sb = new StringBuilder(s.length());
1319    
1320                    while (x >= 0) {
1321                            sb.append(s.subSequence(y, x));
1322    
1323                            y = x + 1;
1324    
1325                            x = s.indexOf(remove, y);
1326                    }
1327    
1328                    sb.append(s.substring(y));
1329    
1330                    return sb.toString();
1331            }
1332    
1333            public static String stripBetween(String s, String begin, String end) {
1334                    if ((s == null) || (begin == null) || (end == null)) {
1335                            return s;
1336                    }
1337    
1338                    StringBuilder sb = new StringBuilder(s.length());
1339    
1340                    int pos = 0;
1341    
1342                    while (true) {
1343                            int x = s.indexOf(begin, pos);
1344                            int y = s.indexOf(end, x + begin.length());
1345    
1346                            if ((x == -1) || (y == -1)) {
1347                                    sb.append(s.substring(pos, s.length()));
1348    
1349                                    break;
1350                            }
1351                            else {
1352                                    sb.append(s.substring(pos, x));
1353    
1354                                    pos = y + end.length();
1355                            }
1356                    }
1357    
1358                    return sb.toString();
1359            }
1360    
1361            public static String toCharCode(String s) {
1362                    StringBundler sb = new StringBundler(s.length());
1363    
1364                    for (int i = 0; i < s.length(); i++) {
1365                            sb.append(s.codePointAt(i));
1366                    }
1367    
1368                    return sb.toString();
1369            }
1370    
1371            public static String toHexString(int i) {
1372                    char[] buffer = new char[8];
1373    
1374                    int index = 8;
1375    
1376                    do {
1377                            buffer[--index] = _HEX_DIGITS[i & 15];
1378    
1379                            i >>>= 4;
1380                    }
1381                    while (i != 0);
1382    
1383                    return new String(buffer, index, 8 - index);
1384            }
1385    
1386            public static String toHexString(long l) {
1387                    char[] buffer = new char[16];
1388    
1389                    int index = 16;
1390    
1391                    do {
1392                            buffer[--index] = _HEX_DIGITS[(int) (l & 15)];
1393    
1394                            l >>>= 4;
1395                    }
1396                    while (l != 0);
1397    
1398                    return new String(buffer, index, 16 - index);
1399            }
1400    
1401            public static String toHexString(Object obj) {
1402                    if (obj instanceof Integer) {
1403                            return toHexString(((Integer)obj).intValue());
1404                    }
1405                    else if (obj instanceof Long) {
1406                            return toHexString(((Long)obj).longValue());
1407                    }
1408                    else {
1409                            return String.valueOf(obj);
1410                    }
1411            }
1412    
1413            public static String trim(String s) {
1414                    return trim(s, null);
1415            }
1416    
1417            public static String trim(String s, char c) {
1418                    return trim(s, new char[] {c});
1419            }
1420    
1421            public static String trim(String s, char[] exceptions) {
1422                    if (s == null) {
1423                            return null;
1424                    }
1425    
1426                    char[] chars = s.toCharArray();
1427    
1428                    int len = chars.length;
1429    
1430                    int x = 0;
1431                    int y = chars.length;
1432    
1433                    for (int i = 0; i < len; i++) {
1434                            char c = chars[i];
1435    
1436                            if (_isTrimable(c, exceptions)) {
1437                                    x = i + 1;
1438                            }
1439                            else {
1440                                    break;
1441                            }
1442                    }
1443    
1444                    for (int i = len - 1; i >= 0; i--) {
1445                            char c = chars[i];
1446    
1447                            if (_isTrimable(c, exceptions)) {
1448                                    y = i;
1449                            }
1450                            else {
1451                                    break;
1452                            }
1453                    }
1454    
1455                    if ((x != 0) || (y != len)) {
1456                            return s.substring(x, y);
1457                    }
1458                    else {
1459                            return s;
1460                    }
1461            }
1462    
1463            public static String trimLeading(String s) {
1464                    return trimLeading(s, null);
1465            }
1466    
1467            public static String trimLeading(String s, char c) {
1468                    return trimLeading(s, new char[] {c});
1469            }
1470    
1471            public static String trimLeading(String s, char[] exceptions) {
1472                    if (s == null) {
1473                            return null;
1474                    }
1475    
1476                    char[] chars = s.toCharArray();
1477    
1478                    int len = chars.length;
1479    
1480                    int x = 0;
1481                    int y = chars.length;
1482    
1483                    for (int i = 0; i < len; i++) {
1484                            char c = chars[i];
1485    
1486                            if (_isTrimable(c, exceptions)) {
1487                                    x = i + 1;
1488                            }
1489                            else {
1490                                    break;
1491                            }
1492                    }
1493    
1494                    if ((x != 0) || (y != len)) {
1495                            return s.substring(x, y);
1496                    }
1497                    else {
1498                            return s;
1499                    }
1500            }
1501    
1502            public static String trimTrailing(String s) {
1503                    return trimTrailing(s, null);
1504            }
1505    
1506            public static String trimTrailing(String s, char c) {
1507                    return trimTrailing(s, new char[] {c});
1508            }
1509    
1510            public static String trimTrailing(String s, char[] exceptions) {
1511                    if (s == null) {
1512                            return null;
1513                    }
1514    
1515                    char[] chars = s.toCharArray();
1516    
1517                    int len = chars.length;
1518    
1519                    int x = 0;
1520                    int y = chars.length;
1521    
1522                    for (int i = len - 1; i >= 0; i--) {
1523                            char c = chars[i];
1524    
1525                            if (_isTrimable(c, exceptions)) {
1526                                    y = i;
1527                            }
1528                            else {
1529                                    break;
1530                            }
1531                    }
1532    
1533                    if ((x != 0) || (y != len)) {
1534                            return s.substring(x, y);
1535                    }
1536                    else {
1537                            return s;
1538                    }
1539            }
1540    
1541            public static String unquote(String s) {
1542                    if (Validator.isNull(s)) {
1543                            return s;
1544                    }
1545    
1546                    if ((s.charAt(0) == CharPool.APOSTROPHE) &&
1547                            (s.charAt(s.length() - 1) == CharPool.APOSTROPHE)) {
1548    
1549                            return s.substring(1, s.length() - 1);
1550                    }
1551                    else if ((s.charAt(0) == CharPool.QUOTE) &&
1552                                     (s.charAt(s.length() - 1) == CharPool.QUOTE)) {
1553    
1554                            return s.substring(1, s.length() - 1);
1555                    }
1556    
1557                    return s;
1558            }
1559    
1560            public static String upperCase(String s) {
1561                    if (s == null) {
1562                            return null;
1563                    }
1564                    else {
1565                            return s.toUpperCase();
1566                    }
1567            }
1568    
1569            public static String upperCaseFirstLetter(String s) {
1570                    char[] chars = s.toCharArray();
1571    
1572                    if ((chars[0] >= 97) && (chars[0] <= 122)) {
1573                            chars[0] = (char)(chars[0] - 32);
1574                    }
1575    
1576                    return new String(chars);
1577            }
1578    
1579            public static String valueOf(Object obj) {
1580                    return String.valueOf(obj);
1581            }
1582    
1583            public static String wrap(String text) {
1584                    return wrap(text, 80, StringPool.NEW_LINE);
1585            }
1586    
1587            public static String wrap(String text, int width, String lineSeparator) {
1588                    try {
1589                            return _wrap(text, width, lineSeparator);
1590                    }
1591                    catch (IOException ioe) {
1592                            _log.error(ioe.getMessage());
1593    
1594                            return text;
1595                    }
1596            }
1597    
1598            private static String _highlight(
1599                    String s, Pattern pattern, String highlight1, String highlight2) {
1600    
1601                    StringTokenizer st = new StringTokenizer(s);
1602    
1603                    StringBundler sb = null;
1604    
1605                    if (st.countTokens() == 0) {
1606                            sb = new StringBundler();
1607                    }
1608                    else {
1609                            sb = new StringBundler(2 * st.countTokens() - 1);
1610                    }
1611    
1612                    while (st.hasMoreTokens()) {
1613                            String token = st.nextToken();
1614    
1615                            Matcher matcher = pattern.matcher(token);
1616    
1617                            if (matcher.find()) {
1618                                    StringBuffer hightlighted = new StringBuffer();
1619    
1620                                    do {
1621                                            matcher.appendReplacement(
1622                                                    hightlighted, highlight1 + matcher.group() +
1623                                                    highlight2);
1624                                    }
1625                                    while (matcher.find());
1626    
1627                                    matcher.appendTail(hightlighted);
1628    
1629                                    sb.append(hightlighted);
1630                            }
1631                            else {
1632                                    sb.append(token);
1633                            }
1634    
1635                            if (st.hasMoreTokens()) {
1636                                    sb.append(StringPool.SPACE);
1637                            }
1638                    }
1639    
1640                    return sb.toString();
1641            }
1642    
1643            private static boolean _isTrimable(char c, char[] exceptions) {
1644                    if ((exceptions != null) && (exceptions.length > 0)) {
1645                            for (int i = 0; i < exceptions.length; i++) {
1646                                    if (c == exceptions[i]) {
1647                                            return false;
1648                                    }
1649                            }
1650                    }
1651    
1652                    return Character.isWhitespace(c);
1653            }
1654    
1655            private static String _wrap(String text, int width, String lineSeparator)
1656                    throws IOException {
1657    
1658                    if (text == null) {
1659                            return null;
1660                    }
1661    
1662                    StringBundler sb = new StringBundler();
1663    
1664                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
1665                            new UnsyncStringReader(text));
1666    
1667                    String s = StringPool.BLANK;
1668    
1669                    while ((s = unsyncBufferedReader.readLine()) != null) {
1670                            if (s.length() == 0) {
1671                                    sb.append(lineSeparator);
1672    
1673                                    continue;
1674                            }
1675    
1676                            int lineLength = 0;
1677    
1678                            String[] tokens = s.split(StringPool.SPACE);
1679    
1680                            for (String token : tokens) {
1681                                    if ((lineLength + token.length() + 1) > width) {
1682                                            if (lineLength > 0) {
1683                                                    sb.append(lineSeparator);
1684                                            }
1685    
1686                                            if (token.length() > width) {
1687                                                    int pos = token.indexOf(CharPool.OPEN_PARENTHESIS);
1688    
1689                                                    if (pos != -1) {
1690                                                            sb.append(token.substring(0, pos + 1));
1691                                                            sb.append(lineSeparator);
1692    
1693                                                            token = token.substring(pos + 1);
1694    
1695                                                            sb.append(token);
1696    
1697                                                            lineLength = token.length();
1698                                                    }
1699                                                    else {
1700                                                            sb.append(token);
1701    
1702                                                            lineLength = token.length();
1703                                                    }
1704                                            }
1705                                            else {
1706                                                    sb.append(token);
1707    
1708                                                    lineLength = token.length();
1709                                            }
1710                                    }
1711                                    else {
1712                                            if (lineLength > 0) {
1713                                                    sb.append(StringPool.SPACE);
1714    
1715                                                    lineLength++;
1716                                            }
1717    
1718                                            sb.append(token);
1719    
1720                                            lineLength += token.length();
1721                                    }
1722                            }
1723    
1724                            sb.append(lineSeparator);
1725                    }
1726    
1727                    return sb.toString();
1728            }
1729    
1730            private static final char[] _HEX_DIGITS = {
1731                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
1732                    'e', 'f'
1733            };
1734    
1735            private static Log _log = LogFactoryUtil.getLog(StringUtil.class);
1736    
1737    }