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