KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > util > StringUtil


1 // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
2

3 package jodd.util;
4
5 import jodd.typeconverter.StringArrayConverter;
6
7 import java.io.UnsupportedEncodingException JavaDoc;
8
9
10 /**
11  * Various String utilities.
12  */

13 public class StringUtil {
14
15     public static final String JavaDoc WHITESPACE = " \n\r\f\t";
16     public static final String JavaDoc EMPTY_STRING = "";
17
18     // ---------------------------------------------------------------- replace
19

20     /**
21      * Replaces the occurrences of a certain pattern in a string with a
22      * replacement string. This is the fastest replace function known to author.
23      *
24      * @param s string to be inspected
25      * @param sub string pattern to be replaced
26      * @param with string that should go where the pattern was
27      */

28     public static String JavaDoc replace(String JavaDoc s, String JavaDoc sub, String JavaDoc with) {
29         int c = 0;
30         int i = s.indexOf(sub, c);
31         if (i == -1) {
32             return s;
33         }
34         int sLen = s.length();
35         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(sLen + with.length());
36         do {
37              buf.append(s.substring(c,i));
38              buf.append(with);
39              c = i + sub.length();
40          } while ((i = s.indexOf(sub, c)) != -1);
41          if (c < sLen) {
42              buf.append(s.substring(c, sLen));
43          }
44          return buf.toString();
45     }
46
47     /**
48      * Replaces all occurrences of a character in a string.
49      *
50      * @param s input string
51      * @param sub character to replace
52      * @param with character to replace with
53      */

54     public static String JavaDoc replace(String JavaDoc s, char sub, char with) {
55         char[] str = s.toCharArray();
56         for (int i = 0; i < str.length; i++) {
57             if (str[i] == sub) {
58                 str[i] = with;
59             }
60         }
61         return new String JavaDoc(str);
62     }
63
64     /**
65      * Replaces the very first occurrence of a substring with supplied string.
66      *
67      * @param s source string
68      * @param sub substring to replace
69      * @param with substring to replace with
70      */

71     public static String JavaDoc replaceFirst(String JavaDoc s, String JavaDoc sub, String JavaDoc with) {
72         int i = s.indexOf(sub);
73         if (i == -1) {
74             return s;
75         }
76         return s.substring(0, i) + with + s.substring(i + sub.length());
77     }
78
79     /**
80      * Replaces the very first occurrence of a character in a string.
81      *
82      * @param s string
83      * @param sub char to replace
84      * @param with char to replace with
85      */

86     public static String JavaDoc replaceFirst(String JavaDoc s, char sub, char with) {
87         char[] str = s.toCharArray();
88         for (int i = 0; i < str.length; i++) {
89             if (str[i] == sub) {
90                 str[i] = with;
91                 break;
92             }
93         }
94         return new String JavaDoc(str);
95     }
96
97     /**
98      * Replaces the very last occurrence of a substring with supplied string.
99      *
100      * @param s source string
101      * @param sub substring to replace
102      * @param with substring to replace with
103      */

104     public static String JavaDoc replaceLast(String JavaDoc s, String JavaDoc sub, String JavaDoc with) {
105         int i = s.lastIndexOf(sub);
106         if (i == -1) {
107             return s;
108         }
109         return s.substring(0, i) + with + s.substring(i + sub.length());
110     }
111
112     /**
113      * Replaces the very last occurrence of a character in a string.
114      *
115      * @param s string
116      * @param sub char to replace
117      * @param with char to replace with
118      */

119     public static String JavaDoc replaceLast(String JavaDoc s, char sub, char with) {
120         char[] str = s.toCharArray();
121         for (int i = str.length - 1; i >= 0; i--) {
122             if (str[i] == sub) {
123                 str[i] = with;
124                 break;
125             }
126         }
127         return new String JavaDoc(str);
128     }
129
130     // ---------------------------------------------------------------- remove
131

132     /**
133      * Removes all substring occurrences from the string.
134      *
135      * @param s source string
136      * @param sub substring to remove
137      */

138     public static String JavaDoc remove(String JavaDoc s, String JavaDoc sub) {
139         int c = 0;
140         int sublen = sub.length();
141         if (sublen == 0) {
142             return s;
143         }
144         int i = s.indexOf(sub, c);
145         if (i == -1) {
146             return s;
147         }
148         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(s.length());
149         do {
150              buf.append(s.substring(c, i));
151              c = i + sublen;
152          } while ((i = s.indexOf(sub, c)) != -1);
153          if (c < s.length()) {
154              buf.append(s.substring(c, s.length()));
155          }
156          return buf.toString();
157     }
158
159     /**
160      * Removes all characters contained in provided string.
161      *
162      * @param src source string
163      * @param chars string containing characters to remove
164      */

165     public static String JavaDoc removeChars(String JavaDoc src, String JavaDoc chars) {
166         int i = src.length();
167         StringBuffer JavaDoc stringbuffer = new StringBuffer JavaDoc(i);
168         for (int j = 0; j < i; j++) {
169             char c = src.charAt(j);
170             if (chars.indexOf(c) == -1) {
171                 stringbuffer.append(c);
172             }
173         }
174         return stringbuffer.toString();
175     }
176
177
178     /**
179      * Removes set of characters from string.
180      *
181      * @param src string
182      * @param chars character to remove
183      */

184     public static String JavaDoc removeChars(String JavaDoc src, char[] chars) {
185         int i = src.length();
186         StringBuffer JavaDoc stringbuffer = new StringBuffer JavaDoc(i);
187         mainloop:
188         for (int j = 0; j < i; j++) {
189             char c = src.charAt(j);
190             for (int k = 0; k < chars.length; k++) {
191                 if (c == chars[k]) {
192                     continue mainloop;
193                 }
194             }
195             stringbuffer.append(c);
196         }
197         return stringbuffer.toString();
198     }
199
200     /**
201      * Removes a single character from string.
202      *
203      * @param src source string
204      * @param chars character to remove
205      */

206     public static String JavaDoc remove(String JavaDoc src, char chars) {
207         int i = src.length();
208         StringBuffer JavaDoc stringbuffer = new StringBuffer JavaDoc(i);
209         for (int j = 0; j < i; j++) {
210             char c = src.charAt(j);
211             if (c == chars) {
212                 continue;
213             }
214             stringbuffer.append(c);
215         }
216         return stringbuffer.toString();
217     }
218
219     // ---------------------------------------------------------------- miscellaneous
220

221     /**
222      * Compares 2 strings. If one of the strings is <code>null</code>, <code>false</code> is returned. if
223      * both string are <code>null</code>, <code>true</code> is returned.
224      *
225      * @param s1 first string to compare
226      * @param s2 second string
227      *
228      * @return <code>true</code> if strings are equal, otherwise <code>false</code>
229      */

230     public static boolean equals(String JavaDoc s1, String JavaDoc s2) {
231         return ObjectUtil.equals(s1, s2);
232     }
233
234     /**
235      * Determines if a string is empty (<code>null</code> or empty).
236      */

237     public static boolean isEmpty(String JavaDoc string) {
238         return ((string == null) || (string.length() == 0));
239     }
240
241     /**
242      * Determines if a string is blank (<code>null</code> or trimmed empty).,
243      */

244     public static boolean isBlank(String JavaDoc string) {
245         return ((string == null) || (string.trim().length() == 0));
246     }
247
248     /**
249      * Determines if a string is not empty.
250      */

251     public static boolean isNotEmpty(String JavaDoc string) {
252         return string != null && string.length() > 0;
253     }
254
255
256     /**
257      * Converts safely an object to a string. If object is <code>null</code> it will be
258      * not converted.
259      */

260     public static String JavaDoc toString(Object JavaDoc obj) {
261         if (obj == null) {
262             return null;
263         }
264         return obj.toString();
265     }
266
267     /**
268      * Converts safely an object to a string. If object is <code>null</code> a empty
269      * string is returned.
270      */

271     public static String JavaDoc toNotNullString(Object JavaDoc obj) {
272         if (obj == null) {
273             return EMPTY_STRING;
274         }
275         return obj.toString();
276     }
277
278     /**
279      * Converts an object to a String Array.
280      */

281     public static String JavaDoc[] toStringArray(Object JavaDoc obj) {
282         return StringArrayConverter.valueOf(obj);
283     }
284
285
286     // ---------------------------------------------------------------- captialize
287

288     /**
289      * Capitalizes a string, changing the first letter to
290      * upper case. No other letters are changed.
291      *
292      * @param str string to capitalize, may be null
293      * @see #uncapitalize(String)
294      */

295     public static String JavaDoc capitalize(String JavaDoc str) {
296         return changeFirstCharacterCase(true, str);
297     }
298
299     /**
300      * Uncapitalizes a <code>String</code>, changing the first letter to
301      * lower case. No other letters are changed.
302      *
303      * @param str the String to uncapitalize, may be null
304      * @return the uncapitalized String, <code>null</code> if null
305      * @see #capitalize(String)
306      */

307     public static String JavaDoc uncapitalize(String JavaDoc str) {
308         return changeFirstCharacterCase(false, str);
309     }
310
311     /**
312      * Internal method for changing the first character case. It is significantly
313      * faster using StringBuffers then just simply Strings.
314      * @param capitalize
315      * @param str
316      */

317     private static String JavaDoc changeFirstCharacterCase(boolean capitalize, String JavaDoc str) {
318         int strLen = str.length();
319         if (strLen == 0) {
320             return str;
321         }
322         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(strLen);
323         if (capitalize) {
324             buf.append(Character.toUpperCase(str.charAt(0)));
325         } else {
326             buf.append(Character.toLowerCase(str.charAt(0)));
327         }
328         buf.append(str.substring(1));
329         return buf.toString();
330     }
331
332
333     // ---------------------------------------------------------------- truncate
334

335
336     /**
337      * Sets the maximum length of the string. Longer strings will be simply truncaten.
338      */

339     public static String JavaDoc truncate(String JavaDoc string, int length) {
340         if (string.length() > length) {
341             string = string.substring(0, length);
342         }
343         return string;
344     }
345
346     // ---------------------------------------------------------------- split
347

348     /**
349      * Splits a string in several parts (tokens) that are separated by delimiter.
350      * Delimiter is <b>always</b> surrounded by two strings! If there is no
351      * content between two delimiters, empty string will be returned for that
352      * token. Therefore, the length of the returned array will always be:
353      * #delimiters + 1.
354      * <p>
355      * Method is much, much faster then regexp <code>String.split()</code>,
356      * and a bit faster then <code>StringTokenizer</code>.
357      *
358      * @param src string to split
359      * @param delimeter split delimiter
360      *
361      * @return array of split strings
362      */

363     public static String JavaDoc[] split(String JavaDoc src, String JavaDoc delimeter) {
364         int maxparts = (src.length() / delimeter.length()) + 2; // one more for the last
365
int[] positions = new int[maxparts];
366         int dellen = delimeter.length();
367
368         int i, j = 0;
369         int count = 0;
370         positions[0] = - dellen;
371         while ((i = src.indexOf(delimeter, j)) != -1) {
372             count++;
373             positions[count] = i;
374             j = i + dellen;
375         }
376         count++;
377         positions[count] = src.length();
378
379         String JavaDoc[] result = new String JavaDoc[count];
380
381         for (i = 0; i < count; i++) {
382             result[i] = src.substring(positions[i] + dellen, positions[i + 1]);
383         }
384         return result;
385     }
386
387     /**
388      * Splits a string in several parts (tokens) that are separated by delimiter
389      * characters. Delimiter may contains any number of character, and it is
390      * always surrounded by two strings.
391      *
392      * @param src source to examine
393      * @param d string with delimiter characters
394      *
395      * @return array of tokens
396      */

397     public static String JavaDoc[] splitc(String JavaDoc src, String JavaDoc d) {
398         if ((d.length() == 0) || (src.length() == 0) ) {
399             return new String JavaDoc[] {src};
400         }
401         char[] delimiters = d.toCharArray();
402         char[] srcc = src.toCharArray();
403
404         int maxparts = srcc.length + 1;
405         int[] start = new int[maxparts];
406         int[] end = new int[maxparts];
407
408         int count = 0;
409
410         start[0] = 0;
411         int s = 0, e;
412         if (CharUtil.equalsOne(srcc[0], delimiters) == true) { // string starts with delimiter
413
end[0] = 0;
414             count++;
415             s = CharUtil.findFirstDiff(srcc, 1, delimiters);
416             if (s == -1) { // nothing after delimiters
417
return new String JavaDoc[] {EMPTY_STRING, EMPTY_STRING};
418             }
419             start[1] = s; // new start
420
}
421         while (true) {
422             // find new end
423
e = CharUtil.findFirstEqual(srcc, s, delimiters);
424             if (e == -1) {
425                 end[count] = srcc.length;
426                 break;
427             }
428             end[count] = e;
429
430             // find new start
431
count++;
432             s = CharUtil.findFirstDiff(srcc, e, delimiters);
433             if (s == -1) {
434                 start[count] = end[count] = srcc.length;
435                 break;
436             }
437             start[count] = s;
438         }
439         count++;
440         String JavaDoc[] result = new String JavaDoc[count];
441         for (int i = 0; i < count; i++) {
442             result[i] = src.substring(start[i], end[i]);
443         }
444         return result;
445     }
446
447     /**
448      * Splits a string in several parts (tokens) that are separated by single delimiter
449      * characters. Delimiter may contains any number of character, and it is
450      * always surrounded by two strings.
451      *
452      * @param src source to examine
453      * @param delimiter delimiter character
454      *
455      * @return array of tokens
456      */

457     public static String JavaDoc[] splitc(String JavaDoc src, char delimiter) {
458         char[] srcc = src.toCharArray();
459
460         int maxparts = srcc.length + 1;
461         int[] start = new int[maxparts];
462         int[] end = new int[maxparts];
463
464         int count = 0;
465
466         start[0] = 0;
467         int s = 0, e;
468         if (srcc[0] == delimiter) { // string starts with delimiter
469
end[0] = 0;
470             count++;
471             s = CharUtil.findFirstDiff(srcc, 1, delimiter);
472             if (s == -1) { // nothing after delimiters
473
return new String JavaDoc[] {EMPTY_STRING, EMPTY_STRING};
474             }
475             start[1] = s; // new start
476
}
477         while (true) {
478             // find new end
479
e = CharUtil.findFirstEqual(srcc, s, delimiter);
480             if (e == -1) {
481                 end[count] = srcc.length;
482                 break;
483             }
484             end[count] = e;
485
486             // find new start
487
count++;
488             s = CharUtil.findFirstDiff(srcc, e, delimiter);
489             if (s == -1) {
490                 start[count] = end[count] = srcc.length;
491                 break;
492             }
493             start[count] = s;
494         }
495         count++;
496         String JavaDoc[] result = new String JavaDoc[count];
497         for (int i = 0; i < count; i++) {
498             result[i] = src.substring(start[i], end[i]);
499         }
500         return result;
501     }
502
503
504     // ---------------------------------------------------------------- indexof and ignore cases
505

506     /**
507      * Finds first occurence of a substring in the given source but within limited range [start, end).
508      * It is fastest possible code, but still original <code>String.indexOf(String, int)</code>
509      * is much faster (since it uses char[] value directly) and should be used when no range is needed.
510      *
511      * @param src source string for examination
512      * @param sub substring to find
513      * @param startIndex starting index
514      * @param endIndex ending index
515      * @return index of founded substring or -1 if substring not found
516      */

517     public static int indexOf(String JavaDoc src, String JavaDoc sub, int startIndex, int endIndex) {
518         int sublen = sub.length();
519         if (sublen == 0) {
520             return startIndex;
521         }
522         int total = endIndex - sublen + 1;
523         char c = sub.charAt(0);
524     mainloop:
525         for (int i = startIndex; i < total; i++) {
526             if (src.charAt(i) != c) {
527                 continue;
528             }
529             int j = 1;
530             int k = i + 1;
531             while (j < sublen) {
532                 if (sub.charAt(j) != src.charAt(k)) {
533                     continue mainloop;
534                 }
535                 j++; k++;
536             }
537             return i;
538         }
539         return -1;
540     }
541
542     /**
543      * Finds the first occurence of a character in the given source but within limited range (start, end].
544      */

545     public static int indexOf(String JavaDoc src, char c, int startIndex, int endIndex) {
546         for (int i = startIndex; i < endIndex; i++) {
547             if (src.charAt(i) == c) {
548                 return i;
549             }
550         }
551         return -1;
552     }
553
554
555
556     /**
557      * Finds first index of a substring in the given source string with ignored case.
558      *
559      * @param src source string for examination
560      * @param subS substring to find
561      *
562      * @return index of founded substring or -1 if substring is not found
563      * @see #indexOfIgnoreCase(String, String, int)
564      */

565     public static int indexOfIgnoreCase(String JavaDoc src, String JavaDoc subS) {
566         return indexOfIgnoreCase(src, subS, 0, src.length());
567     }
568
569     /**
570      * Finds first index of a substring in the given source string with ignored
571      * case. This seems to be the fastest way doing this, with common string
572      * length and content (of course, with no use of Boyer-Mayer type of
573      * algorithms). Other implementations are slower: getting char array first,
574      * lower casing the source string, using String.regionMatch etc.
575      *
576      * @param src source string for examination
577      * @param subS substring to find
578      * @param startIndex starting index from where search begins
579      *
580      * @return index of founded substring or -1 if substring is not found
581      */

582     public static int indexOfIgnoreCase(String JavaDoc src, String JavaDoc subS, int startIndex) {
583         return indexOfIgnoreCase(src, subS, startIndex, src.length());
584     }
585     /**
586      * Finds first index of a substring in the given source string and range with
587      * ignored case.
588      *
589      * @param src source string for examination
590      * @param sub substring to find
591      * @param startIndex starting index from where search begins
592      * @param endIndex endint index
593      * @return index of founded substring or -1 if substring is not found
594      * @see #indexOfIgnoreCase(String, String, int)
595      */

596     public static int indexOfIgnoreCase(String JavaDoc src, String JavaDoc sub, int startIndex, int endIndex) {
597         int sublen = sub.length();
598         if (sublen == 0) {
599             return startIndex;
600         }
601         sub = sub.toLowerCase();
602         int total = endIndex - sublen + 1;
603         char c = sub.charAt(0);
604     mainloop:
605         for (int i = startIndex; i < total; i++) {
606             if (Character.toLowerCase(src.charAt(i)) != c) {
607                 continue;
608             }
609             int j = 1;
610             int k = i + 1;
611             while (j < sublen) {
612                 char source = Character.toLowerCase(src.charAt(k));
613                 if (sub.charAt(j) != source) {
614                     continue mainloop;
615                 }
616                 j++; k++;
617             }
618             return i;
619         }
620         return -1;
621     }
622
623
624     /**
625      * Finds last index of a substring in the given source string with ignored
626      * case.
627      *
628      * @param s source string
629      * @param subS substring to find
630      *
631      * @return last index of founded substring or -1 if substring is not found
632      * @see #indexOfIgnoreCase(String, String, int)
633      * @see #lastIndexOfIgnoreCase(String, String, int)
634      */

635     public static int lastIndexOfIgnoreCase(String JavaDoc s, String JavaDoc subS) {
636         return lastIndexOfIgnoreCase(s, subS, s.length(), 0);
637     }
638
639     /**
640      * Finds last index of a substring in the given source string with ignored
641      * case.
642      *
643      * @param src source string for examination
644      * @param subS substring to find
645      * @param startIndex starting index from where search begins
646      *
647      * @return last index of founded substring or -1 if substring is not found
648      * @see #indexOfIgnoreCase(String, String, int)
649      */

650     public static int lastIndexOfIgnoreCase(String JavaDoc src, String JavaDoc subS, int startIndex) {
651         return lastIndexOfIgnoreCase(src, subS, startIndex, 0);
652     }
653     /**
654      * Finds last index of a substring in the given source string with ignored
655      * case in specified range.
656      *
657      * @param src source to examine
658      * @param sub substring to find
659      * @param startIndex starting index
660      * @param endIndex end index
661      * @return last index of founded substring or -1 if substring is not found
662      */

663     public static int lastIndexOfIgnoreCase(String JavaDoc src, String JavaDoc sub, int startIndex, int endIndex) {
664         int sublen = sub.length();
665         if (sublen == 0) {
666             return startIndex;
667         }
668         sub = sub.toLowerCase();
669         int total = src.length() - sublen;
670         if (total < 0) {
671             return -1;
672         }
673         if (startIndex >= total) {
674             startIndex = total;
675         }
676         char c = sub.charAt(0);
677     mainloop:
678         for (int i = startIndex; i >= endIndex; i--) {
679             if (Character.toLowerCase(src.charAt(i)) != c) {
680                 continue;
681             }
682             int j = 1;
683             int k = i + 1;
684             while (j < sublen) {
685                 char source = Character.toLowerCase(src.charAt(k));
686                 if (sub.charAt(j) != source) {
687                     continue mainloop;
688                 }
689                 j++; k++;
690             }
691             return i;
692         }
693         return -1;
694     }
695
696     /**
697      * Finds last index of a substring in the given source string in specified range [end, start]
698      * See {@link #indexOf(String, String, int, int)} for details about the speed.
699      *
700      * @param src source to examine
701      * @param sub substring to find
702      * @param startIndex starting index
703      * @param endIndex end index
704      * @return last index of founded substring or -1 if substring is not found
705      */

706     public static int lastIndexOf(String JavaDoc src, String JavaDoc sub, int startIndex, int endIndex) {
707         int sublen = sub.length();
708         if (sublen == 0) {
709             return startIndex;
710         }
711         int total = src.length() - sublen;
712         if (total < 0) {
713             return -1;
714         }
715         if (startIndex >= total) {
716             startIndex = total;
717         }
718         char c = sub.charAt(0);
719     mainloop:
720         for (int i = startIndex; i >= endIndex; i--) {
721             if (src.charAt(i) != c) {
722                 continue;
723             }
724             int j = 1;
725             int k = i + 1;
726             while (j < sublen) {
727                 if (sub.charAt(j) != src.charAt(k)) {
728                     continue mainloop;
729                 }
730                 j++; k++;
731             }
732             return i;
733         }
734         return -1;
735     }
736
737     /**
738      * Finds last index of a character in the given source string in specified range [end, start]
739      */

740     public static int lastIndexOf(String JavaDoc src, char c, int startIndex, int endIndex) {
741         int total = src.length() - 1;
742         if (total < 0) {
743             return -1;
744         }
745         if (startIndex >= total) {
746             startIndex = total;
747         }
748         for (int i = startIndex; i >= endIndex; i--) {
749             if (src.charAt(i) == c) {
750                 return i;
751             }
752         }
753         return -1;
754     }
755
756
757
758     /**
759      * Tests if this string starts with the specified prefix with ignored case.
760      *
761      * @param src source string to test
762      * @param subS starting substring
763      *
764      * @return <code>true</code> if the character sequence represented by the argument is
765      * a prefix of the character sequence represented by this string;
766      * <code>false</code> otherwise.
767      */

768     public static boolean startsWithIgnoreCase(String JavaDoc src, String JavaDoc subS) {
769         return startsWithIgnoreCase(src, subS, 0);
770     }
771
772     /**
773      * Tests if this string starts with the specified prefix with ignored case
774      * and with the specified prefix beginning a specified index.
775      *
776      * @param src source string to test
777      * @param subS starting substring
778      * @param startIndex index from where to test
779      *
780      * @return <code>true</code> if the character sequence represented by the argument is
781      * a prefix of the character sequence represented by this string;
782      * <code>false</code> otherwise.
783      */

784     public static boolean startsWithIgnoreCase(String JavaDoc src, String JavaDoc subS, int startIndex) {
785         String JavaDoc sub = subS.toLowerCase();
786         int sublen = sub.length();
787         if (startIndex + sublen > src.length()) {
788             return false;
789         }
790         int j = 0;
791         int i = startIndex;
792         while (j < sublen) {
793             char source = Character.toLowerCase(src.charAt(i));
794             if (sub.charAt(j) != source) {
795                 return false;
796             }
797             j++; i++;
798         }
799         return true;
800     }
801
802     /**
803      * Tests if this string ends with the specified suffix.
804      *
805      * @param src String to test
806      * @param subS suffix
807      *
808      * @return <code>true</code> if the character sequence represented by the argument is
809      * a suffix of the character sequence represented by this object;
810      * <code>false</code> otherwise.
811      */

812     public static boolean endsWithIgnoreCase(String JavaDoc src, String JavaDoc subS) {
813         String JavaDoc sub = subS.toLowerCase();
814         int sublen = sub.length();
815         int j = 0;
816         int i = src.length() - sublen;
817         if (i < 0) {
818             return false;
819         }
820         while (j < sublen) {
821             char source = Character.toLowerCase(src.charAt(i));
822             if (sub.charAt(j) != source) {
823                 return false;
824             }
825             j++; i++;
826         }
827         return true;
828     }
829
830
831     // ---------------------------------------------------------------- count substrings
832

833     /**
834      * Count substring occurrences in a source string.
835      *
836      * @param source source string
837      * @param sub substring to count
838      * @return number of substring occurrences
839      */

840     public static int count(String JavaDoc source, String JavaDoc sub) {
841         return count(source, sub, 0);
842     }
843     public static int count(String JavaDoc source, String JavaDoc sub, int start) {
844         int count = 0;
845         int j = start;
846         while (true) {
847             int i = source.indexOf(sub, j);
848             if (i == -1) {
849                 break;
850             }
851             count++;
852             j = i + sub.length();
853         }
854         return count;
855     }
856
857     public static int count(String JavaDoc source, char c) {
858