1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.kernel.util;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  
28  import java.io.BufferedReader;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.InputStreamReader;
32  import java.io.StringReader;
33  
34  import java.net.URL;
35  
36  import java.util.ArrayList;
37  import java.util.Enumeration;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.StringTokenizer;
41  
42  /**
43   * <a href="StringUtil.java.html"><b><i>View Source</i></b></a>
44   *
45   * @author Brian Wing Shun Chan
46   *
47   */
48  public class StringUtil {
49  
50      public static String add(String s, String add) {
51          return add(s, add, StringPool.COMMA);
52      }
53  
54      public static String add(String s, String add, String delimiter) {
55          return add(s, add, delimiter, false);
56      }
57  
58      public static String add(
59          String s, String add, String delimiter, boolean allowDuplicates) {
60  
61          if ((add == null) || (delimiter == null)) {
62              return null;
63          }
64  
65          if (s == null) {
66              s = StringPool.BLANK;
67          }
68  
69          if (allowDuplicates || !contains(s, add, delimiter)) {
70              StringMaker sm = new StringMaker();
71  
72              sm.append(s);
73  
74              if (Validator.isNull(s) || s.endsWith(delimiter)) {
75                  sm.append(add);
76                  sm.append(delimiter);
77              }
78              else {
79                  sm.append(delimiter);
80                  sm.append(add);
81                  sm.append(delimiter);
82              }
83  
84              s = sm.toString();
85          }
86  
87          return s;
88      }
89  
90      public static String bytesToHexString(byte[] bytes) {
91          StringMaker sm = new StringMaker(bytes.length * 2);
92  
93          for (int i = 0; i < bytes.length; i++) {
94              String hex = Integer.toHexString(
95                  0x0100 + (bytes[i] & 0x00FF)).substring(1);
96  
97              if (hex.length() < 2) {
98                  sm.append("0");
99              }
100 
101             sm.append(hex);
102         }
103 
104         return sm.toString();
105     }
106 
107     public static boolean contains(String s, String text) {
108         return contains(s, text, StringPool.COMMA);
109     }
110 
111     public static boolean contains(String s, String text, String delimiter) {
112         if ((s == null) || (text == null) || (delimiter == null)) {
113             return false;
114         }
115 
116         StringMaker sm = null;
117 
118         if (!s.endsWith(delimiter)) {
119             sm = new StringMaker();
120 
121             sm.append(s);
122             sm.append(delimiter);
123 
124             s = sm.toString();
125         }
126 
127         sm = new StringMaker();
128 
129         sm.append(delimiter);
130         sm.append(text);
131         sm.append(delimiter);
132 
133         String dtd = sm.toString();
134 
135         int pos = s.indexOf(dtd);
136 
137         if (pos == -1) {
138             sm = new StringMaker();
139 
140             sm.append(text);
141             sm.append(delimiter);
142 
143             String td = sm.toString();
144 
145             if (s.startsWith(td)) {
146                 return true;
147             }
148 
149             return false;
150         }
151 
152         return true;
153     }
154 
155     public static int count(String s, String text) {
156         if ((s == null) || (text == null)) {
157             return 0;
158         }
159 
160         int count = 0;
161 
162         int pos = s.indexOf(text);
163 
164         while (pos != -1) {
165             pos = s.indexOf(text, pos + text.length());
166 
167             count++;
168         }
169 
170         return count;
171     }
172 
173     public static boolean endsWith(String s, char end) {
174         return endsWith(s, (new Character(end)).toString());
175     }
176 
177     public static boolean endsWith(String s, String end) {
178         if ((s == null) || (end == null)) {
179             return false;
180         }
181 
182         if (end.length() > s.length()) {
183             return false;
184         }
185 
186         String temp = s.substring(s.length() - end.length(), s.length());
187 
188         if (temp.equalsIgnoreCase(end)) {
189             return true;
190         }
191         else {
192             return false;
193         }
194     }
195 
196     public static String extractChars(String s) {
197         if (s == null) {
198             return StringPool.BLANK;
199         }
200 
201         StringMaker sm = new StringMaker();
202 
203         char[] c = s.toCharArray();
204 
205         for (int i = 0; i < c.length; i++) {
206             if (Validator.isChar(c[i])) {
207                 sm.append(c[i]);
208             }
209         }
210 
211         return sm.toString();
212     }
213 
214     public static String extractDigits(String s) {
215         if (s == null) {
216             return StringPool.BLANK;
217         }
218 
219         StringMaker sm = new StringMaker();
220 
221         char[] c = s.toCharArray();
222 
223         for (int i = 0; i < c.length; i++) {
224             if (Validator.isDigit(c[i])) {
225                 sm.append(c[i]);
226             }
227         }
228 
229         return sm.toString();
230     }
231 
232     public static String extractFirst(String s, String delimiter) {
233         if (s == null) {
234             return null;
235         }
236         else {
237             String[] array = split(s, delimiter);
238 
239             if (array.length > 0) {
240                 return array[0];
241             }
242             else {
243                 return null;
244             }
245         }
246     }
247 
248     public static String extractLast(String s, String delimiter) {
249         if (s == null) {
250             return null;
251         }
252         else {
253             String[] array = split(s, delimiter);
254 
255             if (array.length > 0) {
256                 return array[array.length - 1];
257             }
258             else {
259                 return null;
260             }
261         }
262     }
263 
264     public static String highlight(String s, String keywords) {
265         return highlight(s, keywords, "<span class=\"highlight\">", "</span>");
266     }
267 
268     public static String highlight(
269         String s, String keywords, String highlight1, String highlight2) {
270 
271         if (s == null) {
272             return null;
273         }
274 
275         // The problem with using a regexp is that it searches the text in a
276         // case insenstive manner but doens't replace the text in a case
277         // insenstive manner. So the search results actually get messed up. The
278         // best way is to actually parse the results.
279 
280         //return s.replaceAll(
281         //  "(?i)" + keywords, highlight1 + keywords + highlight2);
282 
283         StringMaker sm = new StringMaker(StringPool.SPACE);
284 
285         StringTokenizer st = new StringTokenizer(s);
286 
287         while (st.hasMoreTokens()) {
288             String token = st.nextToken();
289 
290             if (token.equalsIgnoreCase(keywords)) {
291                 sm.append(highlight1);
292                 sm.append(token);
293                 sm.append(highlight2);
294             }
295             else {
296                 sm.append(token);
297             }
298 
299             if (st.hasMoreTokens()) {
300                 sm.append(StringPool.SPACE);
301             }
302         }
303 
304         return sm.toString();
305     }
306 
307     public static String lowerCase(String s) {
308         if (s == null) {
309             return null;
310         }
311         else {
312             return s.toLowerCase();
313         }
314     }
315 
316     public static String merge(boolean[] array) {
317         return merge(array, StringPool.COMMA);
318     }
319 
320     public static String merge(boolean[] array, String delimiter) {
321         if (array == null) {
322             return null;
323         }
324 
325         StringMaker sm = new StringMaker();
326 
327         for (int i = 0; i < array.length; i++) {
328             sm.append(String.valueOf(array[i]).trim());
329 
330             if ((i + 1) != array.length) {
331                 sm.append(delimiter);
332             }
333         }
334 
335         return sm.toString();
336     }
337 
338     public static String merge(int[] array) {
339         return merge(array, StringPool.COMMA);
340     }
341 
342     public static String merge(int[] array, String delimiter) {
343         if (array == null) {
344             return null;
345         }
346 
347         StringMaker sm = new StringMaker();
348 
349         for (int i = 0; i < array.length; i++) {
350             sm.append(String.valueOf(array[i]).trim());
351 
352             if ((i + 1) != array.length) {
353                 sm.append(delimiter);
354             }
355         }
356 
357         return sm.toString();
358     }
359 
360     public static String merge(long[] array) {
361         return merge(array, StringPool.COMMA);
362     }
363 
364     public static String merge(long[] array, String delimiter) {
365         if (array == null) {
366             return null;
367         }
368 
369         StringMaker sm = new StringMaker();
370 
371         for (int i = 0; i < array.length; i++) {
372             sm.append(String.valueOf(array[i]).trim());
373 
374             if ((i + 1) != array.length) {
375                 sm.append(delimiter);
376             }
377         }
378 
379         return sm.toString();
380     }
381 
382     public static String merge(short[] array) {
383         return merge(array, StringPool.COMMA);
384     }
385 
386     public static String merge(short[] array, String delimiter) {
387         if (array == null) {
388             return null;
389         }
390 
391         StringMaker sm = new StringMaker();
392 
393         for (int i = 0; i < array.length; i++) {
394             sm.append(String.valueOf(array[i]).trim());
395 
396             if ((i + 1) != array.length) {
397                 sm.append(delimiter);
398             }
399         }
400 
401         return sm.toString();
402     }
403 
404     public static String merge(List list) {
405         return merge(list, StringPool.COMMA);
406     }
407 
408     public static String merge(List list, String delimiter) {
409         return merge((Object[])list.toArray(
410             new Object[list.size()]), delimiter);
411     }
412 
413     public static String merge(Object[] array) {
414         return merge(array, StringPool.COMMA);
415     }
416 
417     public static String merge(Object[] array, String delimiter) {
418         if (array == null) {
419             return null;
420         }
421 
422         StringMaker sm = new StringMaker();
423 
424         for (int i = 0; i < array.length; i++) {
425             sm.append(String.valueOf(array[i]).trim());
426 
427             if ((i + 1) != array.length) {
428                 sm.append(delimiter);
429             }
430         }
431 
432         return sm.toString();
433     }
434 
435     public static String randomize(String s) {
436         return Randomizer.getInstance().randomize(s);
437     }
438 
439     public static String read(ClassLoader classLoader, String name)
440         throws IOException {
441 
442         return read(classLoader, name, false);
443     }
444 
445     public static String read(ClassLoader classLoader, String name, boolean all)
446         throws IOException {
447 
448         if (all) {
449             StringMaker sm = new StringMaker();
450 
451             Enumeration enu = classLoader.getResources(name);
452 
453             while (enu.hasMoreElements()) {
454                 URL url = (URL)enu.nextElement();
455 
456                 InputStream is = url.openStream();
457 
458                 String s = read(is);
459 
460                 if (s != null) {
461                     sm.append(s);
462                     sm.append(StringPool.NEW_LINE);
463                 }
464 
465                 is.close();
466             }
467 
468             return sm.toString().trim();
469         }
470         else {
471             InputStream is = classLoader.getResourceAsStream(name);
472 
473             String s = read(is);
474 
475             is.close();
476 
477             return s;
478         }
479     }
480 
481     public static String read(InputStream is) throws IOException {
482         StringMaker sm = new StringMaker();
483 
484         BufferedReader br = new BufferedReader(new InputStreamReader(is));
485 
486         String line = null;
487 
488         while ((line = br.readLine()) != null) {
489             sm.append(line).append('\n');
490         }
491 
492         br.close();
493 
494         return sm.toString().trim();
495     }
496 
497     public static String remove(String s, String remove) {
498         return remove(s, remove, StringPool.COMMA);
499     }
500 
501     public static String remove(String s, String remove, String delimiter) {
502         if ((s == null) || (remove == null) || (delimiter == null)) {
503             return null;
504         }
505 
506         if (Validator.isNotNull(s) && !s.endsWith(delimiter)) {
507             s += delimiter;
508         }
509 
510         StringMaker sm = new StringMaker();
511 
512         sm.append(delimiter);
513         sm.append(remove);
514         sm.append(delimiter);
515 
516         String drd = sm.toString();
517 
518         sm = new StringMaker();
519 
520         sm.append(remove);
521         sm.append(delimiter);
522 
523         String rd = sm.toString();
524 
525         while (contains(s, remove, delimiter)) {
526             int pos = s.indexOf(drd);
527 
528             if (pos == -1) {
529                 if (s.startsWith(rd)) {
530                     int x = remove.length() + delimiter.length();
531                     int y = s.length();
532 
533                     s = s.substring(x, y);
534                 }
535             }
536             else {
537                 int x = pos + remove.length() + delimiter.length();
538                 int y = s.length();
539 
540                 sm = new StringMaker();
541 
542                 sm.append(s.substring(0, pos));
543                 sm.append(s.substring(x, y));
544 
545                 s =  sm.toString();
546             }
547         }
548 
549         return s;
550     }
551 
552     public static String replace(String s, char oldSub, char newSub) {
553         return replace(s, oldSub, new Character(newSub).toString());
554     }
555 
556     public static String replace(String s, char oldSub, String newSub) {
557         if ((s == null) || (newSub == null)) {
558             return null;
559         }
560 
561         StringMaker sm = new StringMaker();
562 
563         char[] c = s.toCharArray();
564 
565         for (int i = 0; i < c.length; i++) {
566             if (c[i] == oldSub) {
567                 sm.append(newSub);
568             }
569             else {
570                 sm.append(c[i]);
571             }
572         }
573 
574         return sm.toString();
575     }
576 
577     public static String replace(String s, String oldSub, String newSub) {
578         if ((s == null) || (oldSub == null) || (newSub == null)) {
579             return null;
580         }
581 
582         int y = s.indexOf(oldSub);
583 
584         if (y >= 0) {
585             StringMaker sm = new StringMaker();
586 
587             int length = oldSub.length();
588             int x = 0;
589 
590             while (x <= y) {
591                 sm.append(s.substring(x, y));
592                 sm.append(newSub);
593                 x = y + length;
594                 y = s.indexOf(oldSub, x);
595             }
596 
597             sm.append(s.substring(x));
598 
599             return sm.toString();
600         }
601         else {
602             return s;
603         }
604     }
605 
606     public static String replace(String s, String[] oldSubs, String[] newSubs) {
607         if ((s == null) || (oldSubs == null) || (newSubs == null)) {
608             return null;
609         }
610 
611         if (oldSubs.length != newSubs.length) {
612             return s;
613         }
614 
615         for (int i = 0; i < oldSubs.length; i++) {
616             s = replace(s, oldSubs[i], newSubs[i]);
617         }
618 
619         return s;
620     }
621 
622     /**
623      * Returns a string with replaced values. This method will replace all text
624      * in the given string, between the beginning and ending delimiter, with new
625      * values found in the given map. For example, if the string contained the
626      * text <code>[$HELLO$]</code>, and the beginning delimiter was
627      * <code>[$]</code>, and the ending delimiter was <code>$]</code>, and the
628      * values map had a key of <code>HELLO</code> that mapped to
629      * <code>WORLD</code>, then the replaced string will contain the text
630      * <code>[$WORLD$]</code>.
631      *
632      * @param       s the original string
633      * @param       begin the beginning delimiter
634      * @param       end the ending delimiter
635      * @param       values a map of old and new values
636      * @return      a string with replaced values
637      */
638     public static String replaceValues(
639         String s, String begin, String end, Map values) {
640 
641         if ((s == null) || (begin == null) || (end == null) ||
642             (values == null) || (values.size() == 0)) {
643 
644             return s;
645         }
646 
647         StringMaker sm = new StringMaker(s.length());
648 
649         int pos = 0;
650 
651         while (true) {
652             int x = s.indexOf(begin, pos);
653             int y = s.indexOf(end, x + begin.length());
654 
655             if ((x == -1) || (y == -1)) {
656                 sm.append(s.substring(pos, s.length()));
657 
658                 break;
659             }
660             else {
661                 sm.append(s.substring(pos, x + begin.length()));
662 
663                 String oldValue = s.substring(x + begin.length(), y);
664 
665                 String newValue = (String)values.get(oldValue);
666 
667                 if (newValue == null) {
668                     newValue = oldValue;
669                 }
670 
671                 sm.append(newValue);
672 
673                 pos = y;
674             }
675         }
676 
677         return sm.toString();
678     }
679 
680     public static String reverse(String s) {
681         if (s == null) {
682             return null;
683         }
684 
685         char[] c = s.toCharArray();
686         char[] reverse = new char[c.length];
687 
688         for (int i = 0; i < c.length; i++) {
689             reverse[i] = c[c.length - i - 1];
690         }
691 
692         return new String(reverse);
693     }
694 
695     public static String safePath(String path) {
696         return StringUtil.replace(
697             path, StringPool.DOUBLE_SLASH, StringPool.SLASH);
698     }
699 
700     public static String shorten(String s) {
701         return shorten(s, 20);
702     }
703 
704     public static String shorten(String s, int length) {
705         return shorten(s, length, "...");
706     }
707 
708     public static String shorten(String s, String suffix) {
709         return shorten(s, 20, suffix);
710     }
711 
712     public static String shorten(String s, int length, String suffix) {
713         if (s == null || suffix == null)  {
714             return null;
715         }
716 
717         if (s.length() > length) {
718             for (int j = length; j >= 0; j--) {
719                 if (Character.isWhitespace(s.charAt(j))) {
720                     length = j;
721 
722                     break;
723                 }
724             }
725 
726             StringMaker sm = new StringMaker();
727 
728             sm.append(s.substring(0, length));
729             sm.append(suffix);
730 
731             s =  sm.toString();
732         }
733 
734         return s;
735     }
736 
737     public static String[] split(String s) {
738         return split(s, StringPool.COMMA);
739     }
740 
741     public static String[] split(String s, String delimiter) {
742         if (s == null || delimiter == null) {
743             return new String[0];
744         }
745 
746         s = s.trim();
747 
748         if (!s.endsWith(delimiter)) {
749             StringMaker sm = new StringMaker();
750 
751             sm.append(s);
752             sm.append(delimiter);
753 
754             s = sm.toString();
755         }
756 
757         if (s.equals(delimiter)) {
758             return new String[0];
759         }
760 
761         List nodeValues = new ArrayList();
762 
763         if (delimiter.equals("\n") || delimiter.equals("\r")) {
764             try {
765                 BufferedReader br = new BufferedReader(new StringReader(s));
766 
767                 String line = null;
768 
769                 while ((line = br.readLine()) != null) {
770                     nodeValues.add(line);
771                 }
772 
773                 br.close();
774             }
775             catch (IOException ioe) {
776                 _log.error(ioe.getMessage());
777             }
778         }
779         else {
780             int offset = 0;
781             int pos = s.indexOf(delimiter, offset);
782 
783             while (pos != -1) {
784                 nodeValues.add(new String(s.substring(offset, pos)));
785 
786                 offset = pos + delimiter.length();
787                 pos = s.indexOf(delimiter, offset);
788             }
789         }
790 
791         return (String[])nodeValues.toArray(new String[nodeValues.size()]);
792     }
793 
794     public static boolean[] split(String s, boolean x) {
795         return split(s, StringPool.COMMA, x);
796     }
797 
798     public static boolean[] split(String s, String delimiter, boolean x) {
799         String[] array = split(s, delimiter);
800         boolean[] newArray = new boolean[array.length];
801 
802         for (int i = 0; i < array.length; i++) {
803             boolean value = x;
804 
805             try {
806                 value = Boolean.valueOf(array[i]).booleanValue();
807             }
808             catch (Exception e) {
809             }
810 
811             newArray[i] = value;
812         }
813 
814         return newArray;
815     }
816 
817     public static double[] split(String s, double x) {
818         return split(s, StringPool.COMMA, x);
819     }
820 
821     public static double[] split(String s, String delimiter, double x) {
822         String[] array = split(s, delimiter);
823         double[] newArray = new double[array.length];
824 
825         for (int i = 0; i < array.length; i++) {
826             double value = x;
827 
828             try {
829                 value = Double.parseDouble(array[i]);
830             }
831             catch (Exception e) {
832             }
833 
834             newArray[i] = value;
835         }
836 
837         return newArray;
838     }
839 
840     public static float[] split(String s, float x) {
841         return split(s, StringPool.COMMA, x);
842     }
843 
844     public static float[] split(String s, String delimiter, float x) {
845         String[] array = split(s, delimiter);
846         float[] newArray = new float[array.length];
847 
848         for (int i = 0; i < array.length; i++) {
849             float value = x;
850 
851             try {
852                 value = Float.parseFloat(array[i]);
853             }
854             catch (Exception e) {
855             }
856 
857             newArray[i] = value;
858         }
859 
860         return newArray;
861     }
862 
863     public static int[] split(String s, int x) {
864         return split(s, StringPool.COMMA, x);
865     }
866 
867     public static int[] split(String s, String delimiter, int x) {
868         String[] array = split(s, delimiter);
869         int[] newArray = new int[array.length];
870 
871         for (int i = 0; i < array.length; i++) {
872             int value = x;
873 
874             try {
875                 value = Integer.parseInt(array[i]);
876             }
877             catch (Exception e) {
878             }
879 
880             newArray[i] = value;
881         }
882 
883         return newArray;
884     }
885 
886     public static long[] split(String s, long x) {
887         return split(s, StringPool.COMMA, x);
888     }
889 
890     public static long[] split(String s, String delimiter, long x) {
891         String[] array = split(s, delimiter);
892         long[] newArray = new long[array.length];
893 
894         for (int i = 0; i < array.length; i++) {
895             long value = x;
896 
897             try {
898                 value = Long.parseLong(array[i]);
899             }
900             catch (Exception e) {
901             }
902 
903             newArray[i] = value;
904         }
905 
906         return newArray;
907     }
908 
909     public static short[] split(String s, short x) {
910         return split(s, StringPool.COMMA, x);
911     }
912 
913     public static short[] split(String s, String delimiter, short x) {
914         String[] array = split(s, delimiter);
915         short[] newArray = new short[array.length];
916 
917         for (int i = 0; i < array.length; i++) {
918             short value = x;
919 
920             try {
921                 value = Short.parseShort(array[i]);
922             }
923             catch (Exception e) {
924             }
925 
926             newArray[i] = value;
927         }
928 
929         return newArray;
930     }
931 
932     public static boolean startsWith(String s, char begin) {
933         return startsWith(s, (new Character(begin)).toString());
934     }
935 
936     public static boolean startsWith(String s, String start) {
937         if ((s == null) || (start == null)) {
938             return false;
939         }
940 
941         if (start.length() > s.length()) {
942             return false;
943         }
944 
945         String temp = s.substring(0, start.length());
946 
947         if (temp.equalsIgnoreCase(start)) {
948             return true;
949         }
950         else {
951             return false;
952         }
953     }
954 
955     public static String stripBetween(String s, String begin, String end) {
956         if ((s == null) || (begin == null) || (end == null)) {
957             return s;
958         }
959 
960         StringMaker sm = new StringMaker(s.length());
961 
962         int pos = 0;
963 
964         while (true) {
965             int x = s.indexOf(begin, pos);
966             int y = s.indexOf(end, x + begin.length());
967 
968             if ((x == -1) || (y == -1)) {
969                 sm.append(s.substring(pos, s.length()));
970 
971                 break;
972             }
973             else {
974                 sm.append(s.substring(pos, x));
975 
976                 pos = y + end.length();
977             }
978         }
979 
980         return sm.toString();
981     }
982 
983     public static String trim(String s) {
984         return trim(s, null);
985     }
986 
987     public static String trim(String s, char c) {
988         return trim(s, new char[] {c});
989     }
990 
991     public static String trim(String s, char[] exceptions) {
992         if (s == null) {
993             return null;
994         }
995 
996         char[] charArray = s.toCharArray();
997 
998         int len = charArray.length;
999 
1000        int x = 0;
1001        int y = charArray.length;
1002
1003        for (int i = 0; i < len; i++) {
1004            char c = charArray[i];
1005
1006            if (_isTrimable(c, exceptions)) {
1007                x = i + 1;
1008            }
1009            else {
1010                break;
1011            }
1012        }
1013
1014        for (int i = len - 1; i >= 0; i--) {
1015            char c = charArray[i];
1016
1017            if (_isTrimable(c, exceptions)) {
1018                y = i;
1019            }
1020            else {
1021                break;
1022            }
1023        }
1024
1025        if ((x != 0) || (y != len)) {
1026            return s.substring(x, y);
1027        }
1028        else {
1029            return s;
1030        }
1031    }
1032
1033    public static String trimLeading(String s) {
1034        return trimLeading(s, null);
1035    }
1036
1037    public static String trimLeading(String s, char c) {
1038        return trimLeading(s, new char[] {c});
1039    }
1040
1041    public static String trimLeading(String s, char[] exceptions) {
1042        if (s == null) {
1043            return null;
1044        }
1045
1046        char[] charArray = s.toCharArray();
1047
1048        int len = charArray.length;
1049
1050        int x = 0;
1051        int y = charArray.length;
1052
1053        for (int i = 0; i < len; i++) {
1054            char c = charArray[i];
1055
1056            if (_isTrimable(c, exceptions)) {
1057                x = i + 1;
1058            }
1059            else {
1060                break;
1061            }
1062        }
1063
1064        if ((x != 0) || (y != len)) {
1065            return s.substring(x, y);
1066        }
1067        else {
1068            return s;
1069        }
1070    }
1071
1072    public static String trimTrailing(String s) {
1073        return trimTrailing(s, null);
1074    }
1075
1076    public static String trimTrailing(String s, char c) {
1077        return trimTrailing(s, new char[] {c});
1078    }
1079
1080    public static String trimTrailing(String s, char[] exceptions) {
1081        if (s == null) {
1082            return null;
1083        }
1084
1085        char[] charArray = s.toCharArray();
1086
1087        int len = charArray.length;
1088
1089        int x = 0;
1090        int y = charArray.length;
1091
1092        for (int i = len - 1; i >= 0; i--) {
1093            char c = charArray[i];
1094
1095            if (_isTrimable(c, exceptions)) {
1096                y = i;
1097            }
1098            else {
1099                break;
1100            }
1101        }
1102
1103        if ((x != 0) || (y != len)) {
1104            return s.substring(x, y);
1105        }
1106        else {
1107            return s;
1108        }
1109    }
1110
1111    public static String upperCase(String s) {
1112        if (s == null) {
1113            return null;
1114        }
1115        else {
1116            return s.toUpperCase();
1117        }
1118    }
1119
1120    public static String upperCaseFirstLetter(String s) {
1121        char[] chars = s.toCharArray();
1122
1123        if (chars[0] >= 97 && chars[0] <= 122) {
1124            chars[0] = (char) ((int) chars[0] - 32);
1125        }
1126
1127        return new String(chars);
1128    }
1129
1130    public static String wrap(String text) {
1131        return wrap(text, 80, "\n");
1132    }
1133
1134    public static String wrap(String text, int width, String lineSeparator) {
1135        if (text == null) {
1136            return null;
1137        }
1138
1139        StringMaker sm = new StringMaker();
1140
1141        try {
1142            BufferedReader br = new BufferedReader(new StringReader(text));
1143
1144            String s = StringPool.BLANK;
1145
1146            while ((s = br.readLine()) != null) {
1147                if (s.length() == 0) {
1148                    sm.append(lineSeparator);
1149                }
1150                else {
1151                    String[] tokens = s.split(StringPool.SPACE);
1152                    boolean firstWord = true;
1153                    int curLineLength = 0;
1154
1155                    for (int i = 0; i < tokens.length; i++) {
1156                        if (!firstWord) {
1157                            sm.append(StringPool.SPACE);
1158                            curLineLength++;
1159                        }
1160
1161                        if (firstWord) {
1162                            sm.append(lineSeparator);
1163                        }
1164
1165                        sm.append(tokens[i]);
1166
1167                        curLineLength += tokens[i].length();
1168
1169                        if (curLineLength >= width) {
1170                            firstWord = true;
1171                            curLineLength = 0;
1172                        }
1173                        else {
1174                            firstWord = false;
1175                        }
1176                    }
1177                }
1178            }
1179        }
1180        catch (IOException ioe) {
1181            _log.error(ioe.getMessage());
1182        }
1183
1184        return sm.toString();
1185    }
1186
1187    private static boolean _isTrimable(char c, char[] exceptions) {
1188        if ((exceptions != null) && (exceptions.length > 0)) {
1189            for (int i = 0; i < exceptions.length; i++) {
1190                if (c == exceptions[i]) {
1191                    return false;
1192                }
1193            }
1194        }
1195
1196        return Character.isWhitespace(c);
1197    }
1198
1199    private static Log _log = LogFactoryUtil.getLog(StringUtil.class);
1200
1201}