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