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