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