View Javadoc
1   /* ====================================================================
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 2002 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowlegement:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.codehaus.org/)."
23   *    Alternately, this acknowlegement may appear in the software itself,
24   *    if and wherever such third-party acknowlegements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written
29   *    permission, please contact codehaus@codehaus.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Software Foundation.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.codehaus.org/>.
53   */
54  package org.codehaus.plexus.util;
55  
56  import java.util.Arrays;
57  import java.util.Iterator;
58  import java.util.Locale;
59  import java.util.Map;
60  import java.util.StringTokenizer;
61  
62  /**
63   * <p>Common <code>String</code> manipulation routines.</p>
64   *
65   * <p>Originally from
66   * <a href="http://jakarta.apache.org/turbine/">Turbine</a> and the
67   * GenerationJavaCore library.</p>
68   *
69   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
70   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
71   * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
72   * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a>
73   * @author <a href="mailto:ed@codehaus.org">Ed Korthof</a>
74   * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
75   * @author Stephen Colebourne
76   * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
77   * @author Holger Krauth
78   * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
79   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
80   * @since 1.0
81   * @version $Id$
82   */
83  public class StringUtils
84  {
85      /**
86       * <p><code>StringUtils</code> instances should NOT be constructed in
87       * standard programming. Instead, the class should be used as
88       * <code>StringUtils.trim(" foo ");</code>.</p>
89       *
90       * <p>This constructor is public to permit tools that require a JavaBean
91       * manager to operate.</p>
92       */
93      public StringUtils()
94      {
95      }
96  
97      // Empty
98      //--------------------------------------------------------------------------
99  
100     /**
101      * <p>Removes control characters, including whitespace, from both
102      * ends of this String, handling <code>null</code> by returning
103      * an empty String.</p>
104      *
105      * @see java.lang.String#trim()
106      * @param str the String to check
107      * @return the trimmed text (never <code>null</code>)
108      */
109     public static String clean( String str )
110     {
111         return ( str == null ? "" : str.trim() );
112     }
113 
114     /**
115      * <p>Removes control characters, including whitespace, from both
116      * ends of this String, handling <code>null</code> by returning
117      * <code>null</code>.</p>
118      *
119      * @see java.lang.String#trim()
120      * @param str the String to check
121      * @return the trimmed text (or <code>null</code>)
122      */
123     public static String trim( String str )
124     {
125         return ( str == null ? null : str.trim() );
126     }
127 
128     /**
129      * <p>Deletes all whitespaces from a String.</p>
130      *
131      * <p>Whitespace is defined by
132      * {@link Character#isWhitespace(char)}.</p>
133      *
134      * @param str String target to delete whitespace from
135      * @return the String without whitespaces
136      * @throws NullPointerException
137      */
138     public static String deleteWhitespace( String str )
139     {
140         StringBuilder buffer = new StringBuilder();
141         int sz = str.length();
142         for ( int i = 0; i < sz; i++ )
143         {
144             if ( !Character.isWhitespace( str.charAt( i ) ) )
145             {
146                 buffer.append( str.charAt( i ) );
147             }
148         }
149         return buffer.toString();
150     }
151 
152     /**
153      * <p>Checks if a String is non <code>null</code> and is
154      * not empty (<code>length &lt; 0</code>).</p>
155      *
156      * @param str the String to check
157      * @return true if the String is non-null, and not length zero
158      */
159     public static boolean isNotEmpty( String str )
160     {
161         return ( ( str != null ) && ( str.length() > 0 ) );
162     }
163 
164     /**
165      * <p>Checks if a (trimmed) String is <code>null</code> or empty.</p>
166      *
167      * <p><strong>Note:</strong> In future releases, this method will no longer trim the input string such that it works
168      * complementary to {@link #isNotEmpty(String)}. Code that wants to test for whitespace-only strings should be
169      * migrated to use {@link #isBlank(String)} instead.</p>
170      *
171      * @param str the String to check
172      * @return <code>true</code> if the String is <code>null</code>, or
173      *  length zero once trimmed
174      */
175     public static boolean isEmpty( String str )
176     {
177         return ( ( str == null ) || ( str.trim().length() == 0 ) );
178     }
179 
180     /**
181      * <p>
182      * Checks if a String is whitespace, empty ("") or null.
183      * </p>
184      *
185      * <pre>
186      * StringUtils.isBlank(null)      = true
187      * StringUtils.isBlank("")        = true
188      * StringUtils.isBlank(" ")       = true
189      * StringUtils.isBlank("bob")     = false
190      * StringUtils.isBlank("  bob  ") = false
191      * </pre>
192      *
193      * @param str the String to check, may be null
194      * @return <code>true</code> if the String is null, empty or whitespace
195      * @since 1.5.2
196      */
197     public static boolean isBlank( String str )
198     {
199         int strLen;
200         if ( str == null || ( strLen = str.length() ) == 0 )
201         {
202             return true;
203         }
204         for ( int i = 0; i < strLen; i++ )
205         {
206             if ( !Character.isWhitespace( str.charAt( i ) ) )
207             {
208                 return false;
209             }
210         }
211         return true;
212     }
213 
214     /**
215      * <p>
216      * Checks if a String is not empty (""), not null and not whitespace only.
217      * </p>
218      *
219      * <pre>
220      * StringUtils.isNotBlank(null)      = false
221      * StringUtils.isNotBlank("")        = false
222      * StringUtils.isNotBlank(" ")       = false
223      * StringUtils.isNotBlank("bob")     = true
224      * StringUtils.isNotBlank("  bob  ") = true
225      * </pre>
226      *
227      * @param str the String to check, may be null
228      * @return <code>true</code> if the String is not empty and not null and not whitespace
229      * @since 1.5.2
230      */
231     public static boolean isNotBlank( String str )
232     {
233         return !StringUtils.isBlank( str );
234     }
235 
236     // Equals and IndexOf
237     //--------------------------------------------------------------------------
238 
239     /**
240      * <p>Compares two Strings, returning <code>true</code> if they are equal.</p>
241      *
242      * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
243      * references are considered to be equal. The comparison is case sensitive.</p>
244      *
245      * @see java.lang.String#equals(Object)
246      * @param str1 the first string
247      * @param str2 the second string
248      * @return <code>true</code> if the Strings are equal, case sensitive, or
249      *  both <code>null</code>
250      */
251     public static boolean equals( String str1, String str2 )
252     {
253         return ( str1 == null ? str2 == null : str1.equals( str2 ) );
254     }
255 
256     /**
257      * <p>Compares two Strings, returning <code>true</code> if they are equal ignoring
258      * the case.</p>
259      *
260      * <p><code>Nulls</code> are handled without exceptions. Two <code>null</code>
261      * references are considered equal. Comparison is case insensitive.</p>
262      *
263      * @see java.lang.String#equalsIgnoreCase(String)
264      * @param str1  the first string
265      * @param str2  the second string
266      * @return <code>true</code> if the Strings are equal, case insensitive, or
267      *  both <code>null</code>
268      */
269     public static boolean equalsIgnoreCase( String str1, String str2 )
270     {
271         return ( str1 == null ? str2 == null : str1.equalsIgnoreCase( str2 ) );
272     }
273 
274     /**
275      * <p>Find the first index of any of a set of potential substrings.</p>
276      *
277      * <p><code>null</code> String will return <code>-1</code>.</p>
278      *
279      * @param str the String to check
280      * @param searchStrs the Strings to search for
281      * @return the first index of any of the searchStrs in str
282      * @throws NullPointerException if any of searchStrs[i] is <code>null</code>
283      */
284     public static int indexOfAny( String str, String[] searchStrs )
285     {
286         if ( ( str == null ) || ( searchStrs == null ) )
287         {
288             return -1;
289         }
290         int sz = searchStrs.length;
291 
292         // String's can't have a MAX_VALUEth index.
293         int ret = Integer.MAX_VALUE;
294 
295         int tmp;
296         for ( String searchStr : searchStrs )
297         {
298             tmp = str.indexOf( searchStr );
299             if ( tmp == -1 )
300             {
301                 continue;
302             }
303 
304             if ( tmp < ret )
305             {
306                 ret = tmp;
307             }
308         }
309 
310         return ( ret == Integer.MAX_VALUE ) ? -1 : ret;
311     }
312 
313     /**
314      * <p>Find the latest index of any of a set of potential substrings.</p>
315      *
316      * <p><code>null</code> string will return <code>-1</code>.</p>
317      *
318      * @param str  the String to check
319      * @param searchStrs  the Strings to search for
320      * @return the last index of any of the Strings
321      * @throws NullPointerException if any of searchStrs[i] is <code>null</code>
322      */
323     public static int lastIndexOfAny( String str, String[] searchStrs )
324     {
325         if ( ( str == null ) || ( searchStrs == null ) )
326         {
327             return -1;
328         }
329         int ret = -1;
330         int tmp;
331         for ( String searchStr : searchStrs )
332         {
333             tmp = str.lastIndexOf( searchStr );
334             if ( tmp > ret )
335             {
336                 ret = tmp;
337             }
338         }
339         return ret;
340     }
341 
342     // Substring
343     //--------------------------------------------------------------------------
344 
345     /**
346      * <p>Gets a substring from the specified string avoiding exceptions.</p>
347      *
348      * <p>A negative start position can be used to start <code>n</code>
349      * characters from the end of the String.</p>
350      *
351      * @param str the String to get the substring from
352      * @param start the position to start from, negative means
353      *  count back from the end of the String by this many characters
354      * @return substring from start position
355      */
356     public static String substring( String str, int start )
357     {
358         if ( str == null )
359         {
360             return null;
361         }
362 
363         // handle negatives, which means last n characters
364         if ( start < 0 )
365         {
366             start = str.length() + start; // remember start is negative
367         }
368 
369         if ( start < 0 )
370         {
371             start = 0;
372         }
373         if ( start > str.length() )
374         {
375             return "";
376         }
377 
378         return str.substring( start );
379     }
380 
381     /**
382      * <p>Gets a substring from the specified String avoiding exceptions.</p>
383      *
384      * <p>A negative start position can be used to start/end <code>n</code>
385      * characters from the end of the String.</p>
386      *
387      * @param str the String to get the substring from
388      * @param start the position to start from, negative means
389      *  count back from the end of the string by this many characters
390      * @param end the position to end at (exclusive), negative means
391      *  count back from the end of the String by this many characters
392      * @return substring from start position to end positon
393      */
394     public static String substring( String str, int start, int end )
395     {
396         if ( str == null )
397         {
398             return null;
399         }
400 
401         // handle negatives
402         if ( end < 0 )
403         {
404             end = str.length() + end; // remember end is negative
405         }
406         if ( start < 0 )
407         {
408             start = str.length() + start; // remember start is negative
409         }
410 
411         // check length next
412         if ( end > str.length() )
413         {
414             // check this works.
415             end = str.length();
416         }
417 
418         // if start is greater than end, return ""
419         if ( start > end )
420         {
421             return "";
422         }
423 
424         if ( start < 0 )
425         {
426             start = 0;
427         }
428         if ( end < 0 )
429         {
430             end = 0;
431         }
432 
433         return str.substring( start, end );
434     }
435 
436     /**
437      * <p>Gets the leftmost <code>n</code> characters of a String.</p>
438      *
439      * <p>If <code>n</code> characters are not available, or the
440      * String is <code>null</code>, the String will be returned without
441      * an exception.</p>
442      *
443      * @param str the String to get the leftmost characters from
444      * @param len the length of the required String
445      * @return the leftmost characters
446      * @throws IllegalArgumentException if len is less than zero
447      */
448     public static String left( String str, int len )
449     {
450         if ( len < 0 )
451         {
452             throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" );
453         }
454         if ( ( str == null ) || ( str.length() <= len ) )
455         {
456             return str;
457         }
458         else
459         {
460             return str.substring( 0, len );
461         }
462     }
463 
464     /**
465      * <p>Gets the rightmost <code>n</code> characters of a String.</p>
466      *
467      * <p>If <code>n</code> characters are not available, or the String
468      * is <code>null</code>, the String will be returned without an
469      * exception.</p>
470      *
471      * @param str the String to get the rightmost characters from
472      * @param len the length of the required String
473      * @return the leftmost characters
474      * @throws IllegalArgumentException if len is less than zero
475      */
476     public static String right( String str, int len )
477     {
478         if ( len < 0 )
479         {
480             throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" );
481         }
482         if ( ( str == null ) || ( str.length() <= len ) )
483         {
484             return str;
485         }
486         else
487         {
488             return str.substring( str.length() - len );
489         }
490     }
491 
492     /**
493      * <p>Gets <code>n</code> characters from the middle of a String.</p>
494      *
495      * <p>If <code>n</code> characters are not available, the remainder
496      * of the String will be returned without an exception. If the
497      * String is <code>null</code>, <code>null</code> will be returned.</p>
498      *
499      * @param str the String to get the characters from
500      * @param pos the position to start from
501      * @param len the length of the required String
502      * @return the leftmost characters
503      * @throws IndexOutOfBoundsException if pos is out of bounds
504      * @throws IllegalArgumentException if len is less than zero
505      */
506     public static String mid( String str, int pos, int len )
507     {
508         if ( ( pos < 0 ) ||
509             ( ( str != null ) && ( pos > str.length() ) ) )
510         {
511             throw new StringIndexOutOfBoundsException( "String index " + pos + " is out of bounds" );
512         }
513         if ( len < 0 )
514         {
515             throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" );
516         }
517         if ( str == null )
518         {
519             return null;
520         }
521         if ( str.length() <= ( pos + len ) )
522         {
523             return str.substring( pos );
524         }
525         else
526         {
527             return str.substring( pos, pos + len );
528         }
529     }
530 
531     // Splitting
532     //--------------------------------------------------------------------------
533 
534     /**
535      * <p>Splits the provided text into a array, using whitespace as the
536      * separator.</p>
537      *
538      * <p>The separator is not included in the returned String array.</p>
539      *
540      * @param str the String to parse
541      * @return an array of parsed Strings
542      */
543     public static String[] split( String str )
544     {
545         return split( str, null, -1 );
546     }
547 
548     /**
549      * @see #split(String, String, int)
550      */
551     public static String[] split( String text, String separator )
552     {
553         return split( text, separator, -1 );
554     }
555 
556     /**
557      * <p>Splits the provided text into a array, based on a given separator.</p>
558      *
559      * <p>The separator is not included in the returned String array. The
560      * maximum number of splits to perfom can be controlled. A <code>null</code>
561      * separator will cause parsing to be on whitespace.</p>
562      *
563      * <p>This is useful for quickly splitting a String directly into
564      * an array of tokens, instead of an enumeration of tokens (as
565      * <code>StringTokenizer</code> does).</p>
566      *
567      * @param str The string to parse.
568      * @param separator Characters used as the delimiters. If
569      *  <code>null</code>, splits on whitespace.
570      * @param max The maximum number of elements to include in the
571      *  array.  A zero or negative value implies no limit.
572      * @return an array of parsed Strings
573      */
574     public static String[] split( String str, String separator, int max )
575     {
576         StringTokenizer tok;
577         if ( separator == null )
578         {
579             // Null separator means we're using StringTokenizer's default
580             // delimiter, which comprises all whitespace characters.
581             tok = new StringTokenizer( str );
582         }
583         else
584         {
585             tok = new StringTokenizer( str, separator );
586         }
587 
588         int listSize = tok.countTokens();
589         if ( ( max > 0 ) && ( listSize > max ) )
590         {
591             listSize = max;
592         }
593 
594         String[] list = new String[listSize];
595         int i = 0;
596         int lastTokenBegin;
597         int lastTokenEnd = 0;
598         while ( tok.hasMoreTokens() )
599         {
600             if ( ( max > 0 ) && ( i == listSize - 1 ) )
601             {
602                 // In the situation where we hit the max yet have
603                 // tokens left over in our input, the last list
604                 // element gets all remaining text.
605                 String endToken = tok.nextToken();
606                 lastTokenBegin = str.indexOf( endToken, lastTokenEnd );
607                 list[i] = str.substring( lastTokenBegin );
608                 break;
609             }
610             else
611             {
612                 list[i] = tok.nextToken();
613                 lastTokenBegin = str.indexOf( list[i], lastTokenEnd );
614                 lastTokenEnd = lastTokenBegin + list[i].length();
615             }
616             i++;
617         }
618         return list;
619     }
620 
621     // Joining
622     //--------------------------------------------------------------------------
623     /**
624      * <p>Concatenates elements of an array into a single String.</p>
625      *
626      * <p>The difference from join is that concatenate has no delimiter.</p>
627      *
628      * @param array the array of values to concatenate.
629      * @return the concatenated string.
630      */
631     public static String concatenate( Object[] array )
632     {
633         return join( array, "" );
634     }
635 
636     /**
637      * <p>Joins the elements of the provided array into a single String
638      * containing the provided list of elements.</p>
639      *
640      * <p>No delimiter is added before or after the list. A
641      * <code>null</code> separator is the same as a blank String.</p>
642      *
643      * @param array the array of values to join together
644      * @param separator the separator character to use
645      * @return the joined String
646      */
647     public static String join( Object[] array, String separator )
648     {
649         if ( separator == null )
650         {
651             separator = "";
652         }
653         int arraySize = array.length;
654         int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() +
655             separator.length() ) * arraySize );
656         StringBuilder buf = new StringBuilder( bufSize );
657 
658         for ( int i = 0; i < arraySize; i++ )
659         {
660             if ( i > 0 )
661             {
662                 buf.append( separator );
663             }
664             buf.append( array[i] );
665         }
666         return buf.toString();
667     }
668 
669     /**
670      * <p>Joins the elements of the provided <code>Iterator</code> into
671      * a single String containing the provided elements.</p>
672      *
673      * <p>No delimiter is added before or after the list. A
674      * <code>null</code> separator is the same as a blank String.</p>
675      *
676      * @param iterator the <code>Iterator</code> of values to join together
677      * @param separator  the separator character to use
678      * @return the joined String
679      */
680     public static String join( Iterator<?> iterator, String separator )
681     {
682         if ( separator == null )
683         {
684             separator = "";
685         }
686         StringBuilder buf = new StringBuilder( 256 );  // Java default is 16, probably too small
687         while ( iterator.hasNext() )
688         {
689             buf.append( iterator.next() );
690             if ( iterator.hasNext() )
691             {
692                 buf.append( separator );
693             }
694         }
695         return buf.toString();
696     }
697 
698 
699 
700     // Replacing
701     //--------------------------------------------------------------------------
702 
703     /**
704      * <p>Replace a char with another char inside a larger String, once.</p>
705      *
706      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
707      *
708      * @see #replace(String text, char repl, char with, int max)
709      * @param text text to search and replace in
710      * @param repl char to search for
711      * @param with char to replace with
712      * @return the text with any replacements processed
713      */
714     public static String replaceOnce( String text, char repl, char with )
715     {
716         return replace( text, repl, with, 1 );
717     }
718 
719     /**
720      * <p>Replace all occurances of a char within another char.</p>
721      *
722      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
723      *
724      * @see #replace(String text, char repl, char with, int max)
725      * @param text text to search and replace in
726      * @param repl char to search for
727      * @param with char to replace with
728      * @return the text with any replacements processed
729      */
730     public static String replace( String text, char repl, char with )
731     {
732         return replace( text, repl, with, -1 );
733     }
734 
735     /**
736      * <p>Replace a char with another char inside a larger String,
737      * for the first <code>max</code> values of the search char.</p>
738      *
739      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
740      *
741      * @param text text to search and replace in
742      * @param repl char to search for
743      * @param with char to replace with
744      * @param max maximum number of values to replace, or <code>-1</code> if no maximum
745      * @return the text with any replacements processed
746      */
747     public static String replace( String text, char repl, char with, int max )
748     {
749         return replace( text, String.valueOf( repl ), String.valueOf( with ), max );
750     }
751 
752     /**
753      * <p>Replace a String with another String inside a larger String, once.</p>
754      *
755      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
756      *
757      * @see #replace(String text, String repl, String with, int max)
758      * @param text text to search and replace in
759      * @param repl String to search for
760      * @param with String to replace with
761      * @return the text with any replacements processed
762      */
763     public static String replaceOnce( String text, String repl, String with )
764     {
765         return replace( text, repl, with, 1 );
766     }
767 
768     /**
769      * <p>Replace all occurances of a String within another String.</p>
770      *
771      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
772      *
773      * @see #replace(String text, String repl, String with, int max)
774      * @param text text to search and replace in
775      * @param repl String to search for
776      * @param with String to replace with
777      * @return the text with any replacements processed
778      */
779     public static String replace( String text, String repl, String with )
780     {
781         return replace( text, repl, with, -1 );
782     }
783 
784     /**
785      * <p>Replace a String with another String inside a larger String,
786      * for the first <code>max</code> values of the search String.</p>
787      *
788      * <p>A <code>null</code> reference passed to this method is a no-op.</p>
789      *
790      * @param text text to search and replace in
791      * @param repl String to search for
792      * @param with String to replace with
793      * @param max maximum number of values to replace, or <code>-1</code> if no maximum
794      * @return the text with any replacements processed
795      */
796     public static String replace( String text, String repl, String with, int max )
797     {
798         if ( ( text == null ) || ( repl == null ) || ( with == null ) || ( repl.length() == 0 ) )
799         {
800             return text;
801         }
802 
803         StringBuilder buf = new StringBuilder( text.length() );
804         int start = 0, end;
805         while ( ( end = text.indexOf( repl, start ) ) != -1 )
806         {
807             buf.append( text, start, end ).append( with );
808             start = end + repl.length();
809 
810             if ( --max == 0 )
811             {
812                 break;
813             }
814         }
815         buf.append( text, start, text.length());
816         return buf.toString();
817     }
818 
819     /**
820      * <p>Overlay a part of a String with another String.</p>
821      *
822      * @param text String to do overlaying in
823      * @param overlay String to overlay
824      * @param start int to start overlaying at
825      * @param end int to stop overlaying before
826      * @return String with overlayed text
827      * @throws NullPointerException if text or overlay is <code>null</code>
828      */
829     public static String overlayString( String text, String overlay, int start, int end )
830     {
831         return new StringBuffer( start + overlay.length() + text.length() - end + 1 )
832             .append( text, 0, start  )
833             .append( overlay )
834             .append( text, end, text.length() )
835             .toString();
836     }
837 
838     // Centering
839     //--------------------------------------------------------------------------
840 
841     /**
842      * <p>Center a String in a larger String of size <code>n</code>.<p>
843      *
844      * <p>Uses spaces as the value to buffer the String with.
845      * Equivalent to <code>center(str, size, " ")</code>.</p>
846      *
847      * @param str String to center
848      * @param size int size of new String
849      * @return String containing centered String
850      * @throws NullPointerException if str is <code>null</code>
851      */
852     public static String center( String str, int size )
853     {
854         return center( str, size, " " );
855     }
856 
857     /**
858      * <p>Center a String in a larger String of size <code>n</code>.</p>
859      *
860      * <p>Uses a supplied String as the value to buffer the String with.</p>
861      *
862      * @param str String to center
863      * @param size int size of new String
864      * @param delim String to buffer the new String with
865      * @return String containing centered String
866      * @throws NullPointerException if str or delim is <code>null</code>
867      * @throws ArithmeticException if delim is the empty String
868      */
869     public static String center( String str, int size, String delim )
870     {
871         int sz = str.length();
872         int p = size - sz;
873         if ( p < 1 )
874         {
875             return str;
876         }
877         str = leftPad( str, sz + p / 2, delim );
878         str = rightPad( str, size, delim );
879         return str;
880     }
881 
882     // Chomping
883     //--------------------------------------------------------------------------
884 
885     /**
886      * <p>Remove the last newline, and everything after it from a String.</p>
887      *
888      * @param str String to chomp the newline from
889      * @return String without chomped newline
890      * @throws NullPointerException if str is <code>null</code>
891      */
892     public static String chomp( String str )
893     {
894         return chomp( str, "\n" );
895     }
896 
897     /**
898      * <p>Remove the last value of a supplied String, and everything after
899      * it from a String.</p>
900      *
901      * @param str String to chomp from
902      * @param sep String to chomp
903      * @return String without chomped ending
904      * @throws NullPointerException if str or sep is <code>null</code>
905      */
906     public static String chomp( String str, String sep )
907     {
908         int idx = str.lastIndexOf( sep );
909         if ( idx != -1 )
910         {
911             return str.substring( 0, idx );
912         }
913         else
914         {
915             return str;
916         }
917     }
918 
919     /**
920      * <p>Remove a newline if and only if it is at the end
921      * of the supplied String.</p>
922      *
923      * @param str String to chomp from
924      * @return String without chomped ending
925      * @throws NullPointerException if str is <code>null</code>
926      */
927     public static String chompLast( String str )
928     {
929         return chompLast( str, "\n" );
930     }
931 
932     /**
933      * <p>Remove a value if and only if the String ends with that value.</p>
934      *
935      * @param str String to chomp from
936      * @param sep String to chomp
937      * @return String without chomped ending
938      * @throws NullPointerException if str or sep is <code>null</code>
939      */
940     public static String chompLast( String str, String sep )
941     {
942         if ( str.length() == 0 )
943         {
944             return str;
945         }
946         String sub = str.substring( str.length() - sep.length() );
947         if ( sep.equals( sub ) )
948         {
949             return str.substring( 0, str.length() - sep.length() );
950         }
951         else
952         {
953             return str;
954         }
955     }
956 
957     /**
958      * <p>Remove everything and return the last value of a supplied String, and
959      * everything after it from a String.</p>
960      *
961      * @param str String to chomp from
962      * @param sep String to chomp
963      * @return String chomped
964      * @throws NullPointerException if str or sep is <code>null</code>
965      */
966     public static String getChomp( String str, String sep )
967     {
968         int idx = str.lastIndexOf( sep );
969         if ( idx == str.length() - sep.length() )
970         {
971             return sep;
972         }
973         else if ( idx != -1 )
974         {
975             return str.substring( idx );
976         }
977         else
978         {
979             return "";
980         }
981     }
982 
983     /**
984      * <p>Remove the first value of a supplied String, and everything before it
985      * from a String.</p>
986      *
987      * @param str String to chomp from
988      * @param sep String to chomp
989      * @return String without chomped beginning
990      * @throws NullPointerException if str or sep is <code>null</code>
991      */
992     public static String prechomp( String str, String sep )
993     {
994         int idx = str.indexOf( sep );
995         if ( idx != -1 )
996         {
997             return str.substring( idx + sep.length() );
998         }
999         else
1000         {
1001             return str;
1002         }
1003     }
1004 
1005     /**
1006      * <p>Remove and return everything before the first value of a
1007      * supplied String from another String.</p>
1008      *
1009      * @param str String to chomp from
1010      * @param sep String to chomp
1011      * @return String prechomped
1012      * @throws NullPointerException if str or sep is <code>null</code>
1013      */
1014     public static String getPrechomp( String str, String sep )
1015     {
1016         int idx = str.indexOf( sep );
1017         if ( idx != -1 )
1018         {
1019             return str.substring( 0, idx + sep.length() );
1020         }
1021         else
1022         {
1023             return "";
1024         }
1025     }
1026 
1027     // Chopping
1028     //--------------------------------------------------------------------------
1029 
1030     /**
1031      * <p>Remove the last character from a String.</p>
1032      *
1033      * <p>If the String ends in <code>\r\n</code>, then remove both
1034      * of them.</p>
1035      *
1036      * @param str String to chop last character from
1037      * @return String without last character
1038      * @throws NullPointerException if str is <code>null</code>
1039      */
1040     public static String chop( String str )
1041     {
1042         if ( "".equals( str ) )
1043         {
1044             return "";
1045         }
1046         if ( str.length() == 1 )
1047         {
1048             return "";
1049         }
1050         int lastIdx = str.length() - 1;
1051         String ret = str.substring( 0, lastIdx );
1052         char last = str.charAt( lastIdx );
1053         if ( last == '\n' )
1054         {
1055             if ( ret.charAt( lastIdx - 1 ) == '\r' )
1056             {
1057                 return ret.substring( 0, lastIdx - 1 );
1058             }
1059         }
1060         return ret;
1061     }
1062 
1063     /**
1064      * <p>Remove <code>\n</code> from end of a String if it's there.
1065      * If a <code>\r</code> precedes it, then remove that too.</p>
1066      *
1067      * @param str String to chop a newline from
1068      * @return String without newline
1069      * @throws NullPointerException if str is <code>null</code>
1070      */
1071     public static String chopNewline( String str )
1072     {
1073         int lastIdx = str.length() - 1;
1074         char last = str.charAt( lastIdx );
1075         if ( last == '\n' )
1076         {
1077             if ( str.charAt( lastIdx - 1 ) == '\r' )
1078             {
1079                 lastIdx--;
1080             }
1081         }
1082         else
1083         {
1084             lastIdx++;
1085         }
1086         return str.substring( 0, lastIdx );
1087     }
1088 
1089 
1090     // Conversion
1091     //--------------------------------------------------------------------------
1092 
1093     // spec 3.10.6
1094     /**
1095      * <p>Escapes any values it finds into their String form.</p>
1096      *
1097      * <p>So a tab becomes the characters <code>'\\'</code> and
1098      * <code>'t'</code>.</p>
1099      *
1100      * @param str String to escape values in
1101      * @return String with escaped values
1102      * @throws NullPointerException if str is <code>null</code>
1103      */
1104     public static String escape( String str )
1105     {
1106         // improved with code from  cybertiger@cyberiantiger.org
1107         // unicode from him, and defaul for < 32's.
1108         int sz = str.length();
1109         StringBuilder buffer = new StringBuilder( 2 * sz );
1110         for ( int i = 0; i < sz; i++ )
1111         {
1112             char ch = str.charAt( i );
1113 
1114             // handle unicode
1115             if ( ch > 0xfff )
1116             {
1117                 buffer.append( "\\u" + Integer.toHexString( ch ) );
1118             }
1119             else if ( ch > 0xff )
1120             {
1121                 buffer.append( "\\u0" + Integer.toHexString( ch ) );
1122             }
1123             else if ( ch > 0x7f )
1124             {
1125                 buffer.append( "\\u00" + Integer.toHexString( ch ) );
1126             }
1127             else if ( ch < 32 )
1128             {
1129                 switch ( ch )
1130                 {
1131                     case '\b':
1132                         buffer.append( '\\' );
1133                         buffer.append( 'b' );
1134                         break;
1135                     case '\n':
1136                         buffer.append( '\\' );
1137                         buffer.append( 'n' );
1138                         break;
1139                     case '\t':
1140                         buffer.append( '\\' );
1141                         buffer.append( 't' );
1142                         break;
1143                     case '\f':
1144                         buffer.append( '\\' );
1145                         buffer.append( 'f' );
1146                         break;
1147                     case '\r':
1148                         buffer.append( '\\' );
1149                         buffer.append( 'r' );
1150                         break;
1151                     default :
1152                         if ( ch > 0xf )
1153                         {
1154                             buffer.append( "\\u00" + Integer.toHexString( ch ) );
1155                         }
1156                         else
1157                         {
1158                             buffer.append( "\\u000" + Integer.toHexString( ch ) );
1159                         }
1160                         break;
1161                 }
1162             }
1163             else
1164             {
1165                 switch ( ch )
1166                 {
1167                     case '\'':
1168                         buffer.append( '\\' );
1169                         buffer.append( '\'' );
1170                         break;
1171                     case '"':
1172                         buffer.append( '\\' );
1173                         buffer.append( '"' );
1174                         break;
1175                     case '\\':
1176                         buffer.append( '\\' );
1177                         buffer.append( '\\' );
1178                         break;
1179                     default :
1180                         buffer.append( ch );
1181                         break;
1182                 }
1183             }
1184         }
1185         return buffer.toString();
1186     }
1187 
1188     // Padding
1189     //--------------------------------------------------------------------------
1190 
1191     /**
1192      * <p>Repeat a String <code>n</code> times to form a
1193      * new string.</p>
1194      *
1195      * @param str String to repeat
1196      * @param repeat number of times to repeat str
1197      * @return String with repeated String
1198      * @throws NegativeArraySizeException if <code>repeat &lt; 0</code>
1199      * @throws NullPointerException if str is <code>null</code>
1200      */
1201     public static String repeat( String str, int repeat )
1202     {
1203         StringBuilder buffer = new StringBuilder( repeat * str.length() );
1204         for ( int i = 0; i < repeat; i++ )
1205         {
1206             buffer.append( str );
1207         }
1208         return buffer.toString();
1209     }
1210 
1211     /**
1212      * <p>Right pad a String with spaces.</p>
1213      *
1214      * <p>The String is padded to the size of <code>n</code>.</p>
1215      *
1216      * @param str String to repeat
1217      * @param size number of times to repeat str
1218      * @return right padded String
1219      * @throws NullPointerException if str is <code>null</code>
1220      */
1221     public static String rightPad( String str, int size )
1222     {
1223         return rightPad( str, size, " " );
1224     }
1225 
1226     /**
1227      * <p>Right pad a String with a specified string.</p>
1228      *
1229      * <p>The String is padded to the size of <code>n</code>.</p>
1230      *
1231      * @param str String to pad out
1232      * @param size size to pad to
1233      * @param delim String to pad with
1234      * @return right padded String
1235      * @throws NullPointerException if str or delim is <code>null</code>
1236      * @throws ArithmeticException if delim is the empty String
1237      */
1238     public static String rightPad( String str, int size, String delim )
1239     {
1240         size = ( size - str.length() ) / delim.length();
1241         if ( size > 0 )
1242         {
1243             str += repeat( delim, size );
1244         }
1245         return str;
1246     }
1247 
1248     /**
1249      * <p>Left pad a String with spaces.</p>
1250      *
1251      * <p>The String is padded to the size of <code>n</code>.</p>
1252      *
1253      * @param str String to pad out
1254      * @param size size to pad to
1255      * @return left padded String
1256      * @throws NullPointerException if str or delim is <code>null</code>
1257      */
1258     public static String leftPad( String str, int size )
1259     {
1260         return leftPad( str, size, " " );
1261     }
1262 
1263     /**
1264      * Left pad a String with a specified string. Pad to a size of n.
1265      *
1266      * @param str String to pad out
1267      * @param size size to pad to
1268      * @param delim String to pad with
1269      * @return left padded String
1270      * @throws NullPointerException if str or delim is null
1271      * @throws ArithmeticException if delim is the empty string
1272      */
1273     public static String leftPad( String str, int size, String delim )
1274     {
1275         size = ( size - str.length() ) / delim.length();
1276         if ( size > 0 )
1277         {
1278             str = repeat( delim, size ) + str;
1279         }
1280         return str;
1281     }
1282 
1283     // Stripping
1284     //--------------------------------------------------------------------------
1285 
1286     /**
1287      * <p>Remove whitespace from the front and back of a String.</p>
1288      *
1289      * @param str the String to remove whitespace from
1290      * @return the stripped String
1291      */
1292     public static String strip( String str )
1293     {
1294         return strip( str, null );
1295     }
1296 
1297     /**
1298      * <p>Remove a specified String from the front and back of a
1299      * String.</p>
1300      *
1301      * <p>If whitespace is wanted to be removed, used the
1302      * {@link #strip(java.lang.String)} method.</p>
1303      *
1304      * @param str the String to remove a string from
1305      * @param delim the String to remove at start and end
1306      * @return the stripped String
1307      */
1308     public static String strip( String str, String delim )
1309     {
1310         str = stripStart( str, delim );
1311         return stripEnd( str, delim );
1312     }
1313 
1314     /**
1315      * <p>Strip whitespace from the front and back of every String
1316      * in the array.</p>
1317      *
1318      * @param strs the Strings to remove whitespace from
1319      * @return the stripped Strings
1320      */
1321     public static String[] stripAll( String[] strs )
1322     {
1323         return stripAll( strs, null );
1324     }
1325 
1326     /**
1327      * <p>Strip the specified delimiter from the front and back of
1328      * every String in the array.</p>
1329      *
1330      * @param strs the Strings to remove a String from
1331      * @param delimiter the String to remove at start and end
1332      * @return the stripped Strings
1333      */
1334     public static String[] stripAll( String[] strs, String delimiter )
1335     {
1336         if ( ( strs == null ) || ( strs.length == 0 ) )
1337         {
1338             return strs;
1339         }
1340         int sz = strs.length;
1341         String[] newArr = new String[sz];
1342         for ( int i = 0; i < sz; i++ )
1343         {
1344             newArr[i] = strip( strs[i], delimiter );
1345         }
1346         return newArr;
1347     }
1348 
1349     /**
1350      * <p>Strip any of a supplied String from the end of a String.</p>
1351      *
1352      * <p>If the strip String is <code>null</code>, whitespace is
1353      * stripped.</p>
1354      *
1355      * @param str the String to remove characters from
1356      * @param strip the String to remove
1357      * @return the stripped String
1358      */
1359     public static String stripEnd( String str, String strip )
1360     {
1361         if ( str == null )
1362         {
1363             return null;
1364         }
1365         int end = str.length();
1366 
1367         if ( strip == null )
1368         {
1369             while ( ( end != 0 ) && Character.isWhitespace( str.charAt( end - 1 ) ) )
1370             {
1371                 end--;
1372             }
1373         }
1374         else
1375         {
1376             while ( ( end != 0 ) && ( strip.indexOf( str.charAt( end - 1 ) ) != -1 ) )
1377             {
1378                 end--;
1379             }
1380         }
1381         return str.substring( 0, end );
1382     }
1383 
1384     /**
1385      * <p>Strip any of a supplied String from the start of a String.</p>
1386      *
1387      * <p>If the strip String is <code>null</code>, whitespace is
1388      * stripped.</p>
1389      *
1390      * @param str the String to remove characters from
1391      * @param strip the String to remove
1392      * @return the stripped String
1393      */
1394     public static String stripStart( String str, String strip )
1395     {
1396         if ( str == null )
1397         {
1398             return null;
1399         }
1400 
1401         int start = 0;
1402 
1403         int sz = str.length();
1404 
1405         if ( strip == null )
1406         {
1407             while ( ( start != sz ) && Character.isWhitespace( str.charAt( start ) ) )
1408             {
1409                 start++;
1410             }
1411         }
1412         else
1413         {
1414             while ( ( start != sz ) && ( strip.indexOf( str.charAt( start ) ) != -1 ) )
1415             {
1416                 start++;
1417             }
1418         }
1419         return str.substring( start );
1420     }
1421 
1422     // Case conversion
1423     //--------------------------------------------------------------------------
1424 
1425     /**
1426      * <p>Convert a String to upper case, <code>null</code> String
1427      * returns <code>null</code>.</p>
1428      *
1429      * @param str the String to uppercase
1430      * @return the upper cased String
1431      */
1432     public static String upperCase( String str )
1433     {
1434         if ( str == null )
1435         {
1436             return null;
1437         }
1438         return str.toUpperCase();
1439     }
1440 
1441     /**
1442      * <p>Convert a String to lower case, <code>null</code> String
1443      * returns <code>null</code>.</p>
1444      *
1445      * @param str the string to lowercase
1446      * @return the lower cased String
1447      */
1448     public static String lowerCase( String str )
1449     {
1450         if ( str == null )
1451         {
1452             return null;
1453         }
1454         return str.toLowerCase();
1455     }
1456 
1457     /**
1458      * <p>Uncapitalise a String.</p>
1459      *
1460      * <p>That is, convert the first character into lower-case.
1461      * <code>null</code> is returned as <code>null</code>.</p>
1462      *
1463      * @param str the String to uncapitalise
1464      * @return uncapitalised String
1465      */
1466     public static String uncapitalise( String str )
1467     {
1468         if ( str == null )
1469         {
1470             return null;
1471         }
1472         else if ( str.length() == 0 )
1473         {
1474             return "";
1475         }
1476         else
1477         {
1478             return new StringBuffer( str.length() )
1479                 .append( Character.toLowerCase( str.charAt( 0 ) ) )
1480                 .append( str, 1, str.length() )
1481                 .toString();
1482         }
1483     }
1484 
1485     /**
1486      * <p>Capitalise a String.</p>
1487      *
1488      * <p>That is, convert the first character into title-case.
1489      * <code>null</code> is returned as <code>null</code>.</p>
1490      *
1491      * @param str the String to capitalise
1492      * @return capitalised String
1493      */
1494     public static String capitalise( String str )
1495     {
1496         if ( str == null )
1497         {
1498             return null;
1499         }
1500         else if ( str.length() == 0 )
1501         {
1502             return "";
1503         }
1504         else
1505         {
1506             return new StringBuilder( str.length() )
1507                 .append( Character.toTitleCase( str.charAt( 0 ) ) )
1508                 .append( str, 1, str.length() )
1509                 .toString();
1510         }
1511     }
1512 
1513     /**
1514      * <p>Swaps the case of String.</p>
1515      *
1516      * <p>Properly looks after making sure the start of words
1517      * are Titlecase and not Uppercase.</p>
1518      *
1519      * <p><code>null</code> is returned as <code>null</code>.</p>
1520      *
1521      * @param str the String to swap the case of
1522      * @return the modified String
1523      */
1524     public static String swapCase( String str )
1525     {
1526         if ( str == null )
1527         {
1528             return null;
1529         }
1530         int sz = str.length();
1531         StringBuilder buffer = new StringBuilder( sz );
1532 
1533         boolean whitespace = false;
1534         char ch;
1535         char tmp;
1536 
1537         for ( int i = 0; i < sz; i++ )
1538         {
1539             ch = str.charAt( i );
1540             if ( Character.isUpperCase( ch ) )
1541             {
1542                 tmp = Character.toLowerCase( ch );
1543             }
1544             else if ( Character.isTitleCase( ch ) )
1545             {
1546                 tmp = Character.toLowerCase( ch );
1547             }
1548             else if ( Character.isLowerCase( ch ) )
1549             {
1550                 if ( whitespace )
1551                 {
1552                     tmp = Character.toTitleCase( ch );
1553                 }
1554                 else
1555                 {
1556                     tmp = Character.toUpperCase( ch );
1557                 }
1558             }
1559             else
1560             {
1561                 tmp = ch;
1562             }
1563             buffer.append( tmp );
1564             whitespace = Character.isWhitespace( ch );
1565         }
1566         return buffer.toString();
1567     }
1568 
1569 
1570     /**
1571      * <p>Capitalise all the words in a String.</p>
1572      *
1573      * <p>Uses {@link Character#isWhitespace(char)} as a
1574      * separator between words.</p>
1575      *
1576      * <p><code>null</code> will return <code>null</code>.</p>
1577      *
1578      * @param str the String to capitalise
1579      * @return capitalised String
1580      */
1581     public static String capitaliseAllWords( String str )
1582     {
1583         if ( str == null )
1584         {
1585             return null;
1586         }
1587         int sz = str.length();
1588         StringBuilder buffer = new StringBuilder( sz );
1589         boolean space = true;
1590         for ( int i = 0; i < sz; i++ )
1591         {
1592             char ch = str.charAt( i );
1593             if ( Character.isWhitespace( ch ) )
1594             {
1595                 buffer.append( ch );
1596                 space = true;
1597             }
1598             else if ( space )
1599             {
1600                 buffer.append( Character.toTitleCase( ch ) );
1601                 space = false;
1602             }
1603             else
1604             {
1605                 buffer.append( ch );
1606             }
1607         }
1608         return buffer.toString();
1609     }
1610 
1611     /**
1612      * <p>Uncapitalise all the words in a string.</p>
1613      *
1614      * <p>Uses {@link Character#isWhitespace(char)} as a
1615      * separator between words.</p>
1616      *
1617      * <p><code>null</code> will return <code>null</code>.</p>
1618      *
1619      * @param str  the string to uncapitalise
1620      * @return uncapitalised string
1621      */
1622     public static String uncapitaliseAllWords( String str )
1623     {
1624         if ( str == null )
1625         {
1626             return null;
1627         }
1628         int sz = str.length();
1629         StringBuilder buffer = new StringBuilder( sz );
1630         boolean space = true;
1631         for ( int i = 0; i < sz; i++ )
1632         {
1633             char ch = str.charAt( i );
1634             if ( Character.isWhitespace( ch ) )
1635             {
1636                 buffer.append( ch );
1637                 space = true;
1638             }
1639             else if ( space )
1640             {
1641                 buffer.append( Character.toLowerCase( ch ) );
1642                 space = false;
1643             }
1644             else
1645             {
1646                 buffer.append( ch );
1647             }
1648         }
1649         return buffer.toString();
1650     }
1651 
1652     // Nested extraction
1653     //--------------------------------------------------------------------------
1654 
1655     /**
1656      * <p>Get the String that is nested in between two instances of the
1657      * same String.</p>
1658      *
1659      * <p>If <code>str</code> is <code>null</code>, will
1660      * return <code>null</code>.</p>
1661      *
1662      * @param str the String containing nested-string
1663      * @param tag the String before and after nested-string
1664      * @return the String that was nested, or <code>null</code>
1665      * @throws NullPointerException if tag is <code>null</code>
1666      */
1667     public static String getNestedString( String str, String tag )
1668     {
1669         return getNestedString( str, tag, tag );
1670     }
1671 
1672     /**
1673      * <p>Get the String that is nested in between two Strings.</p>
1674      *
1675      * @param str the String containing nested-string
1676      * @param open the String before nested-string
1677      * @param close the String after nested-string
1678      * @return the String that was nested, or <code>null</code>
1679      * @throws NullPointerException if open or close is <code>null</code>
1680      */
1681     public static String getNestedString( String str, String open, String close )
1682     {
1683         if ( str == null )
1684         {
1685             return null;
1686         }
1687         int start = str.indexOf( open );
1688         if ( start != -1 )
1689         {
1690             int end = str.indexOf( close, start + open.length() );
1691             if ( end != -1 )
1692             {
1693                 return str.substring( start + open.length(), end );
1694             }
1695         }
1696         return null;
1697     }
1698 
1699     /**
1700      * <p>How many times is the substring in the larger String.</p>
1701      *
1702      * <p><code>null</code> returns <code>0</code>.</p>
1703      *
1704      * @param str the String to check
1705      * @param sub the substring to count
1706      * @return the number of occurances, 0 if the String is <code>null</code>
1707      * @throws NullPointerException if sub is <code>null</code>
1708      */
1709     public static int countMatches( String str, String sub )
1710     {
1711         if ( sub.equals( "" ) )
1712         {
1713             return 0;
1714         }
1715         if ( str == null )
1716         {
1717             return 0;
1718         }
1719         int count = 0;
1720         int idx = 0;
1721         while ( ( idx = str.indexOf( sub, idx ) ) != -1 )
1722         {
1723             count++;
1724             idx += sub.length();
1725         }
1726         return count;
1727     }
1728 
1729     // Character Tests
1730     //--------------------------------------------------------------------------
1731 
1732     /**
1733      * <p>Checks if the String contains only unicode letters.</p>
1734      *
1735      * <p><code>null</code> will return <code>false</code>.
1736      * An empty String will return <code>true</code>.</p>
1737      *
1738      * @param str the String to check
1739      * @return <code>true</code> if only contains letters, and is non-null
1740      */
1741     public static boolean isAlpha( String str )
1742     {
1743         if ( str == null )
1744         {
1745             return false;
1746         }
1747         int sz = str.length();
1748         for ( int i = 0; i < sz; i++ )
1749         {
1750             if ( Character.isLetter( str.charAt( i ) ) == false )
1751             {
1752                 return false;
1753             }
1754         }
1755         return true;
1756     }
1757 
1758     /**
1759      * <p>Checks if the String contains only whitespace.</p>
1760      *
1761      * <p><code>null</code> will return <code>false</code>. An
1762      * empty String will return <code>true</code>.</p>
1763      *
1764      * @param str the String to check
1765      * @return <code>true</code> if only contains whitespace, and is non-null
1766      */
1767     public static boolean isWhitespace( String str )
1768     {
1769         if ( str == null )
1770         {
1771             return false;
1772         }
1773         int sz = str.length();
1774         for ( int i = 0; i < sz; i++ )
1775         {
1776             if ( ( Character.isWhitespace( str.charAt( i ) ) == false ) )
1777             {
1778                 return false;
1779             }
1780         }
1781         return true;
1782     }
1783 
1784     /**
1785      * <p>Checks if the String contains only unicode letters and
1786      * space (<code>' '</code>).</p>
1787      *
1788      * <p><code>null</code> will return <code>false</code>. An
1789      * empty String will return <code>true</code>.</p>
1790      *
1791      * @param str the String to check
1792      * @return <code>true</code> if only contains letters and space,
1793      *  and is non-null
1794      */
1795     public static boolean isAlphaSpace( String str )
1796     {
1797         if ( str == null )
1798         {
1799             return false;
1800         }
1801         int sz = str.length();
1802         for ( int i = 0; i < sz; i++ )
1803         {
1804             if ( ( Character.isLetter( str.charAt( i ) ) == false ) &&
1805                 ( str.charAt( i ) != ' ' ) )
1806             {
1807                 return false;
1808             }
1809         }
1810         return true;
1811     }
1812 
1813     /**
1814      * <p>Checks if the String contains only unicode letters or digits.</p>
1815      *
1816      * <p><code>null</code> will return <code>false</code>. An empty
1817      * String will return <code>true</code>.</p>
1818      *
1819      * @param str the String to check
1820      * @return <code>true</code> if only contains letters or digits,
1821      *  and is non-null
1822      */
1823     public static boolean isAlphanumeric( String str )
1824     {
1825         if ( str == null )
1826         {
1827             return false;
1828         }
1829         int sz = str.length();
1830         for ( int i = 0; i < sz; i++ )
1831         {
1832             if ( Character.isLetterOrDigit( str.charAt( i ) ) == false )
1833             {
1834                 return false;
1835             }
1836         }
1837         return true;
1838     }
1839 
1840     /**
1841      * <p>Checks if the String contains only unicode letters, digits
1842      * or space (<code>' '</code>).</p>
1843      *
1844      * <p><code>null</code> will return <code>false</code>. An empty
1845      * String will return <code>true</code>.</p>
1846      *
1847      * @param str the String to check
1848      * @return <code>true</code> if only contains letters, digits or space,
1849      *  and is non-null
1850      */
1851     public static boolean isAlphanumericSpace( String str )
1852     {
1853         if ( str == null )
1854         {
1855             return false;
1856         }
1857         int sz = str.length();
1858         for ( int i = 0; i < sz; i++ )
1859         {
1860             if ( ( Character.isLetterOrDigit( str.charAt( i ) ) == false ) &&
1861                 ( str.charAt( i ) != ' ' ) )
1862             {
1863                 return false;
1864             }
1865         }
1866         return true;
1867     }
1868 
1869     /**
1870      * <p>Checks if the String contains only unicode digits.</p>
1871      *
1872      * <p><code>null</code> will return <code>false</code>.
1873      * An empty String will return <code>true</code>.</p>
1874      *
1875      * @param str the String to check
1876      * @return <code>true</code> if only contains digits, and is non-null
1877      */
1878     public static boolean isNumeric( String str )
1879     {
1880         if ( str == null )
1881         {
1882             return false;
1883         }
1884         int sz = str.length();
1885         for ( int i = 0; i < sz; i++ )
1886         {
1887             if ( Character.isDigit( str.charAt( i ) ) == false )
1888             {
1889                 return false;
1890             }
1891         }
1892         return true;
1893     }
1894 
1895     /**
1896      * <p>Checks if the String contains only unicode digits or space
1897      * (<code>' '</code>).</p>
1898      *
1899      * <p><code>null</code> will return <code>false</code>. An empty
1900      * String will return <code>true</code>.</p>
1901      *
1902      * @param str the String to check
1903      * @return <code>true</code> if only contains digits or space,
1904      *  and is non-null
1905      */
1906     public static boolean isNumericSpace( String str )
1907     {
1908         if ( str == null )
1909         {
1910             return false;
1911         }
1912         int sz = str.length();
1913         for ( int i = 0; i < sz; i++ )
1914         {
1915             if ( ( Character.isDigit( str.charAt( i ) ) == false ) &&
1916                 ( str.charAt( i ) != ' ' ) )
1917             {
1918                 return false;
1919             }
1920         }
1921         return true;
1922     }
1923 
1924     // Defaults
1925     //--------------------------------------------------------------------------
1926 
1927     /**
1928      * <p>Returns either the passed in <code>Object</code> as a String,
1929      * or, if the <code>Object</code> is <code>null</code>, an empty
1930      * String.</p>
1931      *
1932      * @param obj the Object to check
1933      * @return the passed in Object's toString, or blank if it was
1934      *  <code>null</code>
1935      */
1936     public static String defaultString( Object obj )
1937     {
1938         return defaultString( obj, "" );
1939     }
1940 
1941     /**
1942      * <p>Returns either the passed in <code>Object</code> as a String,
1943      * or, if the <code>Object</code> is <code>null</code>, a passed
1944      * in default String.</p>
1945      *
1946      * @param obj the Object to check
1947      * @param defaultString  the default String to return if str is
1948      *  <code>null</code>
1949      * @return the passed in string, or the default if it was
1950      *  <code>null</code>
1951      */
1952     public static String defaultString( Object obj, String defaultString )
1953     {
1954         return ( obj == null ) ? defaultString : obj.toString();
1955     }
1956 
1957     // Reversing
1958     //--------------------------------------------------------------------------
1959 
1960     /**
1961      * <p>Reverse a String.</p>
1962      *
1963      * <p><code>null</code> String returns <code>null</code>.</p>
1964      *
1965      * @param str the String to reverse
1966      * @return the reversed String
1967      */
1968     public static String reverse( String str )
1969     {
1970         if ( str == null )
1971         {
1972             return null;
1973         }
1974         return new StringBuffer( str ).reverse().toString();
1975     }
1976 
1977     /**
1978      * <p>Reverses a String that is delimited by a specific character.</p>
1979      *
1980      * <p>The Strings between the delimiters are not reversed.
1981      * Thus java.lang.String becomes String.lang.java (if the delimiter
1982      * is <code>'.'</code>).</p>
1983      *
1984      * @param str the String to reverse
1985      * @param delimiter the delimiter to use
1986      * @return the reversed String
1987      */
1988     public static String reverseDelimitedString( String str, String delimiter )
1989     {
1990         // could implement manually, but simple way is to reuse other,
1991         // probably slower, methods.
1992         String[] strs = split( str, delimiter );
1993         reverseArray( strs );
1994         return join( strs, delimiter );
1995     }
1996 
1997     /**
1998      * <p>Reverses an array.</p>
1999      *
2000      * <p>TAKEN FROM CollectionsUtils.</p>
2001      *
2002      * @param array  the array to reverse
2003      */
2004     private static void reverseArray( Object[] array )
2005     {
2006         int i = 0;
2007         int j = array.length - 1;
2008         Object tmp;
2009 
2010         while ( j > i )
2011         {
2012             tmp = array[j];
2013             array[j] = array[i];
2014             array[i] = tmp;
2015             j--;
2016             i++;
2017         }
2018     }
2019 
2020     // Abbreviating
2021     //--------------------------------------------------------------------------
2022 
2023     /**
2024      * Turn "Now is the time for all good men" into "Now is the time for..."
2025      * <p>
2026      * Specifically:
2027      * <p>
2028      * If str is less than max characters long, return it.
2029      * Else abbreviate it to (substring(str, 0, max-3) + "...").
2030      * If maxWidth is less than 3, throw an IllegalArgumentException.
2031      * In no case will it return a string of length greater than maxWidth.
2032      *
2033      * @param maxWidth maximum length of result string
2034      **/
2035     public static String abbreviate( String s, int maxWidth )
2036     {
2037         return abbreviate( s, 0, maxWidth );
2038     }
2039 
2040     /**
2041      * Turn "Now is the time for all good men" into "...is the time for..."
2042      * <p>
2043      * Works like abbreviate(String, int), but allows you to specify a "left edge"
2044      * offset.  Note that this left edge is not necessarily going to be the leftmost
2045      * character in the result, or the first
2046      * character following the ellipses, but it will appear somewhere in the result.
2047      * In no case will it return a string of length greater than maxWidth.
2048      *
2049      * @param offset left edge of source string
2050      * @param maxWidth maximum length of result string
2051      **/
2052     public static String abbreviate( String s, int offset, int maxWidth )
2053     {
2054         if ( maxWidth < 4 )
2055         {
2056             throw new IllegalArgumentException( "Minimum abbreviation width is 4" );
2057         }
2058         if ( s.length() <= maxWidth )
2059         {
2060             return s;
2061         }
2062         if ( offset > s.length() )
2063         {
2064             offset = s.length();
2065         }
2066         if ( ( s.length() - offset ) < ( maxWidth - 3 ) )
2067         {
2068             offset = s.length() - ( maxWidth - 3 );
2069         }
2070         if ( offset <= 4 )
2071         {
2072             return s.substring( 0, maxWidth - 3 ) + "...";
2073         }
2074         if ( maxWidth < 7 )
2075         {
2076             throw new IllegalArgumentException( "Minimum abbreviation width with offset is 7" );
2077         }
2078         if ( ( offset + ( maxWidth - 3 ) ) < s.length() )
2079         {
2080             return "..." + abbreviate( s.substring( offset ), maxWidth - 3 );
2081         }
2082         return "..." + s.substring( s.length() - ( maxWidth - 3 ) );
2083     }
2084 
2085     // Difference
2086     //--------------------------------------------------------------------------
2087 
2088     /**
2089      * Compare two strings, and return the portion where they differ.
2090      * (More precisely, return the remainder of the second string,
2091      * starting from where it's different from the first.)
2092      * <p>
2093      * E.g. strdiff("i am a machine", "i am a robot") -&gt; "robot"
2094      *
2095      * @return the portion of s2 where it differs from s1; returns the empty string ("") if they are equal
2096      **/
2097     public static String difference( String s1, String s2 )
2098     {
2099         int at = differenceAt( s1, s2 );
2100         if ( at == -1 )
2101         {
2102             return "";
2103         }
2104         return s2.substring( at );
2105     }
2106 
2107     /**
2108      * Compare two strings, and return the index at which the strings begin to differ.
2109      * <p>
2110      * E.g. strdiff("i am a machine", "i am a robot") -&gt; 7
2111      * </p>
2112      *
2113      * @return the index where s2 and s1 begin to differ; -1 if they are equal
2114      **/
2115     public static int differenceAt( String s1, String s2 )
2116     {
2117         int i;
2118         for ( i = 0; ( i < s1.length() ) && ( i < s2.length() ); ++i )
2119         {
2120             if ( s1.charAt( i ) != s2.charAt( i ) )
2121             {
2122                 break;
2123             }
2124         }
2125         if ( ( i < s2.length() ) || ( i < s1.length() ) )
2126         {
2127             return i;
2128         }
2129         return -1;
2130     }
2131 
2132     public static String interpolate( String text, Map<?, ?> namespace )
2133     {
2134         Iterator<?> keys = namespace.keySet().iterator();
2135 
2136         while ( keys.hasNext() )
2137         {
2138             String key = keys.next().toString();
2139 
2140             Object obj = namespace.get( key );
2141 
2142             if ( obj == null )
2143             {
2144                 throw new NullPointerException( "The value of the key '" + key + "' is null." );
2145             }
2146 
2147             String value = obj.toString();
2148 
2149             text = replace( text, "${" + key + "}", value );
2150 
2151             if ( !key.contains( " " ) )
2152             {
2153                 text = replace( text, "$" + key, value );
2154             }
2155         }
2156         return text;
2157     }
2158 
2159     public static String removeAndHump( String data, String replaceThis )
2160     {
2161         String temp;
2162 
2163         StringBuilder out = new StringBuilder();
2164 
2165         temp = data;
2166 
2167         StringTokenizer st = new StringTokenizer( temp, replaceThis );
2168 
2169         while ( st.hasMoreTokens() )
2170         {
2171             String element = (String) st.nextElement();
2172 
2173             out.append( capitalizeFirstLetter( element ) );
2174         }
2175 
2176         return out.toString();
2177     }
2178 
2179     public static String capitalizeFirstLetter( String data )
2180     {
2181         char firstLetter = Character.toTitleCase( data.substring( 0, 1 ).charAt( 0 ) );
2182 
2183         String restLetters = data.substring( 1 );
2184 
2185         return firstLetter + restLetters;
2186     }
2187 
2188     public static String lowercaseFirstLetter( String data )
2189     {
2190         char firstLetter = Character.toLowerCase( data.substring( 0, 1 ).charAt( 0 ) );
2191 
2192         String restLetters = data.substring( 1 );
2193 
2194         return firstLetter + restLetters;
2195     }
2196 
2197     public static String addAndDeHump( String view )
2198     {
2199         StringBuilder sb = new StringBuilder();
2200 
2201         for ( int i = 0; i < view.length(); i++ )
2202         {
2203             if ( ( i != 0 ) && Character.isUpperCase( view.charAt( i ) ) )
2204             {
2205                 sb.append( '-' );
2206             }
2207 
2208             sb.append( view.charAt( i ) );
2209         }
2210 
2211         return sb.toString().trim().toLowerCase( Locale.ENGLISH );
2212     }
2213 
2214     /**
2215      * <p>Quote and escape a String with the given character, handling <code>null</code>.</p>
2216      *
2217      * <pre>
2218      * StringUtils.quoteAndEscape(null, *)    = null
2219      * StringUtils.quoteAndEscape("", *)      = ""
2220      * StringUtils.quoteAndEscape("abc", '"') = abc
2221      * StringUtils.quoteAndEscape("a\"bc", '"') = "a\"bc"
2222      * StringUtils.quoteAndEscape("a\"bc", '\'') = 'a\"bc'
2223      * </pre>
2224      *
2225      * @param source
2226      * @param quoteChar
2227      * @return the String quoted and escaped
2228      * @since 1.5.1
2229      * @see #quoteAndEscape(String, char, char[], char[], char, boolean)
2230      */
2231     public static String quoteAndEscape( String source,
2232                                 char quoteChar )
2233     {
2234         return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, new char[]{ ' ' }, '\\', false );
2235     }
2236 
2237     /**
2238      * <p>Quote and escape a String with the given character, handling <code>null</code>.</p>
2239      *
2240      * @param source
2241      * @param quoteChar
2242      * @param quotingTriggers
2243      * @return the String quoted and escaped
2244      * @since 1.5.1
2245      * @see #quoteAndEscape(String, char, char[], char[], char, boolean)
2246      */
2247     public static String quoteAndEscape( String source,
2248                                          char quoteChar,
2249                                          char[] quotingTriggers )
2250     {
2251         return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, quotingTriggers, '\\', false );
2252     }
2253 
2254     /**
2255      * @param source
2256      * @param quoteChar
2257      * @param escapedChars
2258      * @param escapeChar
2259      * @param force
2260      * @return the String quoted and escaped
2261      * @since 1.5.1
2262      * @see #quoteAndEscape(String, char, char[], char[], char, boolean)
2263      */
2264     public static String quoteAndEscape( String source,
2265                                 char quoteChar,
2266                                 final char[] escapedChars,
2267                                 char escapeChar,
2268                                 boolean force )
2269     {
2270         return quoteAndEscape( source, quoteChar, escapedChars, new char[]{ ' ' }, escapeChar, force );
2271     }
2272 
2273     /**
2274      * @param source
2275      * @param quoteChar
2276      * @param escapedChars
2277      * @param quotingTriggers
2278      * @param escapeChar
2279      * @param force
2280      * @return the String quoted and escaped
2281      * @since 1.5.1
2282      */
2283     public static String quoteAndEscape( String source,
2284                                 char quoteChar,
2285                                 final char[] escapedChars,
2286                                 final char[] quotingTriggers,
2287                                 char escapeChar,
2288                                 boolean force )
2289     {
2290         return quoteAndEscape(source, quoteChar, escapedChars, quotingTriggers, escapeChar + "%s", force);
2291     }
2292 
2293     /**
2294      * @param source
2295      * @param quoteChar
2296      * @param escapedChars
2297      * @param quotingTriggers
2298      * @param escapePattern
2299      * @param force
2300      * @return the String quoted and escaped
2301      * @since 3.0.4
2302      */
2303     public static String quoteAndEscape(String source,
2304                                         char quoteChar,
2305                                         final char[] escapedChars,
2306                                         final char[] quotingTriggers,
2307                                         String escapePattern,
2308                                         boolean force) {
2309         if ( source == null )
2310         {
2311             return null;
2312         }
2313 
2314         if ( !force && source.startsWith( Character.toString( quoteChar ) )
2315                 && source.endsWith( Character.toString( quoteChar ) ) )
2316         {
2317             return source;
2318         }
2319 
2320         String escaped = escape( source, escapedChars, escapePattern );
2321 
2322         boolean quote = false;
2323         if ( force )
2324         {
2325             quote = true;
2326         }
2327         else if ( !escaped.equals( source ) )
2328         {
2329             quote = true;
2330         }
2331         else
2332         {
2333             for ( char quotingTrigger : quotingTriggers )
2334             {
2335                 if ( escaped.indexOf( quotingTrigger ) > -1 )
2336                 {
2337                     quote = true;
2338                     break;
2339                 }
2340             }
2341         }
2342 
2343         if ( quote )
2344         {
2345             return quoteChar + escaped + quoteChar;
2346         }
2347 
2348         return escaped;
2349     }
2350 
2351     /**
2352      * @param source
2353      * @param escapedChars
2354      * @param escapeChar
2355      * @return the String escaped
2356      * @since 1.5.1
2357      */
2358     public static String escape( String source, final char[] escapedChars, char escapeChar )
2359     {
2360         return escape(source, escapedChars, escapeChar + "%s");
2361     }
2362 
2363     /**
2364      * @param source
2365      * @param escapedChars
2366      * @param escapePattern
2367      * @return the String escaped
2368      * @since 3.0.4
2369      */
2370     public static String escape( String source, final char[] escapedChars, String escapePattern )
2371     {
2372         if ( source == null )
2373         {
2374             return null;
2375         }
2376 
2377         char[] eqc = new char[ escapedChars.length ];
2378         System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length );
2379         Arrays.sort( eqc );
2380 
2381         StringBuilder buffer = new StringBuilder( source.length() );
2382 
2383         for ( int i = 0; i < source.length(); i++ )
2384         {
2385             final char c = source.charAt( i );
2386             int result = Arrays.binarySearch( eqc, c );
2387 
2388             if ( result > -1 )
2389             {
2390                 buffer.append( String.format(escapePattern, c) );
2391             }
2392             else
2393             {
2394                 buffer.append( c );
2395             }
2396         }
2397 
2398         return buffer.toString();
2399     }
2400 
2401     /**
2402      * Remove all duplicate whitespace characters and line terminators are replaced with a single
2403      * space.
2404      *
2405      * @param s a not null String
2406      * @return a string with unique whitespace.
2407      * @since 1.5.7
2408      */
2409     public static String removeDuplicateWhitespace( String s )
2410     {
2411         StringBuilder result = new StringBuilder( );
2412         int length = s.length();
2413         boolean isPreviousWhiteSpace = false;
2414         for (int i = 0; i < length; i++){
2415             char c = s.charAt( i );
2416             boolean thisCharWhiteSpace = Character.isWhitespace( c );
2417             if (!(isPreviousWhiteSpace && thisCharWhiteSpace)){
2418                 result.append( c );
2419             }
2420             isPreviousWhiteSpace = thisCharWhiteSpace;
2421         }
2422         return result.toString();
2423     }
2424 
2425     /**
2426      * Parses the given String and replaces all occurrences of
2427      * '\n', '\r' and '\r\n' with the system line separator.
2428      *
2429      * @param s a not null String
2430      * @return a String that contains only System line separators.
2431      * @see #unifyLineSeparators(String, String)
2432      * @since 1.5.7
2433      */
2434      public static String unifyLineSeparators( String s )
2435      {
2436          return unifyLineSeparators( s, System.getProperty( "line.separator" ) );
2437      }
2438 
2439     /**
2440      * Parses the given String and replaces all occurrences of
2441      * '\n', '\r' and '\r\n' with the system line separator.
2442      *
2443      * @param s a not null String
2444      * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator.
2445      * @return a String that contains only System line separators.
2446      * @throws IllegalArgumentException if ls is not '\n', '\r' and '\r\n' characters.
2447      * @since 1.5.7
2448      */
2449      public static String unifyLineSeparators( String s, String ls )
2450      {
2451         if ( s == null )
2452         {
2453             return null;
2454         }
2455 
2456         if ( ls == null )
2457         {
2458             ls = System.getProperty( "line.separator" );
2459         }
2460 
2461         if ( !( ls.equals( "\n" ) || ls.equals( "\r" ) || ls.equals( "\r\n" ) ) )
2462         {
2463             throw new IllegalArgumentException( "Requested line separator is invalid." );
2464         }
2465 
2466         int length = s.length();
2467 
2468         StringBuilder buffer = new StringBuilder( length );
2469         for ( int i = 0; i < length; i++ )
2470         {
2471             if ( s.charAt( i ) == '\r' )
2472             {
2473                 if ( ( i + 1 ) < length && s.charAt( i + 1 ) == '\n' )
2474                 {
2475                     i++;
2476                 }
2477 
2478                 buffer.append( ls );
2479             }
2480             else if ( s.charAt( i ) == '\n' )
2481             {
2482                 buffer.append( ls );
2483             }
2484             else
2485             {
2486                 buffer.append( s.charAt( i ) );
2487             }
2488         }
2489 
2490         return buffer.toString();
2491     }
2492 
2493     /**
2494      * <p>Checks if String contains a search character, handling <code>null</code>.
2495      * This method uses {@link String#indexOf(int)}.</p>
2496      *
2497      * <p>A <code>null</code> or empty ("") String will return <code>false</code>.</p>
2498      *
2499      * <pre>
2500      * StringUtils.contains(null, *)    = false
2501      * StringUtils.contains("", *)      = false
2502      * StringUtils.contains("abc", 'a') = true
2503      * StringUtils.contains("abc", 'z') = false
2504      * </pre>
2505      *
2506      * @param str  the String to check, may be null
2507      * @param searchChar  the character to find
2508      * @return true if the String contains the search character,
2509      *  false if not or <code>null</code> string input
2510      * @since 1.5.7
2511      */
2512     public static boolean contains( String str, char searchChar )
2513     {
2514         if ( isEmpty( str ) )
2515         {
2516             return false;
2517         }
2518         return str.indexOf( searchChar ) >= 0;
2519     }
2520 
2521     /**
2522      * <p>Checks if String contains a search String, handling <code>null</code>.
2523      * This method uses {@link String#indexOf(int)}.</p>
2524      *
2525      * <p>A <code>null</code> String will return <code>false</code>.</p>
2526      *
2527      * <pre>
2528      * StringUtils.contains(null, *)     = false
2529      * StringUtils.contains(*, null)     = false
2530      * StringUtils.contains("", "")      = true
2531      * StringUtils.contains("abc", "")   = true
2532      * StringUtils.contains("abc", "a")  = true
2533      * StringUtils.contains("abc", "z")  = false
2534      * </pre>
2535      *
2536      * @param str  the String to check, may be null
2537      * @param searchStr  the String to find, may be null
2538      * @return true if the String contains the search String,
2539      *  false if not or <code>null</code> string input
2540      * @since 1.5.7
2541      */
2542     public static boolean contains( String str, String searchStr )
2543     {
2544         if ( str == null || searchStr == null )
2545         {
2546             return false;
2547         }
2548         return str.contains( searchStr );
2549     }
2550 }