001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.lang3;
018
019 import java.lang.reflect.InvocationTargetException;
020 import java.lang.reflect.Method;
021 import java.util.ArrayList;
022 import java.util.Arrays;
023 import java.util.Iterator;
024 import java.util.List;
025 import java.util.Locale;
026 import java.util.regex.Pattern;
027
028 /**
029 * <p>Operations on {@link java.lang.String} that are
030 * {@code null} safe.</p>
031 *
032 * <ul>
033 * <li><b>IsEmpty/IsBlank</b>
034 * - checks if a String contains text</li>
035 * <li><b>Trim/Strip</b>
036 * - removes leading and trailing whitespace</li>
037 * <li><b>Equals</b>
038 * - compares two strings null-safe</li>
039 * <li><b>startsWith</b>
040 * - check if a String starts with a prefix null-safe</li>
041 * <li><b>endsWith</b>
042 * - check if a String ends with a suffix null-safe</li>
043 * <li><b>IndexOf/LastIndexOf/Contains</b>
044 * - null-safe index-of checks
045 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
046 * - index-of any of a set of Strings</li>
047 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
048 * - does String contains only/none/any of these characters</li>
049 * <li><b>Substring/Left/Right/Mid</b>
050 * - null-safe substring extractions</li>
051 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
052 * - substring extraction relative to other strings</li>
053 * <li><b>Split/Join</b>
054 * - splits a String into an array of substrings and vice versa</li>
055 * <li><b>Remove/Delete</b>
056 * - removes part of a String</li>
057 * <li><b>Replace/Overlay</b>
058 * - Searches a String and replaces one String with another</li>
059 * <li><b>Chomp/Chop</b>
060 * - removes the last part of a String</li>
061 * <li><b>LeftPad/RightPad/Center/Repeat</b>
062 * - pads a String</li>
063 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
064 * - changes the case of a String</li>
065 * <li><b>CountMatches</b>
066 * - counts the number of occurrences of one String in another</li>
067 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
068 * - checks the characters in a String</li>
069 * <li><b>DefaultString</b>
070 * - protects against a null input String</li>
071 * <li><b>Reverse/ReverseDelimited</b>
072 * - reverses a String</li>
073 * <li><b>Abbreviate</b>
074 * - abbreviates a string using ellipsis</li>
075 * <li><b>Difference</b>
076 * - compares Strings and reports on their differences</li>
077 * <li><b>LevenshteinDistance</b>
078 * - the number of changes needed to change one String into another</li>
079 * </ul>
080 *
081 * <p>The {@code StringUtils} class defines certain words related to
082 * String handling.</p>
083 *
084 * <ul>
085 * <li>null - {@code null}</li>
086 * <li>empty - a zero-length string ({@code ""})</li>
087 * <li>space - the space character ({@code ' '}, char 32)</li>
088 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
089 * <li>trim - the characters <= 32 as in {@link String#trim()}</li>
090 * </ul>
091 *
092 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
093 * That is to say that a {@code null} input will return {@code null}.
094 * Where a {@code boolean} or {@code int} is being returned
095 * details vary by method.</p>
096 *
097 * <p>A side effect of the {@code null} handling is that a
098 * {@code NullPointerException} should be considered a bug in
099 * {@code StringUtils}.</p>
100 *
101 * <p>Methods in this class give sample code to explain their operation.
102 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
103 *
104 * <p>#ThreadSafe#</p>
105 * @see java.lang.String
106 * @since 1.0
107 * @version $Id: StringUtils.java 1153241 2011-08-02 18:49:52Z ggregory $
108 */
109 //@Immutable
110 public class StringUtils {
111 // Performance testing notes (JDK 1.4, Jul03, scolebourne)
112 // Whitespace:
113 // Character.isWhitespace() is faster than WHITESPACE.indexOf()
114 // where WHITESPACE is a string of all whitespace characters
115 //
116 // Character access:
117 // String.charAt(n) versus toCharArray(), then array[n]
118 // String.charAt(n) is about 15% worse for a 10K string
119 // They are about equal for a length 50 string
120 // String.charAt(n) is about 4 times better for a length 3 string
121 // String.charAt(n) is best bet overall
122 //
123 // Append:
124 // String.concat about twice as fast as StringBuffer.append
125 // (not sure who tested this)
126
127 /**
128 * The empty String {@code ""}.
129 * @since 2.0
130 */
131 public static final String EMPTY = "";
132
133 /**
134 * Represents a failed index search.
135 * @since 2.1
136 */
137 public static final int INDEX_NOT_FOUND = -1;
138
139 /**
140 * <p>The maximum size to which the padding constant(s) can expand.</p>
141 */
142 private static final int PAD_LIMIT = 8192;
143
144 /**
145 * A regex pattern for recognizing blocks of whitespace characters.
146 */
147 private static final Pattern WHITESPACE_BLOCK = Pattern.compile("\\s+");
148
149 /**
150 * <p>{@code StringUtils} instances should NOT be constructed in
151 * standard programming. Instead, the class should be used as
152 * {@code StringUtils.trim(" foo ");}.</p>
153 *
154 * <p>This constructor is public to permit tools that require a JavaBean
155 * instance to operate.</p>
156 */
157 public StringUtils() {
158 super();
159 }
160
161 // Empty checks
162 //-----------------------------------------------------------------------
163 /**
164 * <p>Checks if a CharSequence is empty ("") or null.</p>
165 *
166 * <pre>
167 * StringUtils.isEmpty(null) = true
168 * StringUtils.isEmpty("") = true
169 * StringUtils.isEmpty(" ") = false
170 * StringUtils.isEmpty("bob") = false
171 * StringUtils.isEmpty(" bob ") = false
172 * </pre>
173 *
174 * <p>NOTE: This method changed in Lang version 2.0.
175 * It no longer trims the CharSequence.
176 * That functionality is available in isBlank().</p>
177 *
178 * @param cs the CharSequence to check, may be null
179 * @return {@code true} if the CharSequence is empty or null
180 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
181 */
182 public static boolean isEmpty(CharSequence cs) {
183 return cs == null || cs.length() == 0;
184 }
185
186 /**
187 * <p>Checks if a CharSequence is not empty ("") and not null.</p>
188 *
189 * <pre>
190 * StringUtils.isNotEmpty(null) = false
191 * StringUtils.isNotEmpty("") = false
192 * StringUtils.isNotEmpty(" ") = true
193 * StringUtils.isNotEmpty("bob") = true
194 * StringUtils.isNotEmpty(" bob ") = true
195 * </pre>
196 *
197 * @param cs the CharSequence to check, may be null
198 * @return {@code true} if the CharSequence is not empty and not null
199 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
200 */
201 public static boolean isNotEmpty(CharSequence cs) {
202 return !StringUtils.isEmpty(cs);
203 }
204
205 /**
206 * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p>
207 *
208 * <pre>
209 * StringUtils.isBlank(null) = true
210 * StringUtils.isBlank("") = true
211 * StringUtils.isBlank(" ") = true
212 * StringUtils.isBlank("bob") = false
213 * StringUtils.isBlank(" bob ") = false
214 * </pre>
215 *
216 * @param cs the CharSequence to check, may be null
217 * @return {@code true} if the CharSequence is null, empty or whitespace
218 * @since 2.0
219 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
220 */
221 public static boolean isBlank(CharSequence cs) {
222 int strLen;
223 if (cs == null || (strLen = cs.length()) == 0) {
224 return true;
225 }
226 for (int i = 0; i < strLen; i++) {
227 if ((Character.isWhitespace(cs.charAt(i)) == false)) {
228 return false;
229 }
230 }
231 return true;
232 }
233
234 /**
235 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
236 *
237 * <pre>
238 * StringUtils.isNotBlank(null) = false
239 * StringUtils.isNotBlank("") = false
240 * StringUtils.isNotBlank(" ") = false
241 * StringUtils.isNotBlank("bob") = true
242 * StringUtils.isNotBlank(" bob ") = true
243 * </pre>
244 *
245 * @param cs the CharSequence to check, may be null
246 * @return {@code true} if the CharSequence is
247 * not empty and not null and not whitespace
248 * @since 2.0
249 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
250 */
251 public static boolean isNotBlank(CharSequence cs) {
252 return !StringUtils.isBlank(cs);
253 }
254
255 // Trim
256 //-----------------------------------------------------------------------
257 /**
258 * <p>Removes control characters (char <= 32) from both
259 * ends of this String, handling {@code null} by returning
260 * {@code null}.</p>
261 *
262 * <p>The String is trimmed using {@link String#trim()}.
263 * Trim removes start and end characters <= 32.
264 * To strip whitespace use {@link #strip(String)}.</p>
265 *
266 * <p>To trim your choice of characters, use the
267 * {@link #strip(String, String)} methods.</p>
268 *
269 * <pre>
270 * StringUtils.trim(null) = null
271 * StringUtils.trim("") = ""
272 * StringUtils.trim(" ") = ""
273 * StringUtils.trim("abc") = "abc"
274 * StringUtils.trim(" abc ") = "abc"
275 * </pre>
276 *
277 * @param str the String to be trimmed, may be null
278 * @return the trimmed string, {@code null} if null String input
279 */
280 public static String trim(String str) {
281 return str == null ? null : str.trim();
282 }
283
284 /**
285 * <p>Removes control characters (char <= 32) from both
286 * ends of this String returning {@code null} if the String is
287 * empty ("") after the trim or if it is {@code null}.
288 *
289 * <p>The String is trimmed using {@link String#trim()}.
290 * Trim removes start and end characters <= 32.
291 * To strip whitespace use {@link #stripToNull(String)}.</p>
292 *
293 * <pre>
294 * StringUtils.trimToNull(null) = null
295 * StringUtils.trimToNull("") = null
296 * StringUtils.trimToNull(" ") = null
297 * StringUtils.trimToNull("abc") = "abc"
298 * StringUtils.trimToNull(" abc ") = "abc"
299 * </pre>
300 *
301 * @param str the String to be trimmed, may be null
302 * @return the trimmed String,
303 * {@code null} if only chars <= 32, empty or null String input
304 * @since 2.0
305 */
306 public static String trimToNull(String str) {
307 String ts = trim(str);
308 return isEmpty(ts) ? null : ts;
309 }
310
311 /**
312 * <p>Removes control characters (char <= 32) from both
313 * ends of this String returning an empty String ("") if the String
314 * is empty ("") after the trim or if it is {@code null}.
315 *
316 * <p>The String is trimmed using {@link String#trim()}.
317 * Trim removes start and end characters <= 32.
318 * To strip whitespace use {@link #stripToEmpty(String)}.</p>
319 *
320 * <pre>
321 * StringUtils.trimToEmpty(null) = ""
322 * StringUtils.trimToEmpty("") = ""
323 * StringUtils.trimToEmpty(" ") = ""
324 * StringUtils.trimToEmpty("abc") = "abc"
325 * StringUtils.trimToEmpty(" abc ") = "abc"
326 * </pre>
327 *
328 * @param str the String to be trimmed, may be null
329 * @return the trimmed String, or an empty String if {@code null} input
330 * @since 2.0
331 */
332 public static String trimToEmpty(String str) {
333 return str == null ? EMPTY : str.trim();
334 }
335
336 // Stripping
337 //-----------------------------------------------------------------------
338 /**
339 * <p>Strips whitespace from the start and end of a String.</p>
340 *
341 * <p>This is similar to {@link #trim(String)} but removes whitespace.
342 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
343 *
344 * <p>A {@code null} input String returns {@code null}.</p>
345 *
346 * <pre>
347 * StringUtils.strip(null) = null
348 * StringUtils.strip("") = ""
349 * StringUtils.strip(" ") = ""
350 * StringUtils.strip("abc") = "abc"
351 * StringUtils.strip(" abc") = "abc"
352 * StringUtils.strip("abc ") = "abc"
353 * StringUtils.strip(" abc ") = "abc"
354 * StringUtils.strip(" ab c ") = "ab c"
355 * </pre>
356 *
357 * @param str the String to remove whitespace from, may be null
358 * @return the stripped String, {@code null} if null String input
359 */
360 public static String strip(String str) {
361 return strip(str, null);
362 }
363
364 /**
365 * <p>Strips whitespace from the start and end of a String returning
366 * {@code null} if the String is empty ("") after the strip.</p>
367 *
368 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
369 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
370 *
371 * <pre>
372 * StringUtils.stripToNull(null) = null
373 * StringUtils.stripToNull("") = null
374 * StringUtils.stripToNull(" ") = null
375 * StringUtils.stripToNull("abc") = "abc"
376 * StringUtils.stripToNull(" abc") = "abc"
377 * StringUtils.stripToNull("abc ") = "abc"
378 * StringUtils.stripToNull(" abc ") = "abc"
379 * StringUtils.stripToNull(" ab c ") = "ab c"
380 * </pre>
381 *
382 * @param str the String to be stripped, may be null
383 * @return the stripped String,
384 * {@code null} if whitespace, empty or null String input
385 * @since 2.0
386 */
387 public static String stripToNull(String str) {
388 if (str == null) {
389 return null;
390 }
391 str = strip(str, null);
392 return str.length() == 0 ? null : str;
393 }
394
395 /**
396 * <p>Strips whitespace from the start and end of a String returning
397 * an empty String if {@code null} input.</p>
398 *
399 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
400 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
401 *
402 * <pre>
403 * StringUtils.stripToEmpty(null) = ""
404 * StringUtils.stripToEmpty("") = ""
405 * StringUtils.stripToEmpty(" ") = ""
406 * StringUtils.stripToEmpty("abc") = "abc"
407 * StringUtils.stripToEmpty(" abc") = "abc"
408 * StringUtils.stripToEmpty("abc ") = "abc"
409 * StringUtils.stripToEmpty(" abc ") = "abc"
410 * StringUtils.stripToEmpty(" ab c ") = "ab c"
411 * </pre>
412 *
413 * @param str the String to be stripped, may be null
414 * @return the trimmed String, or an empty String if {@code null} input
415 * @since 2.0
416 */
417 public static String stripToEmpty(String str) {
418 return str == null ? EMPTY : strip(str, null);
419 }
420
421 /**
422 * <p>Strips any of a set of characters from the start and end of a String.
423 * This is similar to {@link String#trim()} but allows the characters
424 * to be stripped to be controlled.</p>
425 *
426 * <p>A {@code null} input String returns {@code null}.
427 * An empty string ("") input returns the empty string.</p>
428 *
429 * <p>If the stripChars String is {@code null}, whitespace is
430 * stripped as defined by {@link Character#isWhitespace(char)}.
431 * Alternatively use {@link #strip(String)}.</p>
432 *
433 * <pre>
434 * StringUtils.strip(null, *) = null
435 * StringUtils.strip("", *) = ""
436 * StringUtils.strip("abc", null) = "abc"
437 * StringUtils.strip(" abc", null) = "abc"
438 * StringUtils.strip("abc ", null) = "abc"
439 * StringUtils.strip(" abc ", null) = "abc"
440 * StringUtils.strip(" abcyx", "xyz") = " abc"
441 * </pre>
442 *
443 * @param str the String to remove characters from, may be null
444 * @param stripChars the characters to remove, null treated as whitespace
445 * @return the stripped String, {@code null} if null String input
446 */
447 public static String strip(String str, String stripChars) {
448 if (isEmpty(str)) {
449 return str;
450 }
451 str = stripStart(str, stripChars);
452 return stripEnd(str, stripChars);
453 }
454
455 /**
456 * <p>Strips any of a set of characters from the start of a String.</p>
457 *
458 * <p>A {@code null} input String returns {@code null}.
459 * An empty string ("") input returns the empty string.</p>
460 *
461 * <p>If the stripChars String is {@code null}, whitespace is
462 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
463 *
464 * <pre>
465 * StringUtils.stripStart(null, *) = null
466 * StringUtils.stripStart("", *) = ""
467 * StringUtils.stripStart("abc", "") = "abc"
468 * StringUtils.stripStart("abc", null) = "abc"
469 * StringUtils.stripStart(" abc", null) = "abc"
470 * StringUtils.stripStart("abc ", null) = "abc "
471 * StringUtils.stripStart(" abc ", null) = "abc "
472 * StringUtils.stripStart("yxabc ", "xyz") = "abc "
473 * </pre>
474 *
475 * @param str the String to remove characters from, may be null
476 * @param stripChars the characters to remove, null treated as whitespace
477 * @return the stripped String, {@code null} if null String input
478 */
479 public static String stripStart(String str, String stripChars) {
480 int strLen;
481 if (str == null || (strLen = str.length()) == 0) {
482 return str;
483 }
484 int start = 0;
485 if (stripChars == null) {
486 while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
487 start++;
488 }
489 } else if (stripChars.length() == 0) {
490 return str;
491 } else {
492 while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
493 start++;
494 }
495 }
496 return str.substring(start);
497 }
498
499 /**
500 * <p>Strips any of a set of characters from the end of a String.</p>
501 *
502 * <p>A {@code null} input String returns {@code null}.
503 * An empty string ("") input returns the empty string.</p>
504 *
505 * <p>If the stripChars String is {@code null}, whitespace is
506 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
507 *
508 * <pre>
509 * StringUtils.stripEnd(null, *) = null
510 * StringUtils.stripEnd("", *) = ""
511 * StringUtils.stripEnd("abc", "") = "abc"
512 * StringUtils.stripEnd("abc", null) = "abc"
513 * StringUtils.stripEnd(" abc", null) = " abc"
514 * StringUtils.stripEnd("abc ", null) = "abc"
515 * StringUtils.stripEnd(" abc ", null) = " abc"
516 * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
517 * StringUtils.stripEnd("120.00", ".0") = "12"
518 * </pre>
519 *
520 * @param str the String to remove characters from, may be null
521 * @param stripChars the set of characters to remove, null treated as whitespace
522 * @return the stripped String, {@code null} if null String input
523 */
524 public static String stripEnd(String str, String stripChars) {
525 int end;
526 if (str == null || (end = str.length()) == 0) {
527 return str;
528 }
529
530 if (stripChars == null) {
531 while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
532 end--;
533 }
534 } else if (stripChars.length() == 0) {
535 return str;
536 } else {
537 while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
538 end--;
539 }
540 }
541 return str.substring(0, end);
542 }
543
544 // StripAll
545 //-----------------------------------------------------------------------
546 /**
547 * <p>Strips whitespace from the start and end of every String in an array.
548 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
549 *
550 * <p>A new array is returned each time, except for length zero.
551 * A {@code null} array will return {@code null}.
552 * An empty array will return itself.
553 * A {@code null} array entry will be ignored.</p>
554 *
555 * <pre>
556 * StringUtils.stripAll(null) = null
557 * StringUtils.stripAll([]) = []
558 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"]
559 * StringUtils.stripAll(["abc ", null]) = ["abc", null]
560 * </pre>
561 *
562 * @param strs the array to remove whitespace from, may be null
563 * @return the stripped Strings, {@code null} if null array input
564 */
565 public static String[] stripAll(String... strs) {
566 return stripAll(strs, null);
567 }
568
569 /**
570 * <p>Strips any of a set of characters from the start and end of every
571 * String in an array.</p>
572 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
573 *
574 * <p>A new array is returned each time, except for length zero.
575 * A {@code null} array will return {@code null}.
576 * An empty array will return itself.
577 * A {@code null} array entry will be ignored.
578 * A {@code null} stripChars will strip whitespace as defined by
579 * {@link Character#isWhitespace(char)}.</p>
580 *
581 * <pre>
582 * StringUtils.stripAll(null, *) = null
583 * StringUtils.stripAll([], *) = []
584 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"]
585 * StringUtils.stripAll(["abc ", null], null) = ["abc", null]
586 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null]
587 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null]
588 * </pre>
589 *
590 * @param strs the array to remove characters from, may be null
591 * @param stripChars the characters to remove, null treated as whitespace
592 * @return the stripped Strings, {@code null} if null array input
593 */
594 public static String[] stripAll(String[] strs, String stripChars) {
595 int strsLen;
596 if (strs == null || (strsLen = strs.length) == 0) {
597 return strs;
598 }
599 String[] newArr = new String[strsLen];
600 for (int i = 0; i < strsLen; i++) {
601 newArr[i] = strip(strs[i], stripChars);
602 }
603 return newArr;
604 }
605
606 /**
607 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
608 * <p>For instance, 'à' will be replaced by 'a'.</p>
609 * <p>Note that ligatures will be left as is.</p>
610 *
611 * <p>This method will use the first available implementation of:
612 * Java 6's {@link java.text.Normalizer}, Java 1.3–1.5's {@code sun.text.Normalizer}</p>
613 *
614 * <pre>
615 * StringUtils.stripAccents(null) = null
616 * StringUtils.stripAccents("") = ""
617 * StringUtils.stripAccents("control") = "control"
618 * StringUtils.stripAccents("éclair") = "eclair"
619 * </pre>
620 *
621 * @param input String to be stripped
622 * @return input text with diacritics removed
623 *
624 * @since 3.0
625 */
626 // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
627 public static String stripAccents(String input) {
628 if(input == null) {
629 return null;
630 }
631 try {
632 String result = null;
633 if (java6Available) {
634 result = removeAccentsJava6(input);
635 } else if (sunAvailable) {
636 result = removeAccentsSUN(input);
637 } else {
638 throw new UnsupportedOperationException(
639 "The stripAccents(CharSequence) method requires at least Java 1.6 or a Sun JVM");
640 }
641 // Note that none of the above methods correctly remove ligatures...
642 return result;
643 } catch(IllegalArgumentException iae) {
644 throw new RuntimeException("IllegalArgumentException occurred", iae);
645 } catch(IllegalAccessException iae) {
646 throw new RuntimeException("IllegalAccessException occurred", iae);
647 } catch(InvocationTargetException ite) {
648 throw new RuntimeException("InvocationTargetException occurred", ite);
649 } catch(SecurityException se) {
650 throw new RuntimeException("SecurityException occurred", se);
651 }
652 }
653
654 /**
655 * Use {@code java.text.Normalizer#normalize(CharSequence, Normalizer.Form)}
656 * (but be careful, this class exists in Java 1.3, with an entirely different meaning!)
657 *
658 * @param text the text to be processed
659 * @return the processed string
660 * @throws IllegalAccessException may be thrown by a reflection call
661 * @throws InvocationTargetException if a reflection call throws an exception
662 * @throws IllegalStateException if the {@code Normalizer} class is not available
663 */
664 private static String removeAccentsJava6(CharSequence text)
665 throws IllegalAccessException, InvocationTargetException {
666 /*
667 String decomposed = java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
668 return java6Pattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
669 */
670 if (!java6Available || java6NormalizerFormNFD == null) {
671 throw new IllegalStateException("java.text.Normalizer is not available");
672 }
673 String result;
674 result = (String) java6NormalizeMethod.invoke(null, new Object[] {text, java6NormalizerFormNFD});
675 result = java6Pattern.matcher(result).replaceAll("");//$NON-NLS-1$
676 return result;
677 }
678
679 /**
680 * Use {@code sun.text.Normalizer#decompose(String, boolean, int)}
681 *
682 * @param text the text to be processed
683 * @return the processed string
684 * @throws IllegalAccessException may be thrown by a reflection call
685 * @throws InvocationTargetException if a reflection call throws an exception
686 * @throws IllegalStateException if the {@code Normalizer} class is not available
687 */
688 private static String removeAccentsSUN(CharSequence text)
689 throws IllegalAccessException, InvocationTargetException {
690 /*
691 String decomposed = sun.text.Normalizer.decompose(text, false, 0);
692 return sunPattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
693 */
694 if (! sunAvailable) {
695 throw new IllegalStateException("sun.text.Normalizer is not available");
696 }
697 String result;
698 result = (String) sunDecomposeMethod.invoke(null, new Object[] {text, Boolean.FALSE, Integer.valueOf(0)});
699 result = sunPattern.matcher(result).replaceAll("");//$NON-NLS-1$
700 return result;
701 }
702
703 // SUN internal, Java 1.3 -> Java 5
704 private static boolean sunAvailable = false;
705 private static Method sunDecomposeMethod = null;
706 private static final Pattern sunPattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
707 // Java 6+
708 private static boolean java6Available = false;
709 private static Method java6NormalizeMethod = null;
710 private static Object java6NormalizerFormNFD = null;
711 private static final Pattern java6Pattern = sunPattern;
712
713 static {
714 try {
715 // java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
716 // Be careful not to get Java 1.3 java.text.Normalizer!
717 Class<?> normalizerFormClass = Thread.currentThread().getContextClassLoader()
718 .loadClass("java.text.Normalizer$Form");//$NON-NLS-1$
719 java6NormalizerFormNFD = normalizerFormClass.getField("NFD").get(null);//$NON-NLS-1$
720 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader()
721 .loadClass("java.text.Normalizer");//$NON-NLS-1$
722 java6NormalizeMethod = normalizerClass.getMethod("normalize",
723 new Class[] {CharSequence.class, normalizerFormClass});//$NON-NLS-1$
724 java6Available = true;
725 } catch (ClassNotFoundException e) {
726 java6Available = false;
727 } catch (NoSuchFieldException e) {
728 java6Available = false;
729 } catch (IllegalAccessException e) {
730 java6Available = false;
731 } catch (NoSuchMethodException e) {
732 java6Available = false;
733 }
734
735 try {
736 // sun.text.Normalizer.decompose(text, false, 0);
737 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader()
738 .loadClass("sun.text.Normalizer");//$NON-NLS-1$
739 sunDecomposeMethod = normalizerClass.getMethod("decompose",
740 new Class[] {String.class, Boolean.TYPE, Integer.TYPE});//$NON-NLS-1$
741 sunAvailable = true;
742 } catch (ClassNotFoundException e) {
743 sunAvailable = false;
744 } catch (NoSuchMethodException e) {
745 sunAvailable = false;
746 }
747 }
748
749 // Equals
750 //-----------------------------------------------------------------------
751 /**
752 * <p>Compares two CharSequences, returning {@code true} if they are equal.</p>
753 *
754 * <p>{@code null}s are handled without exceptions. Two {@code null}
755 * references are considered to be equal. The comparison is case sensitive.</p>
756 *
757 * <pre>
758 * StringUtils.equals(null, null) = true
759 * StringUtils.equals(null, "abc") = false
760 * StringUtils.equals("abc", null) = false
761 * StringUtils.equals("abc", "abc") = true
762 * StringUtils.equals("abc", "ABC") = false
763 * </pre>
764 *
765 * @see java.lang.String#equals(Object)
766 * @param cs1 the first CharSequence, may be null
767 * @param cs2 the second CharSequence, may be null
768 * @return {@code true} if the CharSequences are equal, case sensitive, or
769 * both {@code null}
770 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
771 */
772 public static boolean equals(CharSequence cs1, CharSequence cs2) {
773 return cs1 == null ? cs2 == null : cs1.equals(cs2);
774 }
775
776 /**
777 * <p>Compares two CharSequences, returning {@code true} if they are equal ignoring
778 * the case.</p>
779 *
780 * <p>{@code null}s are handled without exceptions. Two {@code null}
781 * references are considered equal. Comparison is case insensitive.</p>
782 *
783 * <pre>
784 * StringUtils.equalsIgnoreCase(null, null) = true
785 * StringUtils.equalsIgnoreCase(null, "abc") = false
786 * StringUtils.equalsIgnoreCase("abc", null) = false
787 * StringUtils.equalsIgnoreCase("abc", "abc") = true
788 * StringUtils.equalsIgnoreCase("abc", "ABC") = true
789 * </pre>
790 *
791 * @param str1 the first CharSequence, may be null
792 * @param str2 the second CharSequence, may be null
793 * @return {@code true} if the CharSequence are equal, case insensitive, or
794 * both {@code null}
795 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
796 */
797 public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
798 if (str1 == null || str2 == null) {
799 return str1 == str2;
800 } else {
801 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, Math.max(str1.length(), str2.length()));
802 }
803 }
804
805 // IndexOf
806 //-----------------------------------------------------------------------
807 /**
808 * <p>Finds the first index within a CharSequence, handling {@code null}.
809 * This method uses {@link String#indexOf(int, int)} if possible.</p>
810 *
811 * <p>A {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.</p>
812 *
813 * <pre>
814 * StringUtils.indexOf(null, *) = -1
815 * StringUtils.indexOf("", *) = -1
816 * StringUtils.indexOf("aabaabaa", 'a') = 0
817 * StringUtils.indexOf("aabaabaa", 'b') = 2
818 * </pre>
819 *
820 * @param seq the CharSequence to check, may be null
821 * @param searchChar the character to find
822 * @return the first index of the search character,
823 * -1 if no match or {@code null} string input
824 * @since 2.0
825 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
826 */
827 public static int indexOf(CharSequence seq, int searchChar) {
828 if (isEmpty(seq)) {
829 return INDEX_NOT_FOUND;
830 }
831 return CharSequenceUtils.indexOf(seq, searchChar, 0);
832 }
833
834 /**
835 * <p>Finds the first index within a CharSequence from a start position,
836 * handling {@code null}.
837 * This method uses {@link String#indexOf(int, int)} if possible.</p>
838 *
839 * <p>A {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
840 * A negative start position is treated as zero.
841 * A start position greater than the string length returns {@code -1}.</p>
842 *
843 * <pre>
844 * StringUtils.indexOf(null, *, *) = -1
845 * StringUtils.indexOf("", *, *) = -1
846 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
847 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
848 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
849 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
850 * </pre>
851 *
852 * @param seq the CharSequence to check, may be null
853 * @param searchChar the character to find
854 * @param startPos the start position, negative treated as zero
855 * @return the first index of the search character,
856 * -1 if no match or {@code null} string input
857 * @since 2.0
858 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
859 */
860 public static int indexOf(CharSequence seq, int searchChar, int startPos) {
861 if (isEmpty(seq)) {
862 return INDEX_NOT_FOUND;
863 }
864 return CharSequenceUtils.indexOf(seq, searchChar, startPos);
865 }
866
867 /**
868 * <p>Finds the first index within a CharSequence, handling {@code null}.
869 * This method uses {@link String#indexOf(String, int)} if possible.</p>
870 *
871 * <p>A {@code null} CharSequence will return {@code -1}.</p>
872 *
873 * <pre>
874 * StringUtils.indexOf(null, *) = -1
875 * StringUtils.indexOf(*, null) = -1
876 * StringUtils.indexOf("", "") = 0
877 * StringUtils.indexOf("", *) = -1 (except when * = "")
878 * StringUtils.indexOf("aabaabaa", "a") = 0
879 * StringUtils.indexOf("aabaabaa", "b") = 2
880 * StringUtils.indexOf("aabaabaa", "ab") = 1
881 * StringUtils.indexOf("aabaabaa", "") = 0
882 * </pre>
883 *
884 * @param seq the CharSequence to check, may be null
885 * @param searchSeq the CharSequence to find, may be null
886 * @return the first index of the search CharSequence,
887 * -1 if no match or {@code null} string input
888 * @since 2.0
889 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
890 */
891 public static int indexOf(CharSequence seq, CharSequence searchSeq) {
892 if (seq == null || searchSeq == null) {
893 return INDEX_NOT_FOUND;
894 }
895 return CharSequenceUtils.indexOf(seq, searchSeq, 0);
896 }
897
898 /**
899 * <p>Finds the first index within a CharSequence, handling {@code null}.
900 * This method uses {@link String#indexOf(String, int)} if possible.</p>
901 *
902 * <p>A {@code null} CharSequence will return {@code -1}.
903 * A negative start position is treated as zero.
904 * An empty ("") search CharSequence always matches.
905 * A start position greater than the string length only matches
906 * an empty search CharSequence.</p>
907 *
908 * <pre>
909 * StringUtils.indexOf(null, *, *) = -1
910 * StringUtils.indexOf(*, null, *) = -1
911 * StringUtils.indexOf("", "", 0) = 0
912 * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
913 * StringUtils.indexOf("aabaabaa", "a", 0) = 0
914 * StringUtils.indexOf("aabaabaa", "b", 0) = 2
915 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
916 * StringUtils.indexOf("aabaabaa", "b", 3) = 5
917 * StringUtils.indexOf("aabaabaa", "b", 9) = -1
918 * StringUtils.indexOf("aabaabaa", "b", -1) = 2
919 * StringUtils.indexOf("aabaabaa", "", 2) = 2
920 * StringUtils.indexOf("abc", "", 9) = 3
921 * </pre>
922 *
923 * @param seq the CharSequence to check, may be null
924 * @param searchSeq the CharSequence to find, may be null
925 * @param startPos the start position, negative treated as zero
926 * @return the first index of the search CharSequence,
927 * -1 if no match or {@code null} string input
928 * @since 2.0
929 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
930 */
931 public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
932 if (seq == null || searchSeq == null) {
933 return INDEX_NOT_FOUND;
934 }
935 return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
936 }
937
938 /**
939 * <p>Finds the n-th index within a CharSequence, handling {@code null}.
940 * This method uses {@link String#indexOf(String)} if possible.</p>
941 *
942 * <p>A {@code null} CharSequence will return {@code -1}.</p>
943 *
944 * <pre>
945 * StringUtils.ordinalIndexOf(null, *, *) = -1
946 * StringUtils.ordinalIndexOf(*, null, *) = -1
947 * StringUtils.ordinalIndexOf("", "", *) = 0
948 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
949 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
950 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
951 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
952 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
953 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
954 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
955 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
956 * </pre>
957 *
958 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
959 *
960 * <pre>
961 * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
962 * </pre>
963 *
964 * @param str the CharSequence to check, may be null
965 * @param searchStr the CharSequence to find, may be null
966 * @param ordinal the n-th {@code searchStr} to find
967 * @return the n-th index of the search CharSequence,
968 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
969 * @since 2.1
970 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
971 */
972 public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
973 return ordinalIndexOf(str, searchStr, ordinal, false);
974 }
975
976 /**
977 * <p>Finds the n-th index within a String, handling {@code null}.
978 * This method uses {@link String#indexOf(String)} if possible.</p>
979 *
980 * <p>A {@code null} CharSequence will return {@code -1}.</p>
981 *
982 * @param str the CharSequence to check, may be null
983 * @param searchStr the CharSequence to find, may be null
984 * @param ordinal the n-th {@code searchStr} to find
985 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
986 * @return the n-th index of the search CharSequence,
987 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
988 */
989 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
990 private static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal, boolean lastIndex) {
991 if (str == null || searchStr == null || ordinal <= 0) {
992 return INDEX_NOT_FOUND;
993 }
994 if (searchStr.length() == 0) {
995 return lastIndex ? str.length() : 0;
996 }
997 int found = 0;
998 int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
999 do {
1000 if (lastIndex) {
1001 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1);
1002 } else {
1003 index = CharSequenceUtils.indexOf(str, searchStr, index + 1);
1004 }
1005 if (index < 0) {
1006 return index;
1007 }
1008 found++;
1009 } while (found < ordinal);
1010 return index;
1011 }
1012
1013 /**
1014 * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1015 *
1016 * <p>A {@code null} CharSequence will return {@code -1}.
1017 * A negative start position is treated as zero.
1018 * An empty ("") search CharSequence always matches.
1019 * A start position greater than the string length only matches
1020 * an empty search CharSequence.</p>
1021 *
1022 * <pre>
1023 * StringUtils.indexOfIgnoreCase(null, *) = -1
1024 * StringUtils.indexOfIgnoreCase(*, null) = -1
1025 * StringUtils.indexOfIgnoreCase("", "") = 0
1026 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
1027 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
1028 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1029 * </pre>
1030 *
1031 * @param str the CharSequence to check, may be null
1032 * @param searchStr the CharSequence to find, may be null
1033 * @return the first index of the search CharSequence,
1034 * -1 if no match or {@code null} string input
1035 * @since 2.5
1036 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1037 */
1038 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
1039 return indexOfIgnoreCase(str, searchStr, 0);
1040 }
1041
1042 /**
1043 * <p>Case in-sensitive find of the first index within a CharSequence
1044 * from the specified position.</p>
1045 *
1046 * <p>A {@code null} CharSequence will return {@code -1}.
1047 * A negative start position is treated as zero.
1048 * An empty ("") search CharSequence always matches.
1049 * A start position greater than the string length only matches
1050 * an empty search CharSequence.</p>
1051 *
1052 * <pre>
1053 * StringUtils.indexOfIgnoreCase(null, *, *) = -1
1054 * StringUtils.indexOfIgnoreCase(*, null, *) = -1
1055 * StringUtils.indexOfIgnoreCase("", "", 0) = 0
1056 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
1057 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
1058 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1059 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
1060 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
1061 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1062 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
1063 * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3
1064 * </pre>
1065 *
1066 * @param str the CharSequence to check, may be null
1067 * @param searchStr the CharSequence to find, may be null
1068 * @param startPos the start position, negative treated as zero
1069 * @return the first index of the search CharSequence,
1070 * -1 if no match or {@code null} string input
1071 * @since 2.5
1072 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1073 */
1074 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
1075 if (str == null || searchStr == null) {
1076 return INDEX_NOT_FOUND;
1077 }
1078 if (startPos < 0) {
1079 startPos = 0;
1080 }
1081 int endLimit = (str.length() - searchStr.length()) + 1;
1082 if (startPos > endLimit) {
1083 return INDEX_NOT_FOUND;
1084 }
1085 if (searchStr.length() == 0) {
1086 return startPos;
1087 }
1088 for (int i = startPos; i < endLimit; i++) {
1089 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1090 return i;
1091 }
1092 }
1093 return INDEX_NOT_FOUND;
1094 }
1095
1096 // LastIndexOf
1097 //-----------------------------------------------------------------------
1098 /**
1099 * <p>Finds the last index within a CharSequence, handling {@code null}.
1100 * This method uses {@link String#lastIndexOf(int)} if possible.</p>
1101 *
1102 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}.</p>
1103 *
1104 * <pre>
1105 * StringUtils.lastIndexOf(null, *) = -1
1106 * StringUtils.lastIndexOf("", *) = -1
1107 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1108 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1109 * </pre>
1110 *
1111 * @param seq the CharSequence to check, may be null
1112 * @param searchChar the character to find
1113 * @return the last index of the search character,
1114 * -1 if no match or {@code null} string input
1115 * @since 2.0
1116 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1117 */
1118 public static int lastIndexOf(CharSequence seq, int searchChar) {
1119 if (isEmpty(seq)) {
1120 return INDEX_NOT_FOUND;
1121 }
1122 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1123 }
1124
1125 /**
1126 * <p>Finds the last index within a CharSequence from a start position,
1127 * handling {@code null}.
1128 * This method uses {@link String#lastIndexOf(int, int)} if possible.</p>
1129 *
1130 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}.
1131 * A negative start position returns {@code -1}.
1132 * A start position greater than the string length searches the whole string.</p>
1133 *
1134 * <pre>
1135 * StringUtils.lastIndexOf(null, *, *) = -1
1136 * StringUtils.lastIndexOf("", *, *) = -1
1137 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
1138 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
1139 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
1140 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
1141 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1142 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
1143 * </pre>
1144 *
1145 * @param seq the CharSequence to check, may be null
1146 * @param searchChar the character to find
1147 * @param startPos the start position
1148 * @return the last index of the search character,
1149 * -1 if no match or {@code null} string input
1150 * @since 2.0
1151 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1152 */
1153 public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) {
1154 if (isEmpty(seq)) {
1155 return INDEX_NOT_FOUND;
1156 }
1157 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1158 }
1159
1160 /**
1161 * <p>Finds the last index within a CharSequence, handling {@code null}.
1162 * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1163 *
1164 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1165 *
1166 * <pre>
1167 * StringUtils.lastIndexOf(null, *) = -1
1168 * StringUtils.lastIndexOf(*, null) = -1
1169 * StringUtils.lastIndexOf("", "") = 0
1170 * StringUtils.lastIndexOf("aabaabaa", "a") = 7
1171 * StringUtils.lastIndexOf("aabaabaa", "b") = 5
1172 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1173 * StringUtils.lastIndexOf("aabaabaa", "") = 8
1174 * </pre>
1175 *
1176 * @param seq the CharSequence to check, may be null
1177 * @param searchSeq the CharSequence to find, may be null
1178 * @return the last index of the search String,
1179 * -1 if no match or {@code null} string input
1180 * @since 2.0
1181 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1182 */
1183 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) {
1184 if (seq == null || searchSeq == null) {
1185 return INDEX_NOT_FOUND;
1186 }
1187 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1188 }
1189
1190 /**
1191 * <p>Finds the n-th last index within a String, handling {@code null}.
1192 * This method uses {@link String#lastIndexOf(String)}.</p>
1193 *
1194 * <p>A {@code null} String will return {@code -1}.</p>
1195 *
1196 * <pre>
1197 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
1198 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
1199 * StringUtils.lastOrdinalIndexOf("", "", *) = 0
1200 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
1201 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
1202 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
1203 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
1204 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1205 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1206 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
1207 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
1208 * </pre>
1209 *
1210 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1211 *
1212 * <pre>
1213 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1214 * </pre>
1215 *
1216 * @param str the CharSequence to check, may be null
1217 * @param searchStr the CharSequence to find, may be null
1218 * @param ordinal the n-th last {@code searchStr} to find
1219 * @return the n-th last index of the search CharSequence,
1220 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1221 * @since 2.5
1222 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1223 */
1224 public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
1225 return ordinalIndexOf(str, searchStr, ordinal, true);
1226 }
1227
1228 /**
1229 * <p>Finds the first index within a CharSequence, handling {@code null}.
1230 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1231 *
1232 * <p>A {@code null} CharSequence will return {@code -1}.
1233 * A negative start position returns {@code -1}.
1234 * An empty ("") search CharSequence always matches unless the start position is negative.
1235 * A start position greater than the string length searches the whole string.</p>
1236 *
1237 * <pre>
1238 * StringUtils.lastIndexOf(null, *, *) = -1
1239 * StringUtils.lastIndexOf(*, null, *) = -1
1240 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
1241 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
1242 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1243 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
1244 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1245 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
1246 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
1247 * </pre>
1248 *
1249 * @param seq the CharSequence to check, may be null
1250 * @param searchSeq the CharSequence to find, may be null
1251 * @param startPos the start position, negative treated as zero
1252 * @return the first index of the search CharSequence,
1253 * -1 if no match or {@code null} string input
1254 * @since 2.0
1255 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1256 */
1257 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
1258 if (seq == null || searchSeq == null) {
1259 return INDEX_NOT_FOUND;
1260 }
1261 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1262 }
1263
1264 /**
1265 * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1266 *
1267 * <p>A {@code null} CharSequence will return {@code -1}.
1268 * A negative start position returns {@code -1}.
1269 * An empty ("") search CharSequence always matches unless the start position is negative.
1270 * A start position greater than the string length searches the whole string.</p>
1271 *
1272 * <pre>
1273 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
1274 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
1275 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
1276 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
1277 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1278 * </pre>
1279 *
1280 * @param str the CharSequence to check, may be null
1281 * @param searchStr the CharSequence to find, may be null
1282 * @return the first index of the search CharSequence,
1283 * -1 if no match or {@code null} string input
1284 * @since 2.5
1285 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1286 */
1287 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
1288 if (str == null || searchStr == null) {
1289 return INDEX_NOT_FOUND;
1290 }
1291 return lastIndexOfIgnoreCase(str, searchStr, str.length());
1292 }
1293
1294 /**
1295 * <p>Case in-sensitive find of the last index within a CharSequence
1296 * from the specified position.</p>
1297 *
1298 * <p>A {@code null} CharSequence will return {@code -1}.
1299 * A negative start position returns {@code -1}.
1300 * An empty ("") search CharSequence always matches unless the start position is negative.
1301 * A start position greater than the string length searches the whole string.</p>
1302 *
1303 * <pre>
1304 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
1305 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
1306 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
1307 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
1308 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1309 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
1310 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1311 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
1312 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
1313 * </pre>
1314 *
1315 * @param str the CharSequence to check, may be null
1316 * @param searchStr the CharSequence to find, may be null
1317 * @param startPos the start position
1318 * @return the first index of the search CharSequence,
1319 * -1 if no match or {@code null} input
1320 * @since 2.5
1321 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1322 */
1323 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
1324 if (str == null || searchStr == null) {
1325 return INDEX_NOT_FOUND;
1326 }
1327 if (startPos > (str.length() - searchStr.length())) {
1328 startPos = str.length() - searchStr.length();
1329 }
1330 if (startPos < 0) {
1331 return INDEX_NOT_FOUND;
1332 }
1333 if (searchStr.length() == 0) {
1334 return startPos;
1335 }
1336
1337 for (int i = startPos; i >= 0; i--) {
1338 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1339 return i;
1340 }
1341 }
1342 return INDEX_NOT_FOUND;
1343 }
1344
1345 // Contains
1346 //-----------------------------------------------------------------------
1347 /**
1348 * <p>Checks if CharSequence contains a search character, handling {@code null}.
1349 * This method uses {@link String#indexOf(int)} if possible.</p>
1350 *
1351 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1352 *
1353 * <pre>
1354 * StringUtils.contains(null, *) = false
1355 * StringUtils.contains("", *) = false
1356 * StringUtils.contains("abc", 'a') = true
1357 * StringUtils.contains("abc", 'z') = false
1358 * </pre>
1359 *
1360 * @param seq the CharSequence to check, may be null
1361 * @param searchChar the character to find
1362 * @return true if the CharSequence contains the search character,
1363 * false if not or {@code null} string input
1364 * @since 2.0
1365 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1366 */
1367 public static boolean contains(CharSequence seq, int searchChar) {
1368 if (isEmpty(seq)) {
1369 return false;
1370 }
1371 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1372 }
1373
1374 /**
1375 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1376 * This method uses {@link String#indexOf(String)} if possible.</p>
1377 *
1378 * <p>A {@code null} CharSequence will return {@code false}.</p>
1379 *
1380 * <pre>
1381 * StringUtils.contains(null, *) = false
1382 * StringUtils.contains(*, null) = false
1383 * StringUtils.contains("", "") = true
1384 * StringUtils.contains("abc", "") = true
1385 * StringUtils.contains("abc", "a") = true
1386 * StringUtils.contains("abc", "z") = false
1387 * </pre>
1388 *
1389 * @param seq the CharSequence to check, may be null
1390 * @param searchSeq the CharSequence to find, may be null
1391 * @return true if the CharSequence contains the search CharSequence,
1392 * false if not or {@code null} string input
1393 * @since 2.0
1394 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1395 */
1396 public static boolean contains(CharSequence seq, CharSequence searchSeq) {
1397 if (seq == null || searchSeq == null) {
1398 return false;
1399 }
1400 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1401 }
1402
1403 /**
1404 * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1405 * handling {@code null}. Case-insensitivity is defined as by
1406 * {@link String#equalsIgnoreCase(String)}.
1407 *
1408 * <p>A {@code null} CharSequence will return {@code false}.</p>
1409 *
1410 * <pre>
1411 * StringUtils.contains(null, *) = false
1412 * StringUtils.contains(*, null) = false
1413 * StringUtils.contains("", "") = true
1414 * StringUtils.contains("abc", "") = true
1415 * StringUtils.contains("abc", "a") = true
1416 * StringUtils.contains("abc", "z") = false
1417 * StringUtils.contains("abc", "A") = true
1418 * StringUtils.contains("abc", "Z") = false
1419 * </pre>
1420 *
1421 * @param str the CharSequence to check, may be null
1422 * @param searchStr the CharSequence to find, may be null
1423 * @return true if the CharSequence contains the search CharSequence irrespective of
1424 * case or false if not or {@code null} string input
1425 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1426 */
1427 public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) {
1428 if (str == null || searchStr == null) {
1429 return false;
1430 }
1431 int len = searchStr.length();
1432 int max = str.length() - len;
1433 for (int i = 0; i <= max; i++) {
1434 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1435 return true;
1436 }
1437 }
1438 return false;
1439 }
1440
1441 /**
1442 * Check whether the given CharSequence contains any whitespace characters.
1443 * @param seq the CharSequence to check (may be {@code null})
1444 * @return {@code true} if the CharSequence is not empty and
1445 * contains at least 1 whitespace character
1446 * @see java.lang.Character#isWhitespace
1447 * @since 3.0
1448 */
1449 // From org.springframework.util.StringUtils, under Apache License 2.0
1450 public static boolean containsWhitespace(CharSequence seq) {
1451 if (isEmpty(seq)) {
1452 return false;
1453 }
1454 int strLen = seq.length();
1455 for (int i = 0; i < strLen; i++) {
1456 if (Character.isWhitespace(seq.charAt(i))) {
1457 return true;
1458 }
1459 }
1460 return false;
1461 }
1462
1463 // IndexOfAny chars
1464 //-----------------------------------------------------------------------
1465 /**
1466 * <p>Search a CharSequence to find the first index of any
1467 * character in the given set of characters.</p>
1468 *
1469 * <p>A {@code null} String will return {@code -1}.
1470 * A {@code null} or zero length search array will return {@code -1}.</p>
1471 *
1472 * <pre>
1473 * StringUtils.indexOfAny(null, *) = -1
1474 * StringUtils.indexOfAny("", *) = -1
1475 * StringUtils.indexOfAny(*, null) = -1
1476 * StringUtils.indexOfAny(*, []) = -1
1477 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
1478 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
1479 * StringUtils.indexOfAny("aba", ['z']) = -1
1480 * </pre>
1481 *
1482 * @param cs the CharSequence to check, may be null
1483 * @param searchChars the chars to search for, may be null
1484 * @return the index of any of the chars, -1 if no match or null input
1485 * @since 2.0
1486 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
1487 */
1488 public static int indexOfAny(CharSequence cs, char... searchChars) {
1489 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1490 return INDEX_NOT_FOUND;
1491 }
1492 int csLen = cs.length();
1493 int csLast = csLen - 1;
1494 int searchLen = searchChars.length;
1495 int searchLast = searchLen - 1;
1496 for (int i = 0; i < csLen; i++) {
1497 char ch = cs.charAt(i);
1498 for (int j = 0; j < searchLen; j++) {
1499 if (searchChars[j] == ch) {
1500 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
1501 // ch is a supplementary character
1502 if (searchChars[j + 1] == cs.charAt(i + 1)) {
1503 return i;
1504 }
1505 } else {
1506 return i;
1507 }
1508 }
1509 }
1510 }
1511 return INDEX_NOT_FOUND;
1512 }
1513
1514 /**
1515 * <p>Search a CharSequence to find the first index of any
1516 * character in the given set of characters.</p>
1517 *
1518 * <p>A {@code null} String will return {@code -1}.
1519 * A {@code null} search string will return {@code -1}.</p>
1520 *
1521 * <pre>
1522 * StringUtils.indexOfAny(null, *) = -1
1523 * StringUtils.indexOfAny("", *) = -1
1524 * StringUtils.indexOfAny(*, null) = -1
1525 * StringUtils.indexOfAny(*, "") = -1
1526 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
1527 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
1528 * StringUtils.indexOfAny("aba","z") = -1
1529 * </pre>
1530 *
1531 * @param cs the CharSequence to check, may be null
1532 * @param searchChars the chars to search for, may be null
1533 * @return the index of any of the chars, -1 if no match or null input
1534 * @since 2.0
1535 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
1536 */
1537 public static int indexOfAny(CharSequence cs, String searchChars) {
1538 if (isEmpty(cs) || isEmpty(searchChars)) {
1539 return INDEX_NOT_FOUND;
1540 }
1541 return indexOfAny(cs, searchChars.toCharArray());
1542 }
1543
1544 // ContainsAny
1545 //-----------------------------------------------------------------------
1546 /**
1547 * <p>Checks if the CharSequence contains any character in the given
1548 * set of characters.</p>
1549 *
1550 * <p>A {@code null} CharSequence will return {@code false}.
1551 * A {@code null} or zero length search array will return {@code false}.</p>
1552 *
1553 * <pre>
1554 * StringUtils.containsAny(null, *) = false
1555 * StringUtils.containsAny("", *) = false
1556 * StringUtils.containsAny(*, null) = false
1557 * StringUtils.containsAny(*, []) = false
1558 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
1559 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
1560 * StringUtils.containsAny("aba", ['z']) = false
1561 * </pre>
1562 *
1563 * @param cs the CharSequence to check, may be null
1564 * @param searchChars the chars to search for, may be null
1565 * @return the {@code true} if any of the chars are found,
1566 * {@code false} if no match or null input
1567 * @since 2.4
1568 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1569 */
1570 public static boolean containsAny(CharSequence cs, char... searchChars) {
1571 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1572 return false;
1573 }
1574 int csLength = cs.length();
1575 int searchLength = searchChars.length;
1576 int csLast = csLength - 1;
1577 int searchLast = searchLength - 1;
1578 for (int i = 0; i < csLength; i++) {
1579 char ch = cs.charAt(i);
1580 for (int j = 0; j < searchLength; j++) {
1581 if (searchChars[j] == ch) {
1582 if (Character.isHighSurrogate(ch)) {
1583 if (j == searchLast) {
1584 // missing low surrogate, fine, like String.indexOf(String)
1585 return true;
1586 }
1587 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1588 return true;
1589 }
1590 } else {
1591 // ch is in the Basic Multilingual Plane
1592 return true;
1593 }
1594 }
1595 }
1596 }
1597 return false;
1598 }
1599
1600 /**
1601 * <p>
1602 * Checks if the CharSequence contains any character in the given set of characters.
1603 * </p>
1604 *
1605 * <p>
1606 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1607 * {@code false}.
1608 * </p>
1609 *
1610 * <pre>
1611 * StringUtils.containsAny(null, *) = false
1612 * StringUtils.containsAny("", *) = false
1613 * StringUtils.containsAny(*, null) = false
1614 * StringUtils.containsAny(*, "") = false
1615 * StringUtils.containsAny("zzabyycdxx", "za") = true
1616 * StringUtils.containsAny("zzabyycdxx", "by") = true
1617 * StringUtils.containsAny("aba","z") = false
1618 * </pre>
1619 *
1620 * @param cs
1621 * the CharSequence to check, may be null
1622 * @param searchChars
1623 * the chars to search for, may be null
1624 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1625 * @since 2.4
1626 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1627 */
1628 public static boolean containsAny(CharSequence cs, CharSequence searchChars) {
1629 if (searchChars == null) {
1630 return false;
1631 }
1632 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1633 }
1634
1635 // IndexOfAnyBut chars
1636 //-----------------------------------------------------------------------
1637 /**
1638 * <p>Searches a CharSequence to find the first index of any
1639 * character not in the given set of characters.</p>
1640 *
1641 * <p>A {@code null} CharSequence will return {@code -1}.
1642 * A {@code null} or zero length search array will return {@code -1}.</p>
1643 *
1644 * <pre>
1645 * StringUtils.indexOfAnyBut(null, *) = -1
1646 * StringUtils.indexOfAnyBut("", *) = -1
1647 * StringUtils.indexOfAnyBut(*, null) = -1
1648 * StringUtils.indexOfAnyBut(*, []) = -1
1649 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
1650 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
1651 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
1652
1653 * </pre>
1654 *
1655 * @param cs the CharSequence to check, may be null
1656 * @param searchChars the chars to search for, may be null
1657 * @return the index of any of the chars, -1 if no match or null input
1658 * @since 2.0
1659 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
1660 */
1661 public static int indexOfAnyBut(CharSequence cs, char... searchChars) {
1662 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1663 return INDEX_NOT_FOUND;
1664 }
1665 int csLen = cs.length();
1666 int csLast = csLen - 1;
1667 int searchLen = searchChars.length;
1668 int searchLast = searchLen - 1;
1669 outer:
1670 for (int i = 0; i < csLen; i++) {
1671 char ch = cs.charAt(i);
1672 for (int j = 0; j < searchLen; j++) {
1673 if (searchChars[j] == ch) {
1674 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
1675 if (searchChars[j + 1] == cs.charAt(i + 1)) {
1676 continue outer;
1677 }
1678 } else {
1679 continue outer;
1680 }
1681 }
1682 }
1683 return i;
1684 }
1685 return INDEX_NOT_FOUND;
1686 }
1687
1688 /**
1689 * <p>Search a CharSequence to find the first index of any
1690 * character not in the given set of characters.</p>
1691 *
1692 * <p>A {@code null} CharSequence will return {@code -1}.
1693 * A {@code null} or empty search string will return {@code -1}.</p>
1694 *
1695 * <pre>
1696 * StringUtils.indexOfAnyBut(null, *) = -1
1697 * StringUtils.indexOfAnyBut("", *) = -1
1698 * StringUtils.indexOfAnyBut(*, null) = -1
1699 * StringUtils.indexOfAnyBut(*, "") = -1
1700 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
1701 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
1702 * StringUtils.indexOfAnyBut("aba","ab") = -1
1703 * </pre>
1704 *
1705 * @param seq the CharSequence to check, may be null
1706 * @param searchChars the chars to search for, may be null
1707 * @return the index of any of the chars, -1 if no match or null input
1708 * @since 2.0
1709 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
1710 */
1711 public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) {
1712 if (isEmpty(seq) || isEmpty(searchChars)) {
1713 return INDEX_NOT_FOUND;
1714 }
1715 int strLen = seq.length();
1716 for (int i = 0; i < strLen; i++) {
1717 char ch = seq.charAt(i);
1718 boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
1719 if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
1720 char ch2 = seq.charAt(i + 1);
1721 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
1722 return i;
1723 }
1724 } else {
1725 if (!chFound) {
1726 return i;
1727 }
1728 }
1729 }
1730 return INDEX_NOT_FOUND;
1731 }
1732
1733 // ContainsOnly
1734 //-----------------------------------------------------------------------
1735 /**
1736 * <p>Checks if the CharSequence contains only certain characters.</p>
1737 *
1738 * <p>A {@code null} CharSequence will return {@code false}.
1739 * A {@code null} valid character array will return {@code false}.
1740 * An empty CharSequence (length()=0) always returns {@code true}.</p>
1741 *
1742 * <pre>
1743 * StringUtils.containsOnly(null, *) = false
1744 * StringUtils.containsOnly(*, null) = false
1745 * StringUtils.containsOnly("", *) = true
1746 * StringUtils.containsOnly("ab", '') = false
1747 * StringUtils.containsOnly("abab", 'abc') = true
1748 * StringUtils.containsOnly("ab1", 'abc') = false
1749 * StringUtils.containsOnly("abz", 'abc') = false
1750 * </pre>
1751 *
1752 * @param cs the String to check, may be null
1753 * @param valid an array of valid chars, may be null
1754 * @return true if it only contains valid chars and is non-null
1755 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1756 */
1757 public static boolean containsOnly(CharSequence cs, char... valid) {
1758 // All these pre-checks are to maintain API with an older version
1759 if (valid == null || cs == null) {
1760 return false;
1761 }
1762 if (cs.length() == 0) {
1763 return true;
1764 }
1765 if (valid.length == 0) {
1766 return false;
1767 }
1768 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1769 }
1770
1771 /**
1772 * <p>Checks if the CharSequence contains only certain characters.</p>
1773 *
1774 * <p>A {@code null} CharSequence will return {@code false}.
1775 * A {@code null} valid character String will return {@code false}.
1776 * An empty String (length()=0) always returns {@code true}.</p>
1777 *
1778 * <pre>
1779 * StringUtils.containsOnly(null, *) = false
1780 * StringUtils.containsOnly(*, null) = false
1781 * StringUtils.containsOnly("", *) = true
1782 * StringUtils.containsOnly("ab", "") = false
1783 * StringUtils.containsOnly("abab", "abc") = true
1784 * StringUtils.containsOnly("ab1", "abc") = false
1785 * StringUtils.containsOnly("abz", "abc") = false
1786 * </pre>
1787 *
1788 * @param cs the CharSequence to check, may be null
1789 * @param validChars a String of valid chars, may be null
1790 * @return true if it only contains valid chars and is non-null
1791 * @since 2.0
1792 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1793 */
1794 public static boolean containsOnly(CharSequence cs, String validChars) {
1795 if (cs == null || validChars == null) {
1796 return false;
1797 }
1798 return containsOnly(cs, validChars.toCharArray());
1799 }
1800
1801 // ContainsNone
1802 //-----------------------------------------------------------------------
1803 /**
1804 * <p>Checks that the CharSequence does not contain certain characters.</p>
1805 *
1806 * <p>A {@code null} CharSequence will return {@code true}.
1807 * A {@code null} invalid character array will return {@code true}.
1808 * An empty CharSequence (length()=0) always returns true.</p>
1809 *
1810 * <pre>
1811 * StringUtils.containsNone(null, *) = true
1812 * StringUtils.containsNone(*, null) = true
1813 * StringUtils.containsNone("", *) = true
1814 * StringUtils.containsNone("ab", '') = true
1815 * StringUtils.containsNone("abab", 'xyz') = true
1816 * StringUtils.containsNone("ab1", 'xyz') = true
1817 * StringUtils.containsNone("abz", 'xyz') = false
1818 * </pre>
1819 *
1820 * @param cs the CharSequence to check, may be null
1821 * @param searchChars an array of invalid chars, may be null
1822 * @return true if it contains none of the invalid chars, or is null
1823 * @since 2.0
1824 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1825 */
1826 public static boolean containsNone(CharSequence cs, char... searchChars) {
1827 if (cs == null || searchChars == null) {
1828 return true;
1829 }
1830 int csLen = cs.length();
1831 int csLast = csLen - 1;
1832 int searchLen = searchChars.length;
1833 int searchLast = searchLen - 1;
1834 for (int i = 0; i < csLen; i++) {
1835 char ch = cs.charAt(i);
1836 for (int j = 0; j < searchLen; j++) {
1837 if (searchChars[j] == ch) {
1838 if (Character.isHighSurrogate(ch)) {
1839 if (j == searchLast) {
1840 // missing low surrogate, fine, like String.indexOf(String)
1841 return false;
1842 }
1843 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1844 return false;
1845 }
1846 } else {
1847 // ch is in the Basic Multilingual Plane
1848 return false;
1849 }
1850 }
1851 }
1852 }
1853 return true;
1854 }
1855
1856 /**
1857 * <p>Checks that the CharSequence does not contain certain characters.</p>
1858 *
1859 * <p>A {@code null} CharSequence will return {@code true}.
1860 * A {@code null} invalid character array will return {@code true}.
1861 * An empty String ("") always returns true.</p>
1862 *
1863 * <pre>
1864 * StringUtils.containsNone(null, *) = true
1865 * StringUtils.containsNone(*, null) = true
1866 * StringUtils.containsNone("", *) = true
1867 * StringUtils.containsNone("ab", "") = true
1868 * StringUtils.containsNone("abab", "xyz") = true
1869 * StringUtils.containsNone("ab1", "xyz") = true
1870 * StringUtils.containsNone("abz", "xyz") = false
1871 * </pre>
1872 *
1873 * @param cs the CharSequence to check, may be null
1874 * @param invalidChars a String of invalid chars, may be null
1875 * @return true if it contains none of the invalid chars, or is null
1876 * @since 2.0
1877 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1878 */
1879 public static boolean containsNone(CharSequence cs, String invalidChars) {
1880 if (cs == null || invalidChars == null) {
1881 return true;
1882 }
1883 return containsNone(cs, invalidChars.toCharArray());
1884 }
1885
1886 // IndexOfAny strings
1887 //-----------------------------------------------------------------------
1888 /**
1889 * <p>Find the first index of any of a set of potential substrings.</p>
1890 *
1891 * <p>A {@code null} CharSequence will return {@code -1}.
1892 * A {@code null} or zero length search array will return {@code -1}.
1893 * A {@code null} search array entry will be ignored, but a search
1894 * array containing "" will return {@code 0} if {@code str} is not
1895 * null. This method uses {@link String#indexOf(String)} if possible.</p>
1896 *
1897 * <pre>
1898 * StringUtils.indexOfAny(null, *) = -1
1899 * StringUtils.indexOfAny(*, null) = -1
1900 * StringUtils.indexOfAny(*, []) = -1
1901 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
1902 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
1903 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
1904 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
1905 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
1906 * StringUtils.indexOfAny("", [""]) = 0
1907 * StringUtils.indexOfAny("", ["a"]) = -1
1908 * </pre>
1909 *
1910 * @param str the CharSequence to check, may be null
1911 * @param searchStrs the CharSequences to search for, may be null
1912 * @return the first index of any of the searchStrs in str, -1 if no match
1913 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
1914 */
1915 public static int indexOfAny(CharSequence str, CharSequence... searchStrs) {
1916 if (str == null || searchStrs == null) {
1917 return INDEX_NOT_FOUND;
1918 }
1919 int sz = searchStrs.length;
1920
1921 // String's can't have a MAX_VALUEth index.
1922 int ret = Integer.MAX_VALUE;
1923
1924 int tmp = 0;
1925 for (int i = 0; i < sz; i++) {
1926 CharSequence search = searchStrs[i];
1927 if (search == null) {
1928 continue;
1929 }
1930 tmp = CharSequenceUtils.indexOf(str, search, 0);
1931 if (tmp == INDEX_NOT_FOUND) {
1932 continue;
1933 }
1934
1935 if (tmp < ret) {
1936 ret = tmp;
1937 }
1938 }
1939
1940 return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
1941 }
1942
1943 /**
1944 * <p>Find the latest index of any of a set of potential substrings.</p>
1945 *
1946 * <p>A {@code null} CharSequence will return {@code -1}.
1947 * A {@code null} search array will return {@code -1}.
1948 * A {@code null} or zero length search array entry will be ignored,
1949 * but a search array containing "" will return the length of {@code str}
1950 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
1951 *
1952 * <pre>
1953 * StringUtils.lastIndexOfAny(null, *) = -1
1954 * StringUtils.lastIndexOfAny(*, null) = -1
1955 * StringUtils.lastIndexOfAny(*, []) = -1
1956 * StringUtils.lastIndexOfAny(*, [null]) = -1
1957 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
1958 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
1959 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1960 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1961 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
1962 * </pre>
1963 *
1964 * @param str the CharSequence to check, may be null
1965 * @param searchStrs the CharSequences to search for, may be null
1966 * @return the last index of any of the CharSequences, -1 if no match
1967 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
1968 */
1969 public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) {
1970 if (str == null || searchStrs == null) {
1971 return INDEX_NOT_FOUND;
1972 }
1973 int sz = searchStrs.length;
1974 int ret = INDEX_NOT_FOUND;
1975 int tmp = 0;
1976 for (int i = 0; i < sz; i++) {
1977 CharSequence search = searchStrs[i];
1978 if (search == null) {
1979 continue;
1980 }
1981 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
1982 if (tmp > ret) {
1983 ret = tmp;
1984 }
1985 }
1986 return ret;
1987 }
1988
1989 // Substring
1990 //-----------------------------------------------------------------------
1991 /**
1992 * <p>Gets a substring from the specified String avoiding exceptions.</p>
1993 *
1994 * <p>A negative start position can be used to start {@code n}
1995 * characters from the end of the String.</p>
1996 *
1997 * <p>A {@code null} String will return {@code null}.
1998 * An empty ("") String will return "".</p>
1999 *
2000 * <pre>
2001 * StringUtils.substring(null, *) = null
2002 * StringUtils.substring("", *) = ""
2003 * StringUtils.substring("abc", 0) = "abc"
2004 * StringUtils.substring("abc", 2) = "c"
2005 * StringUtils.substring("abc", 4) = ""
2006 * StringUtils.substring("abc", -2) = "bc"
2007 * StringUtils.substring("abc", -4) = "abc"
2008 * </pre>
2009 *
2010 * @param str the String to get the substring from, may be null
2011 * @param start the position to start from, negative means
2012 * count back from the end of the String by this many characters
2013 * @return substring from start position, {@code null} if null String input
2014 */
2015 public static String substring(String str, int start) {
2016 if (str == null) {
2017 return null;
2018 }
2019
2020 // handle negatives, which means last n characters
2021 if (start < 0) {
2022 start = str.length() + start; // remember start is negative
2023 }
2024
2025 if (start < 0) {
2026 start = 0;
2027 }
2028 if (start > str.length()) {
2029 return EMPTY;
2030 }
2031
2032 return str.substring(start);
2033 }
2034
2035 /**
2036 * <p>Gets a substring from the specified String avoiding exceptions.</p>
2037 *
2038 * <p>A negative start position can be used to start/end {@code n}
2039 * characters from the end of the String.</p>
2040 *
2041 * <p>The returned substring starts with the character in the {@code start}
2042 * position and ends before the {@code end} position. All position counting is
2043 * zero-based -- i.e., to start at the beginning of the string use
2044 * {@code start = 0}. Negative start and end positions can be used to
2045 * specify offsets relative to the end of the String.</p>
2046 *
2047 * <p>If {@code start} is not strictly to the left of {@code end}, ""
2048 * is returned.</p>
2049 *
2050 * <pre>
2051 * StringUtils.substring(null, *, *) = null
2052 * StringUtils.substring("", * , *) = "";
2053 * StringUtils.substring("abc", 0, 2) = "ab"
2054 * StringUtils.substring("abc", 2, 0) = ""
2055 * StringUtils.substring("abc", 2, 4) = "c"
2056 * StringUtils.substring("abc", 4, 6) = ""
2057 * StringUtils.substring("abc", 2, 2) = ""
2058 * StringUtils.substring("abc", -2, -1) = "b"
2059 * StringUtils.substring("abc", -4, 2) = "ab"
2060 * </pre>
2061 *
2062 * @param str the String to get the substring from, may be null
2063 * @param start the position to start from, negative means
2064 * count back from the end of the String by this many characters
2065 * @param end the position to end at (exclusive), negative means
2066 * count back from the end of the String by this many characters
2067 * @return substring from start position to end position,
2068 * {@code null} if null String input
2069 */
2070 public static String substring(String str, int start, int end) {
2071 if (str == null) {
2072 return null;
2073 }
2074
2075 // handle negatives
2076 if (end < 0) {
2077 end = str.length() + end; // remember end is negative
2078 }
2079 if (start < 0) {
2080 start = str.length() + start; // remember start is negative
2081 }
2082
2083 // check length next
2084 if (end > str.length()) {
2085 end = str.length();
2086 }
2087
2088 // if start is greater than end, return ""
2089 if (start > end) {
2090 return EMPTY;
2091 }
2092
2093 if (start < 0) {
2094 start = 0;
2095 }
2096 if (end < 0) {
2097 end = 0;
2098 }
2099
2100 return str.substring(start, end);
2101 }
2102
2103 // Left/Right/Mid
2104 //-----------------------------------------------------------------------
2105 /**
2106 * <p>Gets the leftmost {@code len} characters of a String.</p>
2107 *
2108 * <p>If {@code len} characters are not available, or the
2109 * String is {@code null}, the String will be returned without
2110 * an exception. An empty String is returned if len is negative.</p>
2111 *
2112 * <pre>
2113 * StringUtils.left(null, *) = null
2114 * StringUtils.left(*, -ve) = ""
2115 * StringUtils.left("", *) = ""
2116 * StringUtils.left("abc", 0) = ""
2117 * StringUtils.left("abc", 2) = "ab"
2118 * StringUtils.left("abc", 4) = "abc"
2119 * </pre>
2120 *
2121 * @param str the String to get the leftmost characters from, may be null
2122 * @param len the length of the required String
2123 * @return the leftmost characters, {@code null} if null String input
2124 */
2125 public static String left(String str, int len) {
2126 if (str == null) {
2127 return null;
2128 }
2129 if (len < 0) {
2130 return EMPTY;
2131 }
2132 if (str.length() <= len) {
2133 return str;
2134 }
2135 return str.substring(0, len);
2136 }
2137
2138 /**
2139 * <p>Gets the rightmost {@code len} characters of a String.</p>
2140 *
2141 * <p>If {@code len} characters are not available, or the String
2142 * is {@code null}, the String will be returned without an
2143 * an exception. An empty String is returned if len is negative.</p>
2144 *
2145 * <pre>
2146 * StringUtils.right(null, *) = null
2147 * StringUtils.right(*, -ve) = ""
2148 * StringUtils.right("", *) = ""
2149 * StringUtils.right("abc", 0) = ""
2150 * StringUtils.right("abc", 2) = "bc"
2151 * StringUtils.right("abc", 4) = "abc"
2152 * </pre>
2153 *
2154 * @param str the String to get the rightmost characters from, may be null
2155 * @param len the length of the required String
2156 * @return the rightmost characters, {@code null} if null String input
2157 */
2158 public static String right(String str, int len) {
2159 if (str == null) {
2160 return null;
2161 }
2162 if (len < 0) {
2163 return EMPTY;
2164 }
2165 if (str.length() <= len) {
2166 return str;
2167 }
2168 return str.substring(str.length() - len);
2169 }
2170
2171 /**
2172 * <p>Gets {@code len} characters from the middle of a String.</p>
2173 *
2174 * <p>If {@code len} characters are not available, the remainder
2175 * of the String will be returned without an exception. If the
2176 * String is {@code null}, {@code null} will be returned.
2177 * An empty String is returned if len is negative or exceeds the
2178 * length of {@code str}.</p>
2179 *
2180 * <pre>
2181 * StringUtils.mid(null, *, *) = null
2182 * StringUtils.mid(*, *, -ve) = ""
2183 * StringUtils.mid("", 0, *) = ""
2184 * StringUtils.mid("abc", 0, 2) = "ab"
2185 * StringUtils.mid("abc", 0, 4) = "abc"
2186 * StringUtils.mid("abc", 2, 4) = "c"
2187 * StringUtils.mid("abc", 4, 2) = ""
2188 * StringUtils.mid("abc", -2, 2) = "ab"
2189 * </pre>
2190 *
2191 * @param str the String to get the characters from, may be null
2192 * @param pos the position to start from, negative treated as zero
2193 * @param len the length of the required String
2194 * @return the middle characters, {@code null} if null String input
2195 */
2196 public static String mid(String str, int pos, int len) {
2197 if (str == null) {
2198 return null;
2199 }
2200 if (len < 0 || pos > str.length()) {
2201 return EMPTY;
2202 }
2203 if (pos < 0) {
2204 pos = 0;
2205 }
2206 if (str.length() <= (pos + len)) {
2207 return str.substring(pos);
2208 }
2209 return str.substring(pos, pos + len);
2210 }
2211
2212 // SubStringAfter/SubStringBefore
2213 //-----------------------------------------------------------------------
2214 /**
2215 * <p>Gets the substring before the first occurrence of a separator.
2216 * The separator is not returned.</p>
2217 *
2218 * <p>A {@code null} string input will return {@code null}.
2219 * An empty ("") string input will return the empty string.
2220 * A {@code null} separator will return the input string.</p>
2221 *
2222 * <p>If nothing is found, the string input is returned.</p>
2223 *
2224 * <pre>
2225 * StringUtils.substringBefore(null, *) = null
2226 * StringUtils.substringBefore("", *) = ""
2227 * StringUtils.substringBefore("abc", "a") = ""
2228 * StringUtils.substringBefore("abcba", "b") = "a"
2229 * StringUtils.substringBefore("abc", "c") = "ab"
2230 * StringUtils.substringBefore("abc", "d") = "abc"
2231 * StringUtils.substringBefore("abc", "") = ""
2232 * StringUtils.substringBefore("abc", null) = "abc"
2233 * </pre>
2234 *
2235 * @param str the String to get a substring from, may be null
2236 * @param separator the String to search for, may be null
2237 * @return the substring before the first occurrence of the separator,
2238 * {@code null} if null String input
2239 * @since 2.0
2240 */
2241 public static String substringBefore(String str, String separator) {
2242 if (isEmpty(str) || separator == null) {
2243 return str;
2244 }
2245 if (separator.length() == 0) {
2246 return EMPTY;
2247 }
2248 int pos = str.indexOf(separator);
2249 if (pos == INDEX_NOT_FOUND) {
2250 return str;
2251 }
2252 return str.substring(0, pos);
2253 }
2254
2255 /**
2256 * <p>Gets the substring after the first occurrence of a separator.
2257 * The separator is not returned.</p>
2258 *
2259 * <p>A {@code null} string input will return {@code null}.
2260 * An empty ("") string input will return the empty string.
2261 * A {@code null} separator will return the empty string if the
2262 * input string is not {@code null}.</p>
2263 *
2264 * <p>If nothing is found, the empty string is returned.</p>
2265 *
2266 * <pre>
2267 * StringUtils.substringAfter(null, *) = null
2268 * StringUtils.substringAfter("", *) = ""
2269 * StringUtils.substringAfter(*, null) = ""
2270 * StringUtils.substringAfter("abc", "a") = "bc"
2271 * StringUtils.substringAfter("abcba", "b") = "cba"
2272 * StringUtils.substringAfter("abc", "c") = ""
2273 * StringUtils.substringAfter("abc", "d") = ""
2274 * StringUtils.substringAfter("abc", "") = "abc"
2275 * </pre>
2276 *
2277 * @param str the String to get a substring from, may be null
2278 * @param separator the String to search for, may be null
2279 * @return the substring after the first occurrence of the separator,
2280 * {@code null} if null String input
2281 * @since 2.0
2282 */
2283 public static String substringAfter(String str, String separator) {
2284 if (isEmpty(str)) {
2285 return str;
2286 }
2287 if (separator == null) {
2288 return EMPTY;
2289 }
2290 int pos = str.indexOf(separator);
2291 if (pos == INDEX_NOT_FOUND) {
2292 return EMPTY;
2293 }
2294 return str.substring(pos + separator.length());
2295 }
2296
2297 /**
2298 * <p>Gets the substring before the last occurrence of a separator.
2299 * The separator is not returned.</p>
2300 *
2301 * <p>A {@code null} string input will return {@code null}.
2302 * An empty ("") string input will return the empty string.
2303 * An empty or {@code null} separator will return the input string.</p>
2304 *
2305 * <p>If nothing is found, the string input is returned.</p>
2306 *
2307 * <pre>
2308 * StringUtils.substringBeforeLast(null, *) = null
2309 * StringUtils.substringBeforeLast("", *) = ""
2310 * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2311 * StringUtils.substringBeforeLast("abc", "c") = "ab"
2312 * StringUtils.substringBeforeLast("a", "a") = ""
2313 * StringUtils.substringBeforeLast("a", "z") = "a"
2314 * StringUtils.substringBeforeLast("a", null) = "a"
2315 * StringUtils.substringBeforeLast("a", "") = "a"
2316 * </pre>
2317 *
2318 * @param str the String to get a substring from, may be null
2319 * @param separator the String to search for, may be null
2320 * @return the substring before the last occurrence of the separator,
2321 * {@code null} if null String input
2322 * @since 2.0
2323 */
2324 public static String substringBeforeLast(String str, String separator) {
2325 if (isEmpty(str) || isEmpty(separator)) {
2326 return str;
2327 }
2328 int pos = str.lastIndexOf(separator);
2329 if (pos == INDEX_NOT_FOUND) {
2330 return str;
2331 }
2332 return str.substring(0, pos);
2333 }
2334
2335 /**
2336 * <p>Gets the substring after the last occurrence of a separator.
2337 * The separator is not returned.</p>
2338 *
2339 * <p>A {@code null} string input will return {@code null}.
2340 * An empty ("") string input will return the empty string.
2341 * An empty or {@code null} separator will return the empty string if
2342 * the input string is not {@code null}.</p>
2343 *
2344 * <p>If nothing is found, the empty string is returned.</p>
2345 *
2346 * <pre>
2347 * StringUtils.substringAfterLast(null, *) = null
2348 * StringUtils.substringAfterLast("", *) = ""
2349 * StringUtils.substringAfterLast(*, "") = ""
2350 * StringUtils.substringAfterLast(*, null) = ""
2351 * StringUtils.substringAfterLast("abc", "a") = "bc"
2352 * StringUtils.substringAfterLast("abcba", "b") = "a"
2353 * StringUtils.substringAfterLast("abc", "c") = ""
2354 * StringUtils.substringAfterLast("a", "a") = ""
2355 * StringUtils.substringAfterLast("a", "z") = ""
2356 * </pre>
2357 *
2358 * @param str the String to get a substring from, may be null
2359 * @param separator the String to search for, may be null
2360 * @return the substring after the last occurrence of the separator,
2361 * {@code null} if null String input
2362 * @since 2.0
2363 */
2364 public static String substringAfterLast(String str, String separator) {
2365 if (isEmpty(str)) {
2366 return str;
2367 }
2368 if (isEmpty(separator)) {
2369 return EMPTY;
2370 }
2371 int pos = str.lastIndexOf(separator);
2372 if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
2373 return EMPTY;
2374 }
2375 return str.substring(pos + separator.length());
2376 }
2377
2378 // Substring between
2379 //-----------------------------------------------------------------------
2380 /**
2381 * <p>Gets the String that is nested in between two instances of the
2382 * same String.</p>
2383 *
2384 * <p>A {@code null} input String returns {@code null}.
2385 * A {@code null} tag returns {@code null}.</p>
2386 *
2387 * <pre>
2388 * StringUtils.substringBetween(null, *) = null
2389 * StringUtils.substringBetween("", "") = ""
2390 * StringUtils.substringBetween("", "tag") = null
2391 * StringUtils.substringBetween("tagabctag", null) = null
2392 * StringUtils.substringBetween("tagabctag", "") = ""
2393 * StringUtils.substringBetween("tagabctag", "tag") = "abc"
2394 * </pre>
2395 *
2396 * @param str the String containing the substring, may be null
2397 * @param tag the String before and after the substring, may be null
2398 * @return the substring, {@code null} if no match
2399 * @since 2.0
2400 */
2401 public static String substringBetween(String str, String tag) {
2402 return substringBetween(str, tag, tag);
2403 }
2404
2405 /**
2406 * <p>Gets the String that is nested in between two Strings.
2407 * Only the first match is returned.</p>
2408 *
2409 * <p>A {@code null} input String returns {@code null}.
2410 * A {@code null} open/close returns {@code null} (no match).
2411 * An empty ("") open and close returns an empty string.</p>
2412 *
2413 * <pre>
2414 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
2415 * StringUtils.substringBetween(null, *, *) = null
2416 * StringUtils.substringBetween(*, null, *) = null
2417 * StringUtils.substringBetween(*, *, null) = null
2418 * StringUtils.substringBetween("", "", "") = ""
2419 * StringUtils.substringBetween("", "", "]") = null
2420 * StringUtils.substringBetween("", "[", "]") = null
2421 * StringUtils.substringBetween("yabcz", "", "") = ""
2422 * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
2423 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
2424 * </pre>
2425 *
2426 * @param str the String containing the substring, may be null
2427 * @param open the String before the substring, may be null
2428 * @param close the String after the substring, may be null
2429 * @return the substring, {@code null} if no match
2430 * @since 2.0
2431 */
2432 public static String substringBetween(String str, String open, String close) {
2433 if (str == null || open == null || close == null) {
2434 return null;
2435 }
2436 int start = str.indexOf(open);
2437 if (start != INDEX_NOT_FOUND) {
2438 int end = str.indexOf(close, start + open.length());
2439 if (end != INDEX_NOT_FOUND) {
2440 return str.substring(start + open.length(), end);
2441 }
2442 }
2443 return null;
2444 }
2445
2446 /**
2447 * <p>Searches a String for substrings delimited by a start and end tag,
2448 * returning all matching substrings in an array.</p>
2449 *
2450 * <p>A {@code null} input String returns {@code null}.
2451 * A {@code null} open/close returns {@code null} (no match).
2452 * An empty ("") open/close returns {@code null} (no match).</p>
2453 *
2454 * <pre>
2455 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
2456 * StringUtils.substringsBetween(null, *, *) = null
2457 * StringUtils.substringsBetween(*, null, *) = null
2458 * StringUtils.substringsBetween(*, *, null) = null
2459 * StringUtils.substringsBetween("", "[", "]") = []
2460 * </pre>
2461 *
2462 * @param str the String containing the substrings, null returns null, empty returns empty
2463 * @param open the String identifying the start of the substring, empty returns null
2464 * @param close the String identifying the end of the substring, empty returns null
2465 * @return a String Array of substrings, or {@code null} if no match
2466 * @since 2.3
2467 */
2468 public static String[] substringsBetween(String str, String open, String close) {
2469 if (str == null || isEmpty(open) || isEmpty(close)) {
2470 return null;
2471 }
2472 int strLen = str.length();
2473 if (strLen == 0) {
2474 return ArrayUtils.EMPTY_STRING_ARRAY;
2475 }
2476 int closeLen = close.length();
2477 int openLen = open.length();
2478 List<String> list = new ArrayList<String>();
2479 int pos = 0;
2480 while (pos < (strLen - closeLen)) {
2481 int start = str.indexOf(open, pos);
2482 if (start < 0) {
2483 break;
2484 }
2485 start += openLen;
2486 int end = str.indexOf(close, start);
2487 if (end < 0) {
2488 break;
2489 }
2490 list.add(str.substring(start, end));
2491 pos = end + closeLen;
2492 }
2493 if (list.isEmpty()) {
2494 return null;
2495 }
2496 return list.toArray(new String [list.size()]);
2497 }
2498
2499 // Nested extraction
2500 //-----------------------------------------------------------------------
2501
2502 // Splitting
2503 //-----------------------------------------------------------------------
2504 /**
2505 * <p>Splits the provided text into an array, using whitespace as the
2506 * separator.
2507 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2508 *
2509 * <p>The separator is not included in the returned String array.
2510 * Adjacent separators are treated as one separator.
2511 * For more control over the split use the StrTokenizer class.</p>
2512 *
2513 * <p>A {@code null} input String returns {@code null}.</p>
2514 *
2515 * <pre>
2516 * StringUtils.split(null) = null
2517 * StringUtils.split("") = []
2518 * StringUtils.split("abc def") = ["abc", "def"]
2519 * StringUtils.split("abc def") = ["abc", "def"]
2520 * StringUtils.split(" abc ") = ["abc"]
2521 * </pre>
2522 *
2523 * @param str the String to parse, may be null
2524 * @return an array of parsed Strings, {@code null} if null String input
2525 */
2526 public static String[] split(String str) {
2527 return split(str, null, -1);
2528 }
2529
2530 /**
2531 * <p>Splits the provided text into an array, separator specified.
2532 * This is an alternative to using StringTokenizer.</p>
2533 *
2534 * <p>The separator is not included in the returned String array.
2535 * Adjacent separators are treated as one separator.
2536 * For more control over the split use the StrTokenizer class.</p>
2537 *
2538 * <p>A {@code null} input String returns {@code null}.</p>
2539 *
2540 * <pre>
2541 * StringUtils.split(null, *) = null
2542 * StringUtils.split("", *) = []
2543 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
2544 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
2545 * StringUtils.split("a:b:c", '.') = ["a:b:c"]
2546 * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
2547 * </pre>
2548 *
2549 * @param str the String to parse, may be null
2550 * @param separatorChar the character used as the delimiter
2551 * @return an array of parsed Strings, {@code null} if null String input
2552 * @since 2.0
2553 */
2554 public static String[] split(String str, char separatorChar) {
2555 return splitWorker(str, separatorChar, false);
2556 }
2557
2558 /**
2559 * <p>Splits the provided text into an array, separators specified.
2560 * This is an alternative to using StringTokenizer.</p>
2561 *
2562 * <p>The separator is not included in the returned String array.
2563 * Adjacent separators are treated as one separator.
2564 * For more control over the split use the StrTokenizer class.</p>
2565 *
2566 * <p>A {@code null} input String returns {@code null}.
2567 * A {@code null} separatorChars splits on whitespace.</p>
2568 *
2569 * <pre>
2570 * StringUtils.split(null, *) = null
2571 * StringUtils.split("", *) = []
2572 * StringUtils.split("abc def", null) = ["abc", "def"]
2573 * StringUtils.split("abc def", " ") = ["abc", "def"]
2574 * StringUtils.split("abc def", " ") = ["abc", "def"]
2575 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2576 * </pre>
2577 *
2578 * @param str the String to parse, may be null
2579 * @param separatorChars the characters used as the delimiters,
2580 * {@code null} splits on whitespace
2581 * @return an array of parsed Strings, {@code null} if null String input
2582 */
2583 public static String[] split(String str, String separatorChars) {
2584 return splitWorker(str, separatorChars, -1, false);
2585 }
2586
2587 /**
2588 * <p>Splits the provided text into an array with a maximum length,
2589 * separators specified.</p>
2590 *
2591 * <p>The separator is not included in the returned String array.
2592 * Adjacent separators are treated as one separator.</p>
2593 *
2594 * <p>A {@code null} input String returns {@code null}.
2595 * A {@code null} separatorChars splits on whitespace.</p>
2596 *
2597 * <p>If more than {@code max} delimited substrings are found, the last
2598 * returned string includes all characters after the first {@code max - 1}
2599 * returned strings (including separator characters).</p>
2600 *
2601 * <pre>
2602 * StringUtils.split(null, *, *) = null
2603 * StringUtils.split("", *, *) = []
2604 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
2605 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
2606 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
2607 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2608 * </pre>
2609 *
2610 * @param str the String to parse, may be null
2611 * @param separatorChars the characters used as the delimiters,
2612 * {@code null} splits on whitespace
2613 * @param max the maximum number of elements to include in the
2614 * array. A zero or negative value implies no limit
2615 * @return an array of parsed Strings, {@code null} if null String input
2616 */
2617 public static String[] split(String str, String separatorChars, int max) {
2618 return splitWorker(str, separatorChars, max, false);
2619 }
2620
2621 /**
2622 * <p>Splits the provided text into an array, separator string specified.</p>
2623 *
2624 * <p>The separator(s) will not be included in the returned String array.
2625 * Adjacent separators are treated as one separator.</p>
2626 *
2627 * <p>A {@code null} input String returns {@code null}.
2628 * A {@code null} separator splits on whitespace.</p>
2629 *
2630 * <pre>
2631 * StringUtils.splitByWholeSeparator(null, *) = null
2632 * StringUtils.splitByWholeSeparator("", *) = []
2633 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
2634 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
2635 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2636 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
2637 * </pre>
2638 *
2639 * @param str the String to parse, may be null
2640 * @param separator String containing the String to be used as a delimiter,
2641 * {@code null} splits on whitespace
2642 * @return an array of parsed Strings, {@code null} if null String was input
2643 */
2644 public static String[] splitByWholeSeparator(String str, String separator) {
2645 return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
2646 }
2647
2648 /**
2649 * <p>Splits the provided text into an array, separator string specified.
2650 * Returns a maximum of {@code max} substrings.</p>
2651 *
2652 * <p>The separator(s) will not be included in the returned String array.
2653 * Adjacent separators are treated as one separator.</p>
2654 *
2655 * <p>A {@code null} input String returns {@code null}.
2656 * A {@code null} separator splits on whitespace.</p>
2657 *
2658 * <pre>
2659 * StringUtils.splitByWholeSeparator(null, *, *) = null
2660 * StringUtils.splitByWholeSeparator("", *, *) = []
2661 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
2662 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
2663 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2664 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
2665 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
2666 * </pre>
2667 *
2668 * @param str the String to parse, may be null
2669 * @param separator String containing the String to be used as a delimiter,
2670 * {@code null} splits on whitespace
2671 * @param max the maximum number of elements to include in the returned
2672 * array. A zero or negative value implies no limit.
2673 * @return an array of parsed Strings, {@code null} if null String was input
2674 */
2675 public static String[] splitByWholeSeparator( String str, String separator, int max ) {
2676 return splitByWholeSeparatorWorker(str, separator, max, false);
2677 }
2678
2679 /**
2680 * <p>Splits the provided text into an array, separator string specified. </p>
2681 *
2682 * <p>The separator is not included in the returned String array.
2683 * Adjacent separators are treated as separators for empty tokens.
2684 * For more control over the split use the StrTokenizer class.</p>
2685 *
2686 * <p>A {@code null} input String returns {@code null}.
2687 * A {@code null} separator splits on whitespace.</p>
2688 *
2689 * <pre>
2690 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
2691 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = []
2692 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"]
2693 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"]
2694 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2695 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
2696 * </pre>
2697 *
2698 * @param str the String to parse, may be null
2699 * @param separator String containing the String to be used as a delimiter,
2700 * {@code null} splits on whitespace
2701 * @return an array of parsed Strings, {@code null} if null String was input
2702 * @since 2.4
2703 */
2704 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
2705 return splitByWholeSeparatorWorker(str, separator, -1, true);
2706 }
2707
2708 /**
2709 * <p>Splits the provided text into an array, separator string specified.
2710 * Returns a maximum of {@code max} substrings.</p>
2711 *
2712 * <p>The separator is not included in the returned String array.
2713 * Adjacent separators are treated as separators for empty tokens.
2714 * For more control over the split use the StrTokenizer class.</p>
2715 *
2716 * <p>A {@code null} input String returns {@code null}.
2717 * A {@code null} separator splits on whitespace.</p>
2718 *
2719 * <pre>
2720 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
2721 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = []
2722 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"]
2723 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"]
2724 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2725 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
2726 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
2727 * </pre>
2728 *
2729 * @param str the String to parse, may be null
2730 * @param separator String containing the String to be used as a delimiter,
2731 * {@code null} splits on whitespace
2732 * @param max the maximum number of elements to include in the returned
2733 * array. A zero or negative value implies no limit.
2734 * @return an array of parsed Strings, {@code null} if null String was input
2735 * @since 2.4
2736 */
2737 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
2738 return splitByWholeSeparatorWorker(str, separator, max, true);
2739 }
2740
2741 /**
2742 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
2743 *
2744 * @param str the String to parse, may be {@code null}
2745 * @param separator String containing the String to be used as a delimiter,
2746 * {@code null} splits on whitespace
2747 * @param max the maximum number of elements to include in the returned
2748 * array. A zero or negative value implies no limit.
2749 * @param preserveAllTokens if {@code true}, adjacent separators are
2750 * treated as empty token separators; if {@code false}, adjacent
2751 * separators are treated as one separator.
2752 * @return an array of parsed Strings, {@code null} if null String input
2753 * @since 2.4
2754 */
2755 private static String[] splitByWholeSeparatorWorker(
2756 String str, String separator, int max, boolean preserveAllTokens) {
2757 if (str == null) {
2758 return null;
2759 }
2760
2761 int len = str.length();
2762
2763 if (len == 0) {
2764 return ArrayUtils.EMPTY_STRING_ARRAY;
2765 }
2766
2767 if ((separator == null) || (EMPTY.equals(separator))) {
2768 // Split on whitespace.
2769 return splitWorker(str, null, max, preserveAllTokens);
2770 }
2771
2772 int separatorLength = separator.length();
2773
2774 ArrayList<String> substrings = new ArrayList<String>();
2775 int numberOfSubstrings = 0;
2776 int beg = 0;
2777 int end = 0;
2778 while (end < len) {
2779 end = str.indexOf(separator, beg);
2780
2781 if (end > -1) {
2782 if (end > beg) {
2783 numberOfSubstrings += 1;
2784
2785 if (numberOfSubstrings == max) {
2786 end = len;
2787 substrings.add(str.substring(beg));
2788 } else {
2789 // The following is OK, because String.substring( beg, end ) excludes
2790 // the character at the position 'end'.
2791 substrings.add(str.substring(beg, end));
2792
2793 // Set the starting point for the next search.
2794 // The following is equivalent to beg = end + (separatorLength - 1) + 1,
2795 // which is the right calculation:
2796 beg = end + separatorLength;
2797 }
2798 } else {
2799 // We found a consecutive occurrence of the separator, so skip it.
2800 if (preserveAllTokens) {
2801 numberOfSubstrings += 1;
2802 if (numberOfSubstrings == max) {
2803 end = len;
2804 substrings.add(str.substring(beg));
2805 } else {
2806 substrings.add(EMPTY);
2807 }
2808 }
2809 beg = end + separatorLength;
2810 }
2811 } else {
2812 // String.substring( beg ) goes from 'beg' to the end of the String.
2813 substrings.add(str.substring(beg));
2814 end = len;
2815 }
2816 }
2817
2818 return substrings.toArray(new String[substrings.size()]);
2819 }
2820
2821 // -----------------------------------------------------------------------
2822 /**
2823 * <p>Splits the provided text into an array, using whitespace as the
2824 * separator, preserving all tokens, including empty tokens created by
2825 * adjacent separators. This is an alternative to using StringTokenizer.
2826 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2827 *
2828 * <p>The separator is not included in the returned String array.
2829 * Adjacent separators are treated as separators for empty tokens.
2830 * For more control over the split use the StrTokenizer class.</p>
2831 *
2832 * <p>A {@code null} input String returns {@code null}.</p>
2833 *
2834 * <pre>
2835 * StringUtils.splitPreserveAllTokens(null) = null
2836 * StringUtils.splitPreserveAllTokens("") = []
2837 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
2838 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
2839 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
2840 * </pre>
2841 *
2842 * @param str the String to parse, may be {@code null}
2843 * @return an array of parsed Strings, {@code null} if null String input
2844 * @since 2.1
2845 */
2846 public static String[] splitPreserveAllTokens(String str) {
2847 return splitWorker(str, null, -1, true);
2848 }
2849
2850 /**
2851 * <p>Splits the provided text into an array, separator specified,
2852 * preserving all tokens, including empty tokens created by adjacent
2853 * separators. This is an alternative to using StringTokenizer.</p>
2854 *
2855 * <p>The separator is not included in the returned String array.
2856 * Adjacent separators are treated as separators for empty tokens.
2857 * For more control over the split use the StrTokenizer class.</p>
2858 *
2859 * <p>A {@code null} input String returns {@code null}.</p>
2860 *
2861 * <pre>
2862 * StringUtils.splitPreserveAllTokens(null, *) = null
2863 * StringUtils.splitPreserveAllTokens("", *) = []
2864 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
2865 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"]
2866 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
2867 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
2868 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
2869 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
2870 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
2871 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
2872 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
2873 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
2874 * </pre>
2875 *
2876 * @param str the String to parse, may be {@code null}
2877 * @param separatorChar the character used as the delimiter,
2878 * {@code null} splits on whitespace
2879 * @return an array of parsed Strings, {@code null} if null String input
2880 * @since 2.1
2881 */
2882 public static String[] splitPreserveAllTokens(String str, char separatorChar) {
2883 return splitWorker(str, separatorChar, true);
2884 }
2885
2886 /**
2887 * Performs the logic for the {@code split} and
2888 * {@code splitPreserveAllTokens} methods that do not return a
2889 * maximum array length.
2890 *
2891 * @param str the String to parse, may be {@code null}
2892 * @param separatorChar the separate character
2893 * @param preserveAllTokens if {@code true}, adjacent separators are
2894 * treated as empty token separators; if {@code false}, adjacent
2895 * separators are treated as one separator.
2896 * @return an array of parsed Strings, {@code null} if null String input
2897 */
2898 private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
2899 // Performance tuned for 2.0 (JDK1.4)
2900
2901 if (str == null) {
2902 return null;
2903 }
2904 int len = str.length();
2905 if (len == 0) {
2906 return ArrayUtils.EMPTY_STRING_ARRAY;
2907 }
2908 List<String> list = new ArrayList<String>();
2909 int i = 0, start = 0;
2910 boolean match = false;
2911 boolean lastMatch = false;
2912 while (i < len) {
2913 if (str.charAt(i) == separatorChar) {
2914 if (match || preserveAllTokens) {
2915 list.add(str.substring(start, i));
2916 match = false;
2917 lastMatch = true;
2918 }
2919 start = ++i;
2920 continue;
2921 }
2922 lastMatch = false;
2923 match = true;
2924 i++;
2925 }
2926 if (match || (preserveAllTokens && lastMatch)) {
2927 list.add(str.substring(start, i));
2928 }
2929 return list.toArray(new String[list.size()]);
2930 }
2931
2932 /**
2933 * <p>Splits the provided text into an array, separators specified,
2934 * preserving all tokens, including empty tokens created by adjacent
2935 * separators. This is an alternative to using StringTokenizer.</p>
2936 *
2937 * <p>The separator is not included in the returned String array.
2938 * Adjacent separators are treated as separators for empty tokens.
2939 * For more control over the split use the StrTokenizer class.</p>
2940 *
2941 * <p>A {@code null} input String returns {@code null}.
2942 * A {@code null} separatorChars splits on whitespace.</p>
2943 *
2944 * <pre>
2945 * StringUtils.splitPreserveAllTokens(null, *) = null
2946 * StringUtils.splitPreserveAllTokens("", *) = []
2947 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
2948 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
2949 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
2950 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2951 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
2952 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
2953 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
2954 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
2955 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
2956 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
2957 * </pre>
2958 *
2959 * @param str the String to parse, may be {@code null}
2960 * @param separatorChars the characters used as the delimiters,
2961 * {@code null} splits on whitespace
2962 * @return an array of parsed Strings, {@code null} if null String input
2963 * @since 2.1
2964 */
2965 public static String[] splitPreserveAllTokens(String str, String separatorChars) {
2966 return splitWorker(str, separatorChars, -1, true);
2967 }
2968
2969 /**
2970 * <p>Splits the provided text into an array with a maximum length,
2971 * separators specified, preserving all tokens, including empty tokens
2972 * created by adjacent separators.</p>
2973 *
2974 * <p>The separator is not included in the returned String array.
2975 * Adjacent separators are treated as separators for empty tokens.
2976 * Adjacent separators are treated as one separator.</p>
2977 *
2978 * <p>A {@code null} input String returns {@code null}.
2979 * A {@code null} separatorChars splits on whitespace.</p>
2980 *
2981 * <p>If more than {@code max} delimited substrings are found, the last
2982 * returned string includes all characters after the first {@code max - 1}
2983 * returned strings (including separator characters).</p>
2984 *
2985 * <pre>
2986 * StringUtils.splitPreserveAllTokens(null, *, *) = null
2987 * StringUtils.splitPreserveAllTokens("", *, *) = []
2988 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
2989 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
2990 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
2991 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2992 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
2993 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
2994 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
2995 * </pre>
2996 *
2997 * @param str the String to parse, may be {@code null}
2998 * @param separatorChars the characters used as the delimiters,
2999 * {@code null} splits on whitespace
3000 * @param max the maximum number of elements to include in the
3001 * array. A zero or negative value implies no limit
3002 * @return an array of parsed Strings, {@code null} if null String input
3003 * @since 2.1
3004 */
3005 public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
3006 return splitWorker(str, separatorChars, max, true);
3007 }
3008
3009 /**
3010 * Performs the logic for the {@code split} and
3011 * {@code splitPreserveAllTokens} methods that return a maximum array
3012 * length.
3013 *
3014 * @param str the String to parse, may be {@code null}
3015 * @param separatorChars the separate character
3016 * @param max the maximum number of elements to include in the
3017 * array. A zero or negative value implies no limit.
3018 * @param preserveAllTokens if {@code true}, adjacent separators are
3019 * treated as empty token separators; if {@code false}, adjacent
3020 * separators are treated as one separator.
3021 * @return an array of parsed Strings, {@code null} if null String input
3022 */
3023 private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
3024 // Performance tuned for 2.0 (JDK1.4)
3025 // Direct code is quicker than StringTokenizer.
3026 // Also, StringTokenizer uses isSpace() not isWhitespace()
3027
3028 if (str == null) {
3029 return null;
3030 }
3031 int len = str.length();
3032 if (len == 0) {
3033 return ArrayUtils.EMPTY_STRING_ARRAY;
3034 }
3035 List<String> list = new ArrayList<String>();
3036 int sizePlus1 = 1;
3037 int i = 0, start = 0;
3038 boolean match = false;
3039 boolean lastMatch = false;
3040 if (separatorChars == null) {
3041 // Null separator means use whitespace
3042 while (i < len) {
3043 if (Character.isWhitespace(str.charAt(i))) {
3044 if (match || preserveAllTokens) {
3045 lastMatch = true;
3046 if (sizePlus1++ == max) {
3047 i = len;
3048 lastMatch = false;
3049 }
3050 list.add(str.substring(start, i));
3051 match = false;
3052 }
3053 start = ++i;
3054 continue;
3055 }
3056 lastMatch = false;
3057 match = true;
3058 i++;
3059 }
3060 } else if (separatorChars.length() == 1) {
3061 // Optimise 1 character case
3062 char sep = separatorChars.charAt(0);
3063 while (i < len) {
3064 if (str.charAt(i) == sep) {
3065 if (match || preserveAllTokens) {
3066 lastMatch = true;
3067 if (sizePlus1++ == max) {
3068 i = len;
3069 lastMatch = false;
3070 }
3071 list.add(str.substring(start, i));
3072 match = false;
3073 }
3074 start = ++i;
3075 continue;
3076 }
3077 lastMatch = false;
3078 match = true;
3079 i++;
3080 }
3081 } else {
3082 // standard case
3083 while (i < len) {
3084 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3085 if (match || preserveAllTokens) {
3086 lastMatch = true;
3087 if (sizePlus1++ == max) {
3088 i = len;
3089 lastMatch = false;
3090 }
3091 list.add(str.substring(start, i));
3092 match = false;
3093 }
3094 start = ++i;
3095 continue;
3096 }
3097 lastMatch = false;
3098 match = true;
3099 i++;
3100 }
3101 }
3102 if (match || (preserveAllTokens && lastMatch)) {
3103 list.add(str.substring(start, i));
3104 }
3105 return list.toArray(new String[list.size()]);
3106 }
3107
3108 /**
3109 * <p>Splits a String by Character type as returned by
3110 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3111 * characters of the same type are returned as complete tokens.
3112 * <pre>
3113 * StringUtils.splitByCharacterType(null) = null
3114 * StringUtils.splitByCharacterType("") = []
3115 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3116 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3117 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3118 * StringUtils.splitByCharacterType("number5") = ["number", "5"]
3119 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"]
3120 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"]
3121 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
3122 * </pre>
3123 * @param str the String to split, may be {@code null}
3124 * @return an array of parsed Strings, {@code null} if null String input
3125 * @since 2.4
3126 */
3127 public static String[] splitByCharacterType(String str) {
3128 return splitByCharacterType(str, false);
3129 }
3130
3131 /**
3132 * <p>Splits a String by Character type as returned by
3133 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3134 * characters of the same type are returned as complete tokens, with the
3135 * following exception: the character of type
3136 * {@code Character.UPPERCASE_LETTER}, if any, immediately
3137 * preceding a token of type {@code Character.LOWERCASE_LETTER}
3138 * will belong to the following token rather than to the preceding, if any,
3139 * {@code Character.UPPERCASE_LETTER} token.
3140 * <pre>
3141 * StringUtils.splitByCharacterTypeCamelCase(null) = null
3142 * StringUtils.splitByCharacterTypeCamelCase("") = []
3143 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3144 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3145 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3146 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
3147 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
3148 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
3149 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
3150 * </pre>
3151 * @param str the String to split, may be {@code null}
3152 * @return an array of parsed Strings, {@code null} if null String input
3153 * @since 2.4
3154 */
3155 public static String[] splitByCharacterTypeCamelCase(String str) {
3156 return splitByCharacterType(str, true);
3157 }
3158
3159 /**
3160 * <p>Splits a String by Character type as returned by
3161 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3162 * characters of the same type are returned as complete tokens, with the
3163 * following exception: if {@code camelCase} is {@code true},
3164 * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3165 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3166 * will belong to the following token rather than to the preceding, if any,
3167 * {@code Character.UPPERCASE_LETTER} token.
3168 * @param str the String to split, may be {@code null}
3169 * @param camelCase whether to use so-called "camel-case" for letter types
3170 * @return an array of parsed Strings, {@code null} if null String input
3171 * @since 2.4
3172 */
3173 private static String[] splitByCharacterType(String str, boolean camelCase) {
3174 if (str == null) {
3175 return null;
3176 }
3177 if (str.length() == 0) {
3178 return ArrayUtils.EMPTY_STRING_ARRAY;
3179 }
3180 char[] c = str.toCharArray();
3181 List<String> list = new ArrayList<String>();
3182 int tokenStart = 0;
3183 int currentType = Character.getType(c[tokenStart]);
3184 for (int pos = tokenStart + 1; pos < c.length; pos++) {
3185 int type = Character.getType(c[pos]);
3186 if (type == currentType) {
3187 continue;
3188 }
3189 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3190 int newTokenStart = pos - 1;
3191 if (newTokenStart != tokenStart) {
3192 list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3193 tokenStart = newTokenStart;
3194 }
3195 } else {
3196 list.add(new String(c, tokenStart, pos - tokenStart));
3197 tokenStart = pos;
3198 }
3199 currentType = type;
3200 }
3201 list.add(new String(c, tokenStart, c.length - tokenStart));
3202 return list.toArray(new String[list.size()]);
3203 }
3204
3205 // Joining
3206 //-----------------------------------------------------------------------
3207 /**
3208 * <p>Joins the elements of the provided array into a single String
3209 * containing the provided list of elements.</p>
3210 *
3211 * <p>No separator is added to the joined String.
3212 * Null objects or empty strings within the array are represented by
3213 * empty strings.</p>
3214 *
3215 * <pre>
3216 * StringUtils.join(null) = null
3217 * StringUtils.join([]) = ""
3218 * StringUtils.join([null]) = ""
3219 * StringUtils.join(["a", "b", "c"]) = "abc"
3220 * StringUtils.join([null, "", "a"]) = "a"
3221 * </pre>
3222 *
3223 * @param <T> the specific type of values to join together
3224 * @param elements the values to join together, may be null
3225 * @return the joined String, {@code null} if null array input
3226 * @since 2.0
3227 * @since 3.0 Changed signature to use varargs
3228 */
3229 public static <T> String join(T... elements) {
3230 return join(elements, null);
3231 }
3232
3233 /**
3234 * <p>Joins the elements of the provided array into a single String
3235 * containing the provided list of elements.</p>
3236 *
3237 * <p>No delimiter is added before or after the list.
3238 * Null objects or empty strings within the array are represented by
3239 * empty strings.</p>
3240 *
3241 * <pre>
3242 * StringUtils.join(null, *) = null
3243 * StringUtils.join([], *) = ""
3244 * StringUtils.join([null], *) = ""
3245 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
3246 * StringUtils.join(["a", "b", "c"], null) = "abc"
3247 * StringUtils.join([null, "", "a"], ';') = ";;a"
3248 * </pre>
3249 *
3250 * @param array the array of values to join together, may be null
3251 * @param separator the separator character to use
3252 * @return the joined String, {@code null} if null array input
3253 * @since 2.0
3254 */
3255 public static String join(Object[] array, char separator) {
3256 if (array == null) {
3257 return null;
3258 }
3259
3260 return join(array, separator, 0, array.length);
3261 }
3262
3263 /**
3264 * <p>Joins the elements of the provided array into a single String
3265 * containing the provided list of elements.</p>
3266 *
3267 * <p>No delimiter is added before or after the list.
3268 * Null objects or empty strings within the array are represented by
3269 * empty strings.</p>
3270 *
3271 * <pre>
3272 * StringUtils.join(null, *) = null
3273 * StringUtils.join([], *) = ""
3274 * StringUtils.join([null], *) = ""
3275 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
3276 * StringUtils.join(["a", "b", "c"], null) = "abc"
3277 * StringUtils.join([null, "", "a"], ';') = ";;a"
3278 * </pre>
3279 *
3280 * @param array the array of values to join together, may be null
3281 * @param separator the separator character to use
3282 * @param startIndex the first index to start joining from. It is
3283 * an error to pass in an end index past the end of the array
3284 * @param endIndex the index to stop joining from (exclusive). It is
3285 * an error to pass in an end index past the end of the array
3286 * @return the joined String, {@code null} if null array input
3287 * @since 2.0
3288 */
3289 public static String join(Object[] array, char separator, int startIndex, int endIndex) {
3290 if (array == null) {
3291 return null;
3292 }
3293 int noOfItems = (endIndex - startIndex);
3294 if (noOfItems <= 0) {
3295 return EMPTY;
3296 }
3297
3298 StringBuilder buf = new StringBuilder(noOfItems * 16);
3299
3300 for (int i = startIndex; i < endIndex; i++) {
3301 if (i > startIndex) {
3302 buf.append(separator);
3303 }
3304 if (array[i] != null) {
3305 buf.append(array[i]);
3306 }
3307 }
3308 return buf.toString();
3309 }
3310
3311 /**
3312 * <p>Joins the elements of the provided array into a single String
3313 * containing the provided list of elements.</p>
3314 *
3315 * <p>No delimiter is added before or after the list.
3316 * A {@code null} separator is the same as an empty String ("").
3317 * Null objects or empty strings within the array are represented by
3318 * empty strings.</p>
3319 *
3320 * <pre>
3321 * StringUtils.join(null, *) = null
3322 * StringUtils.join([], *) = ""
3323 * StringUtils.join([null], *) = ""
3324 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
3325 * StringUtils.join(["a", "b", "c"], null) = "abc"
3326 * StringUtils.join(["a", "b", "c"], "") = "abc"
3327 * StringUtils.join([null, "", "a"], ',') = ",,a"
3328 * </pre>
3329 *
3330 * @param array the array of values to join together, may be null
3331 * @param separator the separator character to use, null treated as ""
3332 * @return the joined String, {@code null} if null array input
3333 */
3334 public static String join(Object[] array, String separator) {
3335 if (array == null) {
3336 return null;
3337 }
3338 return join(array, separator, 0, array.length);
3339 }
3340
3341 /**
3342 * <p>Joins the elements of the provided array into a single String
3343 * containing the provided list of elements.</p>
3344 *
3345 * <p>No delimiter is added before or after the list.
3346 * A {@code null} separator is the same as an empty String ("").
3347 * Null objects or empty strings within the array are represented by
3348 * empty strings.</p>
3349 *
3350 * <pre>
3351 * StringUtils.join(null, *) = null
3352 * StringUtils.join([], *) = ""
3353 * StringUtils.join([null], *) = ""
3354 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
3355 * StringUtils.join(["a", "b", "c"], null) = "abc"
3356 * StringUtils.join(["a", "b", "c"], "") = "abc"
3357 * StringUtils.join([null, "", "a"], ',') = ",,a"
3358 * </pre>
3359 *
3360 * @param array the array of values to join together, may be null
3361 * @param separator the separator character to use, null treated as ""
3362 * @param startIndex the first index to start joining from. It is
3363 * an error to pass in an end index past the end of the array
3364 * @param endIndex the index to stop joining from (exclusive). It is
3365 * an error to pass in an end index past the end of the array
3366 * @return the joined String, {@code null} if null array input
3367 */
3368 public static String join(Object[] array, String separator, int startIndex, int endIndex) {
3369 if (array == null) {
3370 return null;
3371 }
3372 if (separator == null) {
3373 separator = EMPTY;
3374 }
3375
3376 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
3377 // (Assuming that all Strings are roughly equally long)
3378 int noOfItems = (endIndex - startIndex);
3379 if (noOfItems <= 0) {
3380 return EMPTY;
3381 }
3382
3383 StringBuilder buf = new StringBuilder(noOfItems * 16);
3384
3385 for (int i = startIndex; i < endIndex; i++) {
3386 if (i > startIndex) {
3387 buf.append(separator);
3388 }
3389 if (array[i] != null) {
3390 buf.append(array[i]);
3391 }
3392 }
3393 return buf.toString();
3394 }
3395
3396 /**
3397 * <p>Joins the elements of the provided {@code Iterator} into
3398 * a single String containing the provided elements.</p>
3399 *
3400 * <p>No delimiter is added before or after the list. Null objects or empty
3401 * strings within the iteration are represented by empty strings.</p>
3402 *
3403 * <p>See the examples here: {@link #join(Object[],char)}. </p>
3404 *
3405 * @param iterator the {@code Iterator} of values to join together, may be null
3406 * @param separator the separator character to use
3407 * @return the joined String, {@code null} if null iterator input
3408 * @since 2.0
3409 */
3410 public static String join(Iterator<?> iterator, char separator) {
3411
3412 // handle null, zero and one elements before building a buffer
3413 if (iterator == null) {
3414 return null;
3415 }
3416 if (!iterator.hasNext()) {
3417 return EMPTY;
3418 }
3419 Object first = iterator.next();
3420 if (!iterator.hasNext()) {
3421 return ObjectUtils.toString(first);
3422 }
3423
3424 // two or more elements
3425 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
3426 if (first != null) {
3427 buf.append(first);
3428 }
3429
3430 while (iterator.hasNext()) {
3431 buf.append(separator);
3432 Object obj = iterator.next();
3433 if (obj != null) {
3434 buf.append(obj);
3435 }
3436 }
3437
3438 return buf.toString();
3439 }
3440
3441 /**
3442 * <p>Joins the elements of the provided {@code Iterator} into
3443 * a single String containing the provided elements.</p>
3444 *
3445 * <p>No delimiter is added before or after the list.
3446 * A {@code null} separator is the same as an empty String ("").</p>
3447 *
3448 * <p>See the examples here: {@link #join(Object[],String)}. </p>
3449 *
3450 * @param iterator the {@code Iterator} of values to join together, may be null
3451 * @param separator the separator character to use, null treated as ""
3452 * @return the joined String, {@code null} if null iterator input
3453 */
3454 public static String join(Iterator<?> iterator, String separator) {
3455
3456 // handle null, zero and one elements before building a buffer
3457 if (iterator == null) {
3458 return null;
3459 }
3460 if (!iterator.hasNext()) {
3461 return EMPTY;
3462 }
3463 Object first = iterator.next();
3464 if (!iterator.hasNext()) {
3465 return ObjectUtils.toString(first);
3466 }
3467
3468 // two or more elements
3469 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
3470 if (first != null) {
3471 buf.append(first);
3472 }
3473
3474 while (iterator.hasNext()) {
3475 if (separator != null) {
3476 buf.append(separator);
3477 }
3478 Object obj = iterator.next();
3479 if (obj != null) {
3480 buf.append(obj);
3481 }
3482 }
3483 return buf.toString();
3484 }
3485
3486 /**
3487 * <p>Joins the elements of the provided {@code Iterable} into
3488 * a single String containing the provided elements.</p>
3489 *
3490 * <p>No delimiter is added before or after the list. Null objects or empty
3491 * strings within the iteration are represented by empty strings.</p>
3492 *
3493 * <p>See the examples here: {@link #join(Object[],char)}. </p>
3494 *
3495 * @param iterable the {@code Iterable} providing the values to join together, may be null
3496 * @param separator the separator character to use
3497 * @return the joined String, {@code null} if null iterator input
3498 * @since 2.3
3499 */
3500 public static String join(Iterable<?> iterable, char separator) {
3501 if (iterable == null) {
3502 return null;
3503 }
3504 return join(iterable.iterator(), separator);
3505 }
3506
3507 /**
3508 * <p>Joins the elements of the provided {@code Iterable} into
3509 * a single String containing the provided elements.</p>
3510 *
3511 * <p>No delimiter is added before or after the list.
3512 * A {@code null} separator is the same as an empty String ("").</p>
3513 *
3514 * <p>See the examples here: {@link #join(Object[],String)}. </p>
3515 *
3516 * @param iterable the {@code Iterable} providing the values to join together, may be null
3517 * @param separator the separator character to use, null treated as ""
3518 * @return the joined String, {@code null} if null iterator input
3519 * @since 2.3
3520 */
3521 public static String join(Iterable<?> iterable, String separator) {
3522 if (iterable == null) {
3523 return null;
3524 }
3525 return join(iterable.iterator(), separator);
3526 }
3527
3528 // Delete
3529 //-----------------------------------------------------------------------
3530 /**
3531 * <p>Deletes all whitespaces from a String as defined by
3532 * {@link Character#isWhitespace(char)}.</p>
3533 *
3534 * <pre>
3535 * StringUtils.deleteWhitespace(null) = null
3536 * StringUtils.deleteWhitespace("") = ""
3537 * StringUtils.deleteWhitespace("abc") = "abc"
3538 * StringUtils.deleteWhitespace(" ab c ") = "abc"
3539 * </pre>
3540 *
3541 * @param str the String to delete whitespace from, may be null
3542 * @return the String without whitespaces, {@code null} if null String input
3543 */
3544 public static String deleteWhitespace(String str) {
3545 if (isEmpty(str)) {
3546 return str;
3547 }
3548 int sz = str.length();
3549 char[] chs = new char[sz];
3550 int count = 0;
3551 for (int i = 0; i < sz; i++) {
3552 if (!Character.isWhitespace(str.charAt(i))) {
3553 chs[count++] = str.charAt(i);
3554 }
3555 }
3556 if (count == sz) {
3557 return str;
3558 }
3559 return new String(chs, 0, count);
3560 }
3561
3562 // Remove
3563 //-----------------------------------------------------------------------
3564 /**
3565 * <p>Removes a substring only if it is at the beginning of a source string,
3566 * otherwise returns the source string.</p>
3567 *
3568 * <p>A {@code null} source string will return {@code null}.
3569 * An empty ("") source string will return the empty string.
3570 * A {@code null} search string will return the source string.</p>
3571 *
3572 * <pre>
3573 * StringUtils.removeStart(null, *) = null
3574 * StringUtils.removeStart("", *) = ""
3575 * StringUtils.removeStart(*, null) = *
3576 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
3577 * StringUtils.removeStart("domain.com", "www.") = "domain.com"
3578 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
3579 * StringUtils.removeStart("abc", "") = "abc"
3580 * </pre>
3581 *
3582 * @param str the source String to search, may be null
3583 * @param remove the String to search for and remove, may be null
3584 * @return the substring with the string removed if found,
3585 * {@code null} if null String input
3586 * @since 2.1
3587 */
3588 public static String removeStart(String str, String remove) {
3589 if (isEmpty(str) || isEmpty(remove)) {
3590 return str;
3591 }
3592 if (str.startsWith(remove)){
3593 return str.substring(remove.length());
3594 }
3595 return str;
3596 }
3597
3598 /**
3599 * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
3600 * otherwise returns the source string.</p>
3601 *
3602 * <p>A {@code null} source string will return {@code null}.
3603 * An empty ("") source string will return the empty string.
3604 * A {@code null} search string will return the source string.</p>
3605 *
3606 * <pre>
3607 * StringUtils.removeStartIgnoreCase(null, *) = null
3608 * StringUtils.removeStartIgnoreCase("", *) = ""
3609 * StringUtils.removeStartIgnoreCase(*, null) = *
3610 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
3611 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
3612 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
3613 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
3614 * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
3615 * </pre>
3616 *
3617 * @param str the source String to search, may be null
3618 * @param remove the String to search for (case insensitive) and remove, may be null
3619 * @return the substring with the string removed if found,
3620 * {@code null} if null String input
3621 * @since 2.4
3622 */
3623 public static String removeStartIgnoreCase(String str, String remove) {
3624 if (isEmpty(str) || isEmpty(remove)) {
3625 return str;
3626 }
3627 if (startsWithIgnoreCase(str, remove)) {
3628 return str.substring(remove.length());
3629 }
3630 return str;
3631 }
3632
3633 /**
3634 * <p>Removes a substring only if it is at the end of a source string,
3635 * otherwise returns the source string.</p>
3636 *
3637 * <p>A {@code null} source string will return {@code null}.
3638 * An empty ("") source string will return the empty string.
3639 * A {@code null} search string will return the source string.</p>
3640 *
3641 * <pre>
3642 * StringUtils.removeEnd(null, *) = null
3643 * StringUtils.removeEnd("", *) = ""
3644 * StringUtils.removeEnd(*, null) = *
3645 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
3646 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
3647 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
3648 * StringUtils.removeEnd("abc", "") = "abc"
3649 * </pre>
3650 *
3651 * @param str the source String to search, may be null
3652 * @param remove the String to search for and remove, may be null
3653 * @return the substring with the string removed if found,
3654 * {@code null} if null String input
3655 * @since 2.1
3656 */
3657 public static String removeEnd(String str, String remove) {
3658 if (isEmpty(str) || isEmpty(remove)) {
3659 return str;
3660 }
3661 if (str.endsWith(remove)) {
3662 return str.substring(0, str.length() - remove.length());
3663 }
3664 return str;
3665 }
3666
3667 /**
3668 * <p>Case insensitive removal of a substring if it is at the end of a source string,
3669 * otherwise returns the source string.</p>
3670 *
3671 * <p>A {@code null} source string will return {@code null}.
3672 * An empty ("") source string will return the empty string.
3673 * A {@code null} search string will return the source string.</p>
3674 *
3675 * <pre>
3676 * StringUtils.removeEndIgnoreCase(null, *) = null
3677 * StringUtils.removeEndIgnoreCase("", *) = ""
3678 * StringUtils.removeEndIgnoreCase(*, null) = *
3679 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
3680 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
3681 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
3682 * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
3683 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
3684 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
3685 * </pre>
3686 *
3687 * @param str the source String to search, may be null
3688 * @param remove the String to search for (case insensitive) and remove, may be null
3689 * @return the substring with the string removed if found,
3690 * {@code null} if null String input
3691 * @since 2.4
3692 */
3693 public static String removeEndIgnoreCase(String str, String remove) {
3694 if (isEmpty(str) || isEmpty(remove)) {
3695 return str;
3696 }
3697 if (endsWithIgnoreCase(str, remove)) {
3698 return str.substring(0, str.length() - remove.length());
3699 }
3700 return str;
3701 }
3702
3703 /**
3704 * <p>Removes all occurrences of a substring from within the source string.</p>
3705 *
3706 * <p>A {@code null} source string will return {@code null}.
3707 * An empty ("") source string will return the empty string.
3708 * A {@code null} remove string will return the source string.
3709 * An empty ("") remove string will return the source string.</p>
3710 *
3711 * <pre>
3712 * StringUtils.remove(null, *) = null
3713 * StringUtils.remove("", *) = ""
3714 * StringUtils.remove(*, null) = *
3715 * StringUtils.remove(*, "") = *
3716 * StringUtils.remove("queued", "ue") = "qd"
3717 * StringUtils.remove("queued", "zz") = "queued"
3718 * </pre>
3719 *
3720 * @param str the source String to search, may be null
3721 * @param remove the String to search for and remove, may be null
3722 * @return the substring with the string removed if found,
3723 * {@code null} if null String input
3724 * @since 2.1
3725 */
3726 public static String remove(String str, String remove) {
3727 if (isEmpty(str) || isEmpty(remove)) {
3728 return str;
3729 }
3730 return replace(str, remove, EMPTY, -1);
3731 }
3732
3733 /**
3734 * <p>Removes all occurrences of a character from within the source string.</p>
3735 *
3736 * <p>A {@code null} source string will return {@code null}.
3737 * An empty ("") source string will return the empty string.</p>
3738 *
3739 * <pre>
3740 * StringUtils.remove(null, *) = null
3741 * StringUtils.remove("", *) = ""
3742 * StringUtils.remove("queued", 'u') = "qeed"
3743 * StringUtils.remove("queued", 'z') = "queued"
3744 * </pre>
3745 *
3746 * @param str the source String to search, may be null
3747 * @param remove the char to search for and remove, may be null
3748 * @return the substring with the char removed if found,
3749 * {@code null} if null String input
3750 * @since 2.1
3751 */
3752 public static String remove(String str, char remove) {
3753 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
3754 return str;
3755 }
3756 char[] chars = str.toCharArray();
3757 int pos = 0;
3758 for (int i = 0; i < chars.length; i++) {
3759 if (chars[i] != remove) {
3760 chars[pos++] = chars[i];
3761 }
3762 }
3763 return new String(chars, 0, pos);
3764 }
3765
3766 // Replacing
3767 //-----------------------------------------------------------------------
3768 /**
3769 * <p>Replaces a String with another String inside a larger String, once.</p>
3770 *
3771 * <p>A {@code null} reference passed to this method is a no-op.</p>
3772 *
3773 * <pre>
3774 * StringUtils.replaceOnce(null, *, *) = null
3775 * StringUtils.replaceOnce("", *, *) = ""
3776 * StringUtils.replaceOnce("any", null, *) = "any"
3777 * StringUtils.replaceOnce("any", *, null) = "any"
3778 * StringUtils.replaceOnce("any", "", *) = "any"
3779 * StringUtils.replaceOnce("aba", "a", null) = "aba"
3780 * StringUtils.replaceOnce("aba", "a", "") = "ba"
3781 * StringUtils.replaceOnce("aba", "a", "z") = "zba"
3782 * </pre>
3783 *
3784 * @see #replace(String text, String searchString, String replacement, int max)
3785 * @param text text to search and replace in, may be null
3786 * @param searchString the String to search for, may be null
3787 * @param replacement the String to replace with, may be null
3788 * @return the text with any replacements processed,
3789 * {@code null} if null String input
3790 */
3791 public static String replaceOnce(String text, String searchString, String replacement) {
3792 return replace(text, searchString, replacement, 1);
3793 }
3794
3795 /**
3796 * <p>Replaces all occurrences of a String within another String.</p>
3797 *
3798 * <p>A {@code null} reference passed to this method is a no-op.</p>
3799 *
3800 * <pre>
3801 * StringUtils.replace(null, *, *) = null
3802 * StringUtils.replace("", *, *) = ""
3803 * StringUtils.replace("any", null, *) = "any"
3804 * StringUtils.replace("any", *, null) = "any"
3805 * StringUtils.replace("any", "", *) = "any"
3806 * StringUtils.replace("aba", "a", null) = "aba"
3807 * StringUtils.replace("aba", "a", "") = "b"
3808 * StringUtils.replace("aba", "a", "z") = "zbz"
3809 * </pre>
3810 *
3811 * @see #replace(String text, String searchString, String replacement, int max)
3812 * @param text text to search and replace in, may be null
3813 * @param searchString the String to search for, may be null
3814 * @param replacement the String to replace it with, may be null
3815 * @return the text with any replacements processed,
3816 * {@code null} if null String input
3817 */
3818 public static String replace(String text, String searchString, String replacement) {
3819 return replace(text, searchString, replacement, -1);
3820 }
3821
3822 /**
3823 * <p>Replaces a String with another String inside a larger String,
3824 * for the first {@code max} values of the search String.</p>
3825 *
3826 * <p>A {@code null} reference passed to this method is a no-op.</p>
3827 *
3828 * <pre>
3829 * StringUtils.replace(null, *, *, *) = null
3830 * StringUtils.replace("", *, *, *) = ""
3831 * StringUtils.replace("any", null, *, *) = "any"
3832 * StringUtils.replace("any", *, null, *) = "any"
3833 * StringUtils.replace("any", "", *, *) = "any"
3834 * StringUtils.replace("any", *, *, 0) = "any"
3835 * StringUtils.replace("abaa", "a", null, -1) = "abaa"
3836 * StringUtils.replace("abaa", "a", "", -1) = "b"
3837 * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
3838 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
3839 * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
3840 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
3841 * </pre>
3842 *
3843 * @param text text to search and replace in, may be null
3844 * @param searchString the String to search for, may be null
3845 * @param replacement the String to replace it with, may be null
3846 * @param max maximum number of values to replace, or {@code -1} if no maximum
3847 * @return the text with any replacements processed,
3848 * {@code null} if null String input
3849 */
3850 public static String replace(String text, String searchString, String replacement, int max) {
3851 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
3852 return text;
3853 }
3854 int start = 0;
3855 int end = text.indexOf(searchString, start);
3856 if (end == INDEX_NOT_FOUND) {
3857 return text;
3858 }
3859 int replLength = searchString.length();
3860 int increase = replacement.length() - replLength;
3861 increase = (increase < 0 ? 0 : increase);
3862 increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
3863 StringBuilder buf = new StringBuilder(text.length() + increase);
3864 while (end != INDEX_NOT_FOUND) {
3865 buf.append(text.substring(start, end)).append(replacement);
3866 start = end + replLength;
3867 if (--max == 0) {
3868 break;
3869 }
3870 end = text.indexOf(searchString, start);
3871 }
3872 buf.append(text.substring(start));
3873 return buf.toString();
3874 }
3875
3876 /**
3877 * <p>
3878 * Replaces all occurrences of Strings within another String.
3879 * </p>
3880 *
3881 * <p>
3882 * A {@code null} reference passed to this method is a no-op, or if
3883 * any "search string" or "string to replace" is null, that replace will be
3884 * ignored. This will not repeat. For repeating replaces, call the
3885 * overloaded method.
3886 * </p>
3887 *
3888 * <pre>
3889 * StringUtils.replaceEach(null, *, *) = null
3890 * StringUtils.replaceEach("", *, *) = ""
3891 * StringUtils.replaceEach("aba", null, null) = "aba"
3892 * StringUtils.replaceEach("aba", new String[0], null) = "aba"
3893 * StringUtils.replaceEach("aba", null, new String[0]) = "aba"
3894 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
3895 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
3896 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
3897 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
3898 * (example of how it does not repeat)
3899 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
3900 * </pre>
3901 *
3902 * @param text
3903 * text to search and replace in, no-op if null
3904 * @param searchList
3905 * the Strings to search for, no-op if null
3906 * @param replacementList
3907 * the Strings to replace them with, no-op if null
3908 * @return the text with any replacements processed, {@code null} if
3909 * null String input
3910 * @throws IllegalArgumentException
3911 * if the lengths of the arrays are not the same (null is ok,
3912 * and/or size 0)
3913 * @since 2.4
3914 */
3915 public static String replaceEach(String text, String[] searchList, String[] replacementList) {
3916 return replaceEach(text, searchList, replacementList, false, 0);
3917 }
3918
3919 /**
3920 * <p>
3921 * Replaces all occurrences of Strings within another String.
3922 * </p>
3923 *
3924 * <p>
3925 * A {@code null} reference passed to this method is a no-op, or if
3926 * any "search string" or "string to replace" is null, that replace will be
3927 * ignored.
3928 * </p>
3929 *
3930 * <pre>
3931 * StringUtils.replaceEach(null, *, *, *) = null
3932 * StringUtils.replaceEach("", *, *, *) = ""
3933 * StringUtils.replaceEach("aba", null, null, *) = "aba"
3934 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
3935 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
3936 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
3937 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
3938 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
3939 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
3940 * (example of how it repeats)
3941 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
3942 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
3943 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalStateException
3944 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe"
3945 * </pre>
3946 *
3947 * @param text
3948 * text to search and replace in, no-op if null
3949 * @param searchList
3950 * the Strings to search for, no-op if null
3951 * @param replacementList
3952 * the Strings to replace them with, no-op if null
3953 * @return the text with any replacements processed, {@code null} if
3954 * null String input
3955 * @throws IllegalStateException
3956 * if the search is repeating and there is an endless loop due
3957 * to outputs of one being inputs to another
3958 * @throws IllegalArgumentException
3959 * if the lengths of the arrays are not the same (null is ok,
3960 * and/or size 0)
3961 * @since 2.4
3962 */
3963 public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
3964 // timeToLive should be 0 if not used or nothing to replace, else it's
3965 // the length of the replace array
3966 int timeToLive = searchList == null ? 0 : searchList.length;
3967 return replaceEach(text, searchList, replacementList, true, timeToLive);
3968 }
3969
3970 /**
3971 * <p>
3972 * Replaces all occurrences of Strings within another String.
3973 * </p>
3974 *
3975 * <p>
3976 * A {@code null} reference passed to this method is a no-op, or if
3977 * any "search string" or "string to replace" is null, that replace will be
3978 * ignored.
3979 * </p>
3980 *
3981 * <pre>
3982 * StringUtils.replaceEach(null, *, *, *) = null
3983 * StringUtils.replaceEach("", *, *, *) = ""
3984 * StringUtils.replaceEach("aba", null, null, *) = "aba"
3985 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
3986 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
3987 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
3988 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
3989 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
3990 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
3991 * (example of how it repeats)
3992 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
3993 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
3994 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
3995 * </pre>
3996 *
3997 * @param text
3998 * text to search and replace in, no-op if null
3999 * @param searchList
4000 * the Strings to search for, no-op if null
4001 * @param replacementList
4002 * the Strings to replace them with, no-op if null
4003 * @param repeat if true, then replace repeatedly
4004 * until there are no more possible replacements or timeToLive < 0
4005 * @param timeToLive
4006 * if less than 0 then there is a circular reference and endless
4007 * loop
4008 * @return the text with any replacements processed, {@code null} if
4009 * null String input
4010 * @throws IllegalStateException
4011 * if the search is repeating and there is an endless loop due
4012 * to outputs of one being inputs to another
4013 * @throws IllegalArgumentException
4014 * if the lengths of the arrays are not the same (null is ok,
4015 * and/or size 0)
4016 * @since 2.4
4017 */
4018 private static String replaceEach(
4019 String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) {
4020
4021 // mchyzer Performance note: This creates very few new objects (one major goal)
4022 // let me know if there are performance requests, we can create a harness to measure
4023
4024 if (text == null || text.length() == 0 || searchList == null ||
4025 searchList.length == 0 || replacementList == null || replacementList.length == 0) {
4026 return text;
4027 }
4028
4029 // if recursing, this shouldn't be less than 0
4030 if (timeToLive < 0) {
4031 throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
4032 "output of one loop is the input of another");
4033 }
4034
4035 int searchLength = searchList.length;
4036 int replacementLength = replacementList.length;
4037
4038 // make sure lengths are ok, these need to be equal
4039 if (searchLength != replacementLength) {
4040 throw new IllegalArgumentException("Search and Replace array lengths don't match: "
4041 + searchLength
4042 + " vs "
4043 + replacementLength);
4044 }
4045
4046 // keep track of which still have matches
4047 boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
4048
4049 // index on index that the match was found
4050 int textIndex = -1;
4051 int replaceIndex = -1;
4052 int tempIndex = -1;
4053
4054 // index of replace array that will replace the search string found
4055 // NOTE: logic duplicated below START
4056 for (int i = 0; i < searchLength; i++) {
4057 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
4058 searchList[i].length() == 0 || replacementList[i] == null) {
4059 continue;
4060 }
4061 tempIndex = text.indexOf(searchList[i]);
4062
4063 // see if we need to keep searching for this
4064 if (tempIndex == -1) {
4065 noMoreMatchesForReplIndex[i] = true;
4066 } else {
4067 if (textIndex == -1 || tempIndex < textIndex) {
4068 textIndex = tempIndex;
4069 replaceIndex = i;
4070 }
4071 }
4072 }
4073 // NOTE: logic mostly below END
4074
4075 // no search strings found, we are done
4076 if (textIndex == -1) {
4077 return text;
4078 }
4079
4080 int start = 0;
4081
4082 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
4083 int increase = 0;
4084
4085 // count the replacement text elements that are larger than their corresponding text being replaced
4086 for (int i = 0; i < searchList.length; i++) {
4087 if (searchList[i] == null || replacementList[i] == null) {
4088 continue;
4089 }
4090 int greater = replacementList[i].length() - searchList[i].length();
4091 if (greater > 0) {
4092 increase += 3 * greater; // assume 3 matches
4093 }
4094 }
4095 // have upper-bound at 20% increase, then let Java take over
4096 increase = Math.min(increase, text.length() / 5);
4097
4098 StringBuilder buf = new StringBuilder(text.length() + increase);
4099
4100 while (textIndex != -1) {
4101
4102 for (int i = start; i < textIndex; i++) {
4103 buf.append(text.charAt(i));
4104 }
4105 buf.append(replacementList[replaceIndex]);
4106
4107 start = textIndex + searchList[replaceIndex].length();
4108
4109 textIndex = -1;
4110 replaceIndex = -1;
4111 tempIndex = -1;
4112 // find the next earliest match
4113 // NOTE: logic mostly duplicated above START
4114 for (int i = 0; i < searchLength; i++) {
4115 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
4116 searchList[i].length() == 0 || replacementList[i] == null) {
4117 continue;
4118 }
4119 tempIndex = text.indexOf(searchList[i], start);
4120
4121 // see if we need to keep searching for this
4122 if (tempIndex == -1) {
4123 noMoreMatchesForReplIndex[i] = true;
4124 } else {
4125 if (textIndex == -1 || tempIndex < textIndex) {
4126 textIndex = tempIndex;
4127 replaceIndex = i;
4128 }
4129 }
4130 }
4131 // NOTE: logic duplicated above END
4132
4133 }
4134 int textLength = text.length();
4135 for (int i = start; i < textLength; i++) {
4136 buf.append(text.charAt(i));
4137 }
4138 String result = buf.toString();
4139 if (!repeat) {
4140 return result;
4141 }
4142
4143 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
4144 }
4145
4146 // Replace, character based
4147 //-----------------------------------------------------------------------
4148 /**
4149 * <p>Replaces all occurrences of a character in a String with another.
4150 * This is a null-safe version of {@link String#replace(char, char)}.</p>
4151 *
4152 * <p>A {@code null} string input returns {@code null}.
4153 * An empty ("") string input returns an empty string.</p>
4154 *
4155 * <pre>
4156 * StringUtils.replaceChars(null, *, *) = null
4157 * StringUtils.replaceChars("", *, *) = ""
4158 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
4159 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
4160 * </pre>
4161 *
4162 * @param str String to replace characters in, may be null
4163 * @param searchChar the character to search for, may be null
4164 * @param replaceChar the character to replace, may be null
4165 * @return modified String, {@code null} if null string input
4166 * @since 2.0
4167 */
4168 public static String replaceChars(String str, char searchChar, char replaceChar) {
4169 if (str == null) {
4170 return null;
4171 }
4172 return str.replace(searchChar, replaceChar);
4173 }
4174
4175 /**
4176 * <p>Replaces multiple characters in a String in one go.
4177 * This method can also be used to delete characters.</p>
4178 *
4179 * <p>For example:<br />
4180 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p>
4181 *
4182 * <p>A {@code null} string input returns {@code null}.
4183 * An empty ("") string input returns an empty string.
4184 * A null or empty set of search characters returns the input string.</p>
4185 *
4186 * <p>The length of the search characters should normally equal the length
4187 * of the replace characters.
4188 * If the search characters is longer, then the extra search characters
4189 * are deleted.
4190 * If the search characters is shorter, then the extra replace characters
4191 * are ignored.</p>
4192 *
4193 * <pre>
4194 * StringUtils.replaceChars(null, *, *) = null
4195 * StringUtils.replaceChars("", *, *) = ""
4196 * StringUtils.replaceChars("abc", null, *) = "abc"
4197 * StringUtils.replaceChars("abc", "", *) = "abc"
4198 * StringUtils.replaceChars("abc", "b", null) = "ac"
4199 * StringUtils.replaceChars("abc", "b", "") = "ac"
4200 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya"
4201 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya"
4202 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
4203 * </pre>
4204 *
4205 * @param str String to replace characters in, may be null
4206 * @param searchChars a set of characters to search for, may be null
4207 * @param replaceChars a set of characters to replace, may be null
4208 * @return modified String, {@code null} if null string input
4209 * @since 2.0
4210 */
4211 public static String replaceChars(String str, String searchChars, String replaceChars) {
4212 if (isEmpty(str) || isEmpty(searchChars)) {
4213 return str;
4214 }
4215 if (replaceChars == null) {
4216 replaceChars = EMPTY;
4217 }
4218 boolean modified = false;
4219 int replaceCharsLength = replaceChars.length();
4220 int strLength = str.length();
4221 StringBuilder buf = new StringBuilder(strLength);
4222 for (int i = 0; i < strLength; i++) {
4223 char ch = str.charAt(i);
4224 int index = searchChars.indexOf(ch);
4225 if (index >= 0) {
4226 modified = true;
4227 if (index < replaceCharsLength) {
4228 buf.append(replaceChars.charAt(index));
4229 }
4230 } else {
4231 buf.append(ch);
4232 }
4233 }
4234 if (modified) {
4235 return buf.toString();
4236 }
4237 return str;
4238 }
4239
4240 // Overlay
4241 //-----------------------------------------------------------------------
4242 /**
4243 * <p>Overlays part of a String with another String.</p>
4244 *
4245 * <p>A {@code null} string input returns {@code null}.
4246 * A negative index is treated as zero.
4247 * An index greater than the string length is treated as the string length.
4248 * The start index is always the smaller of the two indices.</p>
4249 *
4250 * <pre>
4251 * StringUtils.overlay(null, *, *, *) = null
4252 * StringUtils.overlay("", "abc", 0, 0) = "abc"
4253 * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
4254 * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
4255 * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
4256 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
4257 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
4258 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
4259 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
4260 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
4261 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
4262 * </pre>
4263 *
4264 * @param str the String to do overlaying in, may be null
4265 * @param overlay the String to overlay, may be null
4266 * @param start the position to start overlaying at
4267 * @param end the position to stop overlaying before
4268 * @return overlayed String, {@code null} if null String input
4269 * @since 2.0
4270 */
4271 public static String overlay(String str, String overlay, int start, int end) {
4272 if (str == null) {
4273 return null;
4274 }
4275 if (overlay == null) {
4276 overlay = EMPTY;
4277 }
4278 int len = str.length();
4279 if (start < 0) {
4280 start = 0;
4281 }
4282 if (start > len) {
4283 start = len;
4284 }
4285 if (end < 0) {
4286 end = 0;
4287 }
4288 if (end > len) {
4289 end = len;
4290 }
4291 if (start > end) {
4292 int temp = start;
4293 start = end;
4294 end = temp;
4295 }
4296 return new StringBuilder(len + start - end + overlay.length() + 1)
4297 .append(str.substring(0, start))
4298 .append(overlay)
4299 .append(str.substring(end))
4300 .toString();
4301 }
4302
4303 // Chomping
4304 //-----------------------------------------------------------------------
4305 /**
4306 * <p>Removes one newline from end of a String if it's there,
4307 * otherwise leave it alone. A newline is "{@code \n}",
4308 * "{@code \r}", or "{@code \r\n}".</p>
4309 *
4310 * <p>NOTE: This method changed in 2.0.
4311 * It now more closely matches Perl chomp.</p>
4312 *
4313 * <pre>
4314 * StringUtils.chomp(null) = null
4315 * StringUtils.chomp("") = ""
4316 * StringUtils.chomp("abc \r") = "abc "
4317 * StringUtils.chomp("abc\n") = "abc"
4318 * StringUtils.chomp("abc\r\n") = "abc"
4319 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
4320 * StringUtils.chomp("abc\n\r") = "abc\n"
4321 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
4322 * StringUtils.chomp("\r") = ""
4323 * StringUtils.chomp("\n") = ""
4324 * StringUtils.chomp("\r\n") = ""
4325 * </pre>
4326 *
4327 * @param str the String to chomp a newline from, may be null
4328 * @return String without newline, {@code null} if null String input
4329 */
4330 public static String chomp(String str) {
4331 if (isEmpty(str)) {
4332 return str;
4333 }
4334
4335 if (str.length() == 1) {
4336 char ch = str.charAt(0);
4337 if (ch == CharUtils.CR || ch == CharUtils.LF) {
4338 return EMPTY;
4339 }
4340 return str;
4341 }
4342
4343 int lastIdx = str.length() - 1;
4344 char last = str.charAt(lastIdx);
4345
4346 if (last == CharUtils.LF) {
4347 if (str.charAt(lastIdx - 1) == CharUtils.CR) {
4348 lastIdx--;
4349 }
4350 } else if (last != CharUtils.CR) {
4351 lastIdx++;
4352 }
4353 return str.substring(0, lastIdx);
4354 }
4355
4356 /**
4357 * <p>Removes {@code separator} from the end of
4358 * {@code str} if it's there, otherwise leave it alone.</p>
4359 *
4360 * <p>NOTE: This method changed in version 2.0.
4361 * It now more closely matches Perl chomp.
4362 * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
4363 * This method uses {@link String#endsWith(String)}.</p>
4364 *
4365 * <pre>
4366 * StringUtils.chomp(null, *) = null
4367 * StringUtils.chomp("", *) = ""
4368 * StringUtils.chomp("foobar", "bar") = "foo"
4369 * StringUtils.chomp("foobar", "baz") = "foobar"
4370 * StringUtils.chomp("foo", "foo") = ""
4371 * StringUtils.chomp("foo ", "foo") = "foo "
4372 * StringUtils.chomp(" foo", "foo") = " "
4373 * StringUtils.chomp("foo", "foooo") = "foo"
4374 * StringUtils.chomp("foo", "") = "foo"
4375 * StringUtils.chomp("foo", null) = "foo"
4376 * </pre>
4377 *
4378 * @param str the String to chomp from, may be null
4379 * @param separator separator String, may be null
4380 * @return String without trailing separator, {@code null} if null String input
4381 */
4382 public static String chomp(String str, String separator) {
4383 if (isEmpty(str) || separator == null) {
4384 return str;
4385 }
4386 if (str.endsWith(separator)) {
4387 return str.substring(0, str.length() - separator.length());
4388 }
4389 return str;
4390 }
4391
4392 // Chopping
4393 //-----------------------------------------------------------------------
4394 /**
4395 * <p>Remove the last character from a String.</p>
4396 *
4397 * <p>If the String ends in {@code \r\n}, then remove both
4398 * of them.</p>
4399 *
4400 * <pre>
4401 * StringUtils.chop(null) = null
4402 * StringUtils.chop("") = ""
4403 * StringUtils.chop("abc \r") = "abc "
4404 * StringUtils.chop("abc\n") = "abc"
4405 * StringUtils.chop("abc\r\n") = "abc"
4406 * StringUtils.chop("abc") = "ab"
4407 * StringUtils.chop("abc\nabc") = "abc\nab"
4408 * StringUtils.chop("a") = ""
4409 * StringUtils.chop("\r") = ""
4410 * StringUtils.chop("\n") = ""
4411 * StringUtils.chop("\r\n") = ""
4412 * </pre>
4413 *
4414 * @param str the String to chop last character from, may be null
4415 * @return String without last character, {@code null} if null String input
4416 */
4417 public static String chop(String str) {
4418 if (str == null) {
4419 return null;
4420 }
4421 int strLen = str.length();
4422 if (strLen < 2) {
4423 return EMPTY;
4424 }
4425 int lastIdx = strLen - 1;
4426 String ret = str.substring(0, lastIdx);
4427 char last = str.charAt(lastIdx);
4428 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
4429 return ret.substring(0, lastIdx - 1);
4430 }
4431 return ret;
4432 }
4433
4434 // Conversion
4435 //-----------------------------------------------------------------------
4436
4437 // Padding
4438 //-----------------------------------------------------------------------
4439 /**
4440 * <p>Repeat a String {@code repeat} times to form a
4441 * new String.</p>
4442 *
4443 * <pre>
4444 * StringUtils.repeat(null, 2) = null
4445 * StringUtils.repeat("", 0) = ""
4446 * StringUtils.repeat("", 2) = ""
4447 * StringUtils.repeat("a", 3) = "aaa"
4448 * StringUtils.repeat("ab", 2) = "abab"
4449 * StringUtils.repeat("a", -2) = ""
4450 * </pre>
4451 *
4452 * @param str the String to repeat, may be null
4453 * @param repeat number of times to repeat str, negative treated as zero
4454 * @return a new String consisting of the original String repeated,
4455 * {@code null} if null String input
4456 */
4457 public static String repeat(String str, int repeat) {
4458 // Performance tuned for 2.0 (JDK1.4)
4459
4460 if (str == null) {
4461 return null;
4462 }
4463 if (repeat <= 0) {
4464 return EMPTY;
4465 }
4466 int inputLength = str.length();
4467 if (repeat == 1 || inputLength == 0) {
4468 return str;
4469 }
4470 if (inputLength == 1 && repeat <= PAD_LIMIT) {
4471 return repeat(str.charAt(0), repeat);
4472 }
4473
4474 int outputLength = inputLength * repeat;
4475 switch (inputLength) {
4476 case 1 :
4477 return repeat(str.charAt(0), repeat);
4478 case 2 :
4479 char ch0 = str.charAt(0);
4480 char ch1 = str.charAt(1);
4481 char[] output2 = new char[outputLength];
4482 for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
4483 output2[i] = ch0;
4484 output2[i + 1] = ch1;
4485 }
4486 return new String(output2);
4487 default :
4488 StringBuilder buf = new StringBuilder(outputLength);
4489 for (int i = 0; i < repeat; i++) {
4490 buf.append(str);
4491 }
4492 return buf.toString();
4493 }
4494 }
4495
4496 /**
4497 * <p>Repeat a String {@code repeat} times to form a
4498 * new String, with a String separator injected each time. </p>
4499 *
4500 * <pre>
4501 * StringUtils.repeat(null, null, 2) = null
4502 * StringUtils.repeat(null, "x", 2) = null
4503 * StringUtils.repeat("", null, 0) = ""
4504 * StringUtils.repeat("", "", 2) = ""
4505 * StringUtils.repeat("", "x", 3) = "xxx"
4506 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
4507 * </pre>
4508 *
4509 * @param str the String to repeat, may be null
4510 * @param separator the String to inject, may be null
4511 * @param repeat number of times to repeat str, negative treated as zero
4512 * @return a new String consisting of the original String repeated,
4513 * {@code null} if null String input
4514 * @since 2.5
4515 */
4516 public static String repeat(String str, String separator, int repeat) {
4517 if(str == null || separator == null) {
4518 return repeat(str, repeat);
4519 } else {
4520 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
4521 String result = repeat(str + separator, repeat);
4522 return removeEnd(result, separator);
4523 }
4524 }
4525
4526 /**
4527 * <p>Returns padding using the specified delimiter repeated
4528 * to a given length.</p>
4529 *
4530 * <pre>
4531 * StringUtils.repeat(0, 'e') = ""
4532 * StringUtils.repeat(3, 'e') = "eee"
4533 * StringUtils.repeat(-2, 'e') = ""
4534 * </pre>
4535 *
4536 * <p>Note: this method doesn't not support padding with
4537 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
4538 * as they require a pair of {@code char}s to be represented.
4539 * If you are needing to support full I18N of your applications
4540 * consider using {@link #repeat(String, int)} instead.
4541 * </p>
4542 *
4543 * @param ch character to repeat
4544 * @param repeat number of times to repeat char, negative treated as zero
4545 * @return String with repeated character
4546 * @see #repeat(String, int)
4547 */
4548 public static String repeat(char ch, int repeat) {
4549 char[] buf = new char[repeat];
4550 for (int i = repeat - 1; i >= 0; i--) {
4551 buf[i] = ch;
4552 }
4553 return new String(buf);
4554 }
4555
4556 /**
4557 * <p>Right pad a String with spaces (' ').</p>
4558 *
4559 * <p>The String is padded to the size of {@code size}.</p>
4560 *
4561 * <pre>
4562 * StringUtils.rightPad(null, *) = null
4563 * StringUtils.rightPad("", 3) = " "
4564 * StringUtils.rightPad("bat", 3) = "bat"
4565 * StringUtils.rightPad("bat", 5) = "bat "
4566 * StringUtils.rightPad("bat", 1) = "bat"
4567 * StringUtils.rightPad("bat", -1) = "bat"
4568 * </pre>
4569 *
4570 * @param str the String to pad out, may be null
4571 * @param size the size to pad to
4572 * @return right padded String or original String if no padding is necessary,
4573 * {@code null} if null String input
4574 */
4575 public static String rightPad(String str, int size) {
4576 return rightPad(str, size, ' ');
4577 }
4578
4579 /**
4580 * <p>Right pad a String with a specified character.</p>
4581 *
4582 * <p>The String is padded to the size of {@code size}.</p>
4583 *
4584 * <pre>
4585 * StringUtils.rightPad(null, *, *) = null
4586 * StringUtils.rightPad("", 3, 'z') = "zzz"
4587 * StringUtils.rightPad("bat", 3, 'z') = "bat"
4588 * StringUtils.rightPad("bat", 5, 'z') = "batzz"
4589 * StringUtils.rightPad("bat", 1, 'z') = "bat"
4590 * StringUtils.rightPad("bat", -1, 'z') = "bat"
4591 * </pre>
4592 *
4593 * @param str the String to pad out, may be null
4594 * @param size the size to pad to
4595 * @param padChar the character to pad with
4596 * @return right padded String or original String if no padding is necessary,
4597 * {@code null} if null String input
4598 * @since 2.0
4599 */
4600 public static String rightPad(String str, int size, char padChar) {
4601 if (str == null) {
4602 return null;
4603 }
4604 int pads = size - str.length();
4605 if (pads <= 0) {
4606 return str; // returns original String when possible
4607 }
4608 if (pads > PAD_LIMIT) {
4609 return rightPad(str, size, String.valueOf(padChar));
4610 }
4611 return str.concat(repeat(padChar, pads));
4612 }
4613
4614 /**
4615 * <p>Right pad a String with a specified String.</p>
4616 *
4617 * <p>The String is padded to the size of {@code size}.</p>
4618 *
4619 * <pre>
4620 * StringUtils.rightPad(null, *, *) = null
4621 * StringUtils.rightPad("", 3, "z") = "zzz"
4622 * StringUtils.rightPad("bat", 3, "yz") = "bat"
4623 * StringUtils.rightPad("bat", 5, "yz") = "batyz"
4624 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
4625 * StringUtils.rightPad("bat", 1, "yz") = "bat"
4626 * StringUtils.rightPad("bat", -1, "yz") = "bat"
4627 * StringUtils.rightPad("bat", 5, null) = "bat "
4628 * StringUtils.rightPad("bat", 5, "") = "bat "
4629 * </pre>
4630 *
4631 * @param str the String to pad out, may be null
4632 * @param size the size to pad to
4633 * @param padStr the String to pad with, null or empty treated as single space
4634 * @return right padded String or original String if no padding is necessary,
4635 * {@code null} if null String input
4636 */
4637 public static String rightPad(String str, int size, String padStr) {
4638 if (str == null) {
4639 return null;
4640 }
4641 if (isEmpty(padStr)) {
4642 padStr = " ";
4643 }
4644 int padLen = padStr.length();
4645 int strLen = str.length();
4646 int pads = size - strLen;
4647 if (pads <= 0) {
4648 return str; // returns original String when possible
4649 }
4650 if (padLen == 1 && pads <= PAD_LIMIT) {
4651 return rightPad(str, size, padStr.charAt(0));
4652 }
4653
4654 if (pads == padLen) {
4655 return str.concat(padStr);
4656 } else if (pads < padLen) {
4657 return str.concat(padStr.substring(0, pads));
4658 } else {
4659 char[] padding = new char[pads];
4660 char[] padChars = padStr.toCharArray();
4661 for (int i = 0; i < pads; i++) {
4662 padding[i] = padChars[i % padLen];
4663 }
4664 return str.concat(new String(padding));
4665 }
4666 }
4667
4668 /**
4669 * <p>Left pad a String with spaces (' ').</p>
4670 *
4671 * <p>The String is padded to the size of {@code size}.</p>
4672 *
4673 * <pre>
4674 * StringUtils.leftPad(null, *) = null
4675 * StringUtils.leftPad("", 3) = " "
4676 * StringUtils.leftPad("bat", 3) = "bat"
4677 * StringUtils.leftPad("bat", 5) = " bat"
4678 * StringUtils.leftPad("bat", 1) = "bat"
4679 * StringUtils.leftPad("bat", -1) = "bat"
4680 * </pre>
4681 *
4682 * @param str the String to pad out, may be null
4683 * @param size the size to pad to
4684 * @return left padded String or original String if no padding is necessary,
4685 * {@code null} if null String input
4686 */
4687 public static String leftPad(String str, int size) {
4688 return leftPad(str, size, ' ');
4689 }
4690
4691 /**
4692 * <p>Left pad a String with a specified character.</p>
4693 *
4694 * <p>Pad to a size of {@code size}.</p>
4695 *
4696 * <pre>
4697 * StringUtils.leftPad(null, *, *) = null
4698 * StringUtils.leftPad("", 3, 'z') = "zzz"
4699 * StringUtils.leftPad("bat", 3, 'z') = "bat"
4700 * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
4701 * StringUtils.leftPad("bat", 1, 'z') = "bat"
4702 * StringUtils.leftPad("bat", -1, 'z') = "bat"
4703 * </pre>
4704 *
4705 * @param str the String to pad out, may be null
4706 * @param size the size to pad to
4707 * @param padChar the character to pad with
4708 * @return left padded String or original String if no padding is necessary,
4709 * {@code null} if null String input
4710 * @since 2.0
4711 */
4712 public static String leftPad(String str, int size, char padChar) {
4713 if (str == null) {
4714 return null;
4715 }
4716 int pads = size - str.length();
4717 if (pads <= 0) {
4718 return str; // returns original String when possible
4719 }
4720 if (pads > PAD_LIMIT) {
4721 return leftPad(str, size, String.valueOf(padChar));
4722 }
4723 return repeat(padChar, pads).concat(str);
4724 }
4725
4726 /**
4727 * <p>Left pad a String with a specified String.</p>
4728 *
4729 * <p>Pad to a size of {@code size}.</p>
4730 *
4731 * <pre>
4732 * StringUtils.leftPad(null, *, *) = null
4733 * StringUtils.leftPad("", 3, "z") = "zzz"
4734 * StringUtils.leftPad("bat", 3, "yz") = "bat"
4735 * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
4736 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
4737 * StringUtils.leftPad("bat", 1, "yz") = "bat"
4738 * StringUtils.leftPad("bat", -1, "yz") = "bat"
4739 * StringUtils.leftPad("bat", 5, null) = " bat"
4740 * StringUtils.leftPad("bat", 5, "") = " bat"
4741 * </pre>
4742 *
4743 * @param str the String to pad out, may be null
4744 * @param size the size to pad to
4745 * @param padStr the String to pad with, null or empty treated as single space
4746 * @return left padded String or original String if no padding is necessary,
4747 * {@code null} if null String input
4748 */
4749 public static String leftPad(String str, int size, String padStr) {
4750 if (str == null) {
4751 return null;
4752 }
4753 if (isEmpty(padStr)) {
4754 padStr = " ";
4755 }
4756 int padLen = padStr.length();
4757 int strLen = str.length();
4758 int pads = size - strLen;
4759 if (pads <= 0) {
4760 return str; // returns original String when possible
4761 }
4762 if (padLen == 1 && pads <= PAD_LIMIT) {
4763 return leftPad(str, size, padStr.charAt(0));
4764 }
4765
4766 if (pads == padLen) {
4767 return padStr.concat(str);
4768 } else if (pads < padLen) {
4769 return padStr.substring(0, pads).concat(str);
4770 } else {
4771 char[] padding = new char[pads];
4772 char[] padChars = padStr.toCharArray();
4773 for (int i = 0; i < pads; i++) {
4774 padding[i] = padChars[i % padLen];
4775 }
4776 return new String(padding).concat(str);
4777 }
4778 }
4779
4780 /**
4781 * Gets a CharSequence length or {@code 0} if the CharSequence is
4782 * {@code null}.
4783 *
4784 * @param cs
4785 * a CharSequence or {@code null}
4786 * @return CharSequence length or {@code 0} if the CharSequence is
4787 * {@code null}.
4788 * @since 2.4
4789 * @since 3.0 Changed signature from length(String) to length(CharSequence)
4790 */
4791 public static int length(CharSequence cs) {
4792 return cs == null ? 0 : cs.length();
4793 }
4794
4795 // Centering
4796 //-----------------------------------------------------------------------
4797 /**
4798 * <p>Centers a String in a larger String of size {@code size}
4799 * using the space character (' ').<p>
4800 *
4801 * <p>If the size is less than the String length, the String is returned.
4802 * A {@code null} String returns {@code null}.
4803 * A negative size is treated as zero.</p>
4804 *
4805 * <p>Equivalent to {@code center(str, size, " ")}.</p>
4806 *
4807 * <pre>
4808 * StringUtils.center(null, *) = null
4809 * StringUtils.center("", 4) = " "
4810 * StringUtils.center("ab", -1) = "ab"
4811 * StringUtils.center("ab", 4) = " ab "
4812 * StringUtils.center("abcd", 2) = "abcd"
4813 * StringUtils.center("a", 4) = " a "
4814 * </pre>
4815 *
4816 * @param str the String to center, may be null
4817 * @param size the int size of new String, negative treated as zero
4818 * @return centered String, {@code null} if null String input
4819 */
4820 public static String center(String str, int size) {
4821 return center(str, size, ' ');
4822 }
4823
4824 /**
4825 * <p>Centers a String in a larger String of size {@code size}.
4826 * Uses a supplied character as the value to pad the String with.</p>
4827 *
4828 * <p>If the size is less than the String length, the String is returned.
4829 * A {@code null} String returns {@code null}.
4830 * A negative size is treated as zero.</p>
4831 *
4832 * <pre>
4833 * StringUtils.center(null, *, *) = null
4834 * StringUtils.center("", 4, ' ') = " "
4835 * StringUtils.center("ab", -1, ' ') = "ab"
4836 * StringUtils.center("ab", 4, ' ') = " ab"
4837 * StringUtils.center("abcd", 2, ' ') = "abcd"
4838 * StringUtils.center("a", 4, ' ') = " a "
4839 * StringUtils.center("a", 4, 'y') = "yayy"
4840 * </pre>
4841 *
4842 * @param str the String to center, may be null
4843 * @param size the int size of new String, negative treated as zero
4844 * @param padChar the character to pad the new String with
4845 * @return centered String, {@code null} if null String input
4846 * @since 2.0
4847 */
4848 public static String center(String str, int size, char padChar) {
4849 if (str == null || size <= 0) {
4850 return str;
4851 }
4852 int strLen = str.length();
4853 int pads = size - strLen;
4854 if (pads <= 0) {
4855 return str;
4856 }
4857 str = leftPad(str, strLen + pads / 2, padChar);
4858 str = rightPad(str, size, padChar);
4859 return str;
4860 }
4861
4862 /**
4863 * <p>Centers a String in a larger String of size {@code size}.
4864 * Uses a supplied String as the value to pad the String with.</p>
4865 *
4866 * <p>If the size is less than the String length, the String is returned.
4867 * A {@code null} String returns {@code null}.
4868 * A negative size is treated as zero.</p>
4869 *
4870 * <pre>
4871 * StringUtils.center(null, *, *) = null
4872 * StringUtils.center("", 4, " ") = " "
4873 * StringUtils.center("ab", -1, " ") = "ab"
4874 * StringUtils.center("ab", 4, " ") = " ab"
4875 * StringUtils.center("abcd", 2, " ") = "abcd"
4876 * StringUtils.center("a", 4, " ") = " a "
4877 * StringUtils.center("a", 4, "yz") = "yayz"
4878 * StringUtils.center("abc", 7, null) = " abc "
4879 * StringUtils.center("abc", 7, "") = " abc "
4880 * </pre>
4881 *
4882 * @param str the String to center, may be null
4883 * @param size the int size of new String, negative treated as zero
4884 * @param padStr the String to pad the new String with, must not be null or empty
4885 * @return centered String, {@code null} if null String input
4886 * @throws IllegalArgumentException if padStr is {@code null} or empty
4887 */
4888 public static String center(String str, int size, String padStr) {
4889 if (str == null || size <= 0) {
4890 return str;
4891 }
4892 if (isEmpty(padStr)) {
4893 padStr = " ";
4894 }
4895 int strLen = str.length();
4896 int pads = size - strLen;
4897 if (pads <= 0) {
4898 return str;
4899 }
4900 str = leftPad(str, strLen + pads / 2, padStr);
4901 str = rightPad(str, size, padStr);
4902 return str;
4903 }
4904
4905 // Case conversion
4906 //-----------------------------------------------------------------------
4907 /**
4908 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
4909 *
4910 * <p>A {@code null} input String returns {@code null}.</p>
4911 *
4912 * <pre>
4913 * StringUtils.upperCase(null) = null
4914 * StringUtils.upperCase("") = ""
4915 * StringUtils.upperCase("aBc") = "ABC"
4916 * </pre>
4917 *
4918 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
4919 * the result of this method is affected by the current locale.
4920 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
4921 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
4922 *
4923 * @param str the String to upper case, may be null
4924 * @return the upper cased String, {@code null} if null String input
4925 */
4926 public static String upperCase(String str) {
4927 if (str == null) {
4928 return null;
4929 }
4930 return str.toUpperCase();
4931 }
4932
4933 /**
4934 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
4935 *
4936 * <p>A {@code null} input String returns {@code null}.</p>
4937 *
4938 * <pre>
4939 * StringUtils.upperCase(null, Locale.ENGLISH) = null
4940 * StringUtils.upperCase("", Locale.ENGLISH) = ""
4941 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
4942 * </pre>
4943 *
4944 * @param str the String to upper case, may be null
4945 * @param locale the locale that defines the case transformation rules, must not be null
4946 * @return the upper cased String, {@code null} if null String input
4947 * @since 2.5
4948 */
4949 public static String upperCase(String str, Locale locale) {
4950 if (str == null) {
4951 return null;
4952 }
4953 return str.toUpperCase(locale);
4954 }
4955
4956 /**
4957 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
4958 *
4959 * <p>A {@code null} input String returns {@code null}.</p>
4960 *
4961 * <pre>
4962 * StringUtils.lowerCase(null) = null
4963 * StringUtils.lowerCase("") = ""
4964 * StringUtils.lowerCase("aBc") = "abc"
4965 * </pre>
4966 *
4967 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
4968 * the result of this method is affected by the current locale.
4969 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
4970 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
4971 *
4972 * @param str the String to lower case, may be null
4973 * @return the lower cased String, {@code null} if null String input
4974 */
4975 public static String lowerCase(String str) {
4976 if (str == null) {
4977 return null;
4978 }
4979 return str.toLowerCase();
4980 }
4981
4982 /**
4983 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
4984 *
4985 * <p>A {@code null} input String returns {@code null}.</p>
4986 *
4987 * <pre>
4988 * StringUtils.lowerCase(null, Locale.ENGLISH) = null
4989 * StringUtils.lowerCase("", Locale.ENGLISH) = ""
4990 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
4991 * </pre>
4992 *
4993 * @param str the String to lower case, may be null
4994 * @param locale the locale that defines the case transformation rules, must not be null
4995 * @return the lower cased String, {@code null} if null String input
4996 * @since 2.5
4997 */
4998 public static String lowerCase(String str, Locale locale) {
4999 if (str == null) {
5000 return null;
5001 }
5002 return str.toLowerCase(locale);
5003 }
5004
5005 /**
5006 * <p>Capitalizes a String changing the first letter to title case as
5007 * per {@link Character#toTitleCase(char)}. No other letters are changed.</p>
5008 *
5009 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
5010 * A {@code null} input String returns {@code null}.</p>
5011 *
5012 * <pre>
5013 * StringUtils.capitalize(null) = null
5014 * StringUtils.capitalize("") = ""
5015 * StringUtils.capitalize("cat") = "Cat"
5016 * StringUtils.capitalize("cAt") = "CAt"
5017 * </pre>
5018 *
5019 * @param str the String to capitalize, may be null
5020 * @return the capitalized String, {@code null} if null String input
5021 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
5022 * @see #uncapitalize(String)
5023 * @since 2.0
5024 */
5025 public static String capitalize(String str) {
5026 int strLen;
5027 if (str == null || (strLen = str.length()) == 0) {
5028 return str;
5029 }
5030 return new StringBuilder(strLen)
5031 .append(Character.toTitleCase(str.charAt(0)))
5032 .append(str.substring(1))
5033 .toString();
5034 }
5035
5036 /**
5037 * <p>Uncapitalizes a String changing the first letter to title case as
5038 * per {@link Character#toLowerCase(char)}. No other letters are changed.</p>
5039 *
5040 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
5041 * A {@code null} input String returns {@code null}.</p>
5042 *
5043 * <pre>
5044 * StringUtils.uncapitalize(null) = null
5045 * StringUtils.uncapitalize("") = ""
5046 * StringUtils.uncapitalize("Cat") = "cat"
5047 * StringUtils.uncapitalize("CAT") = "cAT"
5048 * </pre>
5049 *
5050 * @param str the String to uncapitalize, may be null
5051 * @return the uncapitalized String, {@code null} if null String input
5052 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
5053 * @see #capitalize(String)
5054 * @since 2.0
5055 */
5056 public static String uncapitalize(String str) {
5057 int strLen;
5058 if (str == null || (strLen = str.length()) == 0) {
5059 return str;
5060 }
5061 return new StringBuilder(strLen)
5062 .append(Character.toLowerCase(str.charAt(0)))
5063 .append(str.substring(1))
5064 .toString();
5065 }
5066
5067 /**
5068 * <p>Swaps the case of a String changing upper and title case to
5069 * lower case, and lower case to upper case.</p>
5070 *
5071 * <ul>
5072 * <li>Upper case character converts to Lower case</li>
5073 * <li>Title case character converts to Lower case</li>
5074 * <li>Lower case character converts to Upper case</li>
5075 * </ul>
5076 *
5077 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
5078 * A {@code null} input String returns {@code null}.</p>
5079 *
5080 * <pre>
5081 * StringUtils.swapCase(null) = null
5082 * StringUtils.swapCase("") = ""
5083 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
5084 * </pre>
5085 *
5086 * <p>NOTE: This method changed in Lang version 2.0.
5087 * It no longer performs a word based algorithm.
5088 * If you only use ASCII, you will notice no change.
5089 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
5090 *
5091 * @param str the String to swap case, may be null
5092 * @return the changed String, {@code null} if null String input
5093 */
5094 public static String swapCase(String str) {
5095 if (StringUtils.isEmpty(str)) {
5096 return str;
5097 }
5098
5099 char[] buffer = str.toCharArray();
5100
5101 for (int i = 0; i < buffer.length; i++) {
5102 char ch = buffer[i];
5103 if (Character.isUpperCase(ch)) {
5104 buffer[i] = Character.toLowerCase(ch);
5105 } else if (Character.isTitleCase(ch)) {
5106 buffer[i] = Character.toLowerCase(ch);
5107 } else if (Character.isLowerCase(ch)) {
5108 buffer[i] = Character.toUpperCase(ch);
5109 }
5110 }
5111 return new String(buffer);
5112 }
5113
5114 // Count matches
5115 //-----------------------------------------------------------------------
5116 /**
5117 * <p>Counts how many times the substring appears in the larger string.</p>
5118 *
5119 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
5120 *
5121 * <pre>
5122 * StringUtils.countMatches(null, *) = 0
5123 * StringUtils.countMatches("", *) = 0
5124 * StringUtils.countMatches("abba", null) = 0
5125 * StringUtils.countMatches("abba", "") = 0
5126 * StringUtils.countMatches("abba", "a") = 2
5127 * StringUtils.countMatches("abba", "ab") = 1
5128 * StringUtils.countMatches("abba", "xxx") = 0
5129 * </pre>
5130 *
5131 * @param str the CharSequence to check, may be null
5132 * @param sub the substring to count, may be null
5133 * @return the number of occurrences, 0 if either CharSequence is {@code null}
5134 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
5135 */
5136 public static int countMatches(CharSequence str, CharSequence sub) {
5137 if (isEmpty(str) || isEmpty(sub)) {
5138 return 0;
5139 }
5140 int count = 0;
5141 int idx = 0;
5142 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
5143 count++;
5144 idx += sub.length();
5145 }
5146 return count;
5147 }
5148
5149 // Character Tests
5150 //-----------------------------------------------------------------------
5151 /**
5152 * <p>Checks if the CharSequence contains only Unicode letters.</p>
5153 *
5154 * <p>{@code null} will return {@code false}.
5155 * An empty CharSequence (length()=0) will return {@code false}.</p>
5156 *
5157 * <pre>
5158 * StringUtils.isAlpha(null) = false
5159 * StringUtils.isAlpha("") = false
5160 * StringUtils.isAlpha(" ") = false
5161 * StringUtils.isAlpha("abc") = true
5162 * StringUtils.isAlpha("ab2c") = false
5163 * StringUtils.isAlpha("ab-c") = false
5164 * </pre>
5165 *
5166 * @param cs the CharSequence to check, may be null
5167 * @return {@code true} if only contains letters, and is non-null
5168 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
5169 * @since 3.0 Changed "" to return false and not true
5170 */
5171 public static boolean isAlpha(CharSequence cs) {
5172 if (cs == null || cs.length() == 0) {
5173 return false;
5174 }
5175 int sz = cs.length();
5176 for (int i = 0; i < sz; i++) {
5177 if (Character.isLetter(cs.charAt(i)) == false) {
5178 return false;
5179 }
5180 }
5181 return true;
5182 }
5183
5184 /**
5185 * <p>Checks if the CharSequence contains only Unicode letters and
5186 * space (' ').</p>
5187 *
5188 * <p>{@code null} will return {@code false}
5189 * An empty CharSequence (length()=0) will return {@code true}.</p>
5190 *
5191 * <pre>
5192 * StringUtils.isAlphaSpace(null) = false
5193 * StringUtils.isAlphaSpace("") = true
5194 * StringUtils.isAlphaSpace(" ") = true
5195 * StringUtils.isAlphaSpace("abc") = true
5196 * StringUtils.isAlphaSpace("ab c") = true
5197 * StringUtils.isAlphaSpace("ab2c") = false
5198 * StringUtils.isAlphaSpace("ab-c") = false
5199 * </pre>
5200 *
5201 * @param cs the CharSequence to check, may be null
5202 * @return {@code true} if only contains letters and space,
5203 * and is non-null
5204 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
5205 */
5206 public static boolean isAlphaSpace(CharSequence cs) {
5207 if (cs == null) {
5208 return false;
5209 }
5210 int sz = cs.length();
5211 for (int i = 0; i < sz; i++) {
5212 if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5213 return false;
5214 }
5215 }
5216 return true;
5217 }
5218
5219 /**
5220 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
5221 *
5222 * <p>{@code null} will return {@code false}.
5223 * An empty CharSequence (length()=0) will return {@code false}.</p>
5224 *
5225 * <pre>
5226 * StringUtils.isAlphanumeric(null) = false
5227 * StringUtils.isAlphanumeric("") = false
5228 * StringUtils.isAlphanumeric(" ") = false
5229 * StringUtils.isAlphanumeric("abc") = true
5230 * StringUtils.isAlphanumeric("ab c") = false
5231 * StringUtils.isAlphanumeric("ab2c") = true
5232 * StringUtils.isAlphanumeric("ab-c") = false
5233 * </pre>
5234 *
5235 * @param cs the CharSequence to check, may be null
5236 * @return {@code true} if only contains letters or digits,
5237 * and is non-null
5238 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
5239 * @since 3.0 Changed "" to return false and not true
5240 */
5241 public static boolean isAlphanumeric(CharSequence cs) {
5242 if (cs == null || cs.length() == 0) {
5243 return false;
5244 }
5245 int sz = cs.length();
5246 for (int i = 0; i < sz; i++) {
5247 if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
5248 return false;
5249 }
5250 }
5251 return true;
5252 }
5253
5254 /**
5255 * <p>Checks if the CharSequence contains only Unicode letters, digits
5256 * or space ({@code ' '}).</p>
5257 *
5258 * <p>{@code null} will return {@code false}.
5259 * An empty CharSequence (length()=0) will return {@code true}.</p>
5260 *
5261 * <pre>
5262 * StringUtils.isAlphanumericSpace(null) = false
5263 * StringUtils.isAlphanumericSpace("") = true
5264 * StringUtils.isAlphanumericSpace(" ") = true
5265 * StringUtils.isAlphanumericSpace("abc") = true
5266 * StringUtils.isAlphanumericSpace("ab c") = true
5267 * StringUtils.isAlphanumericSpace("ab2c") = true
5268 * StringUtils.isAlphanumericSpace("ab-c") = false
5269 * </pre>
5270 *
5271 * @param cs the CharSequence to check, may be null
5272 * @return {@code true} if only contains letters, digits or space,
5273 * and is non-null
5274 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
5275 */
5276 public static boolean isAlphanumericSpace(CharSequence cs) {
5277 if (cs == null) {
5278 return false;
5279 }
5280 int sz = cs.length();
5281 for (int i = 0; i < sz; i++) {
5282 if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5283 return false;
5284 }
5285 }
5286 return true;
5287 }
5288
5289 /**
5290 * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
5291 *
5292 * <p>{@code null} will return {@code false}.
5293 * An empty CharSequence (length()=0) will return {@code true}.</p>
5294 *
5295 * <pre>
5296 * StringUtils.isAsciiPrintable(null) = false
5297 * StringUtils.isAsciiPrintable("") = true
5298 * StringUtils.isAsciiPrintable(" ") = true
5299 * StringUtils.isAsciiPrintable("Ceki") = true
5300 * StringUtils.isAsciiPrintable("ab2c") = true
5301 * StringUtils.isAsciiPrintable("!ab-c~") = true
5302 * StringUtils.isAsciiPrintable("\u0020") = true
5303 * StringUtils.isAsciiPrintable("\u0021") = true
5304 * StringUtils.isAsciiPrintable("\u007e") = true
5305 * StringUtils.isAsciiPrintable("\u007f") = false
5306 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
5307 * </pre>
5308 *
5309 * @param cs the CharSequence to check, may be null
5310 * @return {@code true} if every character is in the range
5311 * 32 thru 126
5312 * @since 2.1
5313 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
5314 */
5315 public static boolean isAsciiPrintable(CharSequence cs) {
5316 if (cs == null) {
5317 return false;
5318 }
5319 int sz = cs.length();
5320 for (int i = 0; i < sz; i++) {
5321 if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
5322 return false;
5323 }
5324 }
5325 return true;
5326 }
5327
5328 /**
5329 * <p>Checks if the CharSequence contains only Unicode digits.
5330 * A decimal point is not a Unicode digit and returns false.</p>
5331 *
5332 * <p>{@code null} will return {@code false}.
5333 * An empty CharSequence (length()=0) will return {@code false}.</p>
5334 *
5335 * <pre>
5336 * StringUtils.isNumeric(null) = false
5337 * StringUtils.isNumeric("") = false
5338 * StringUtils.isNumeric(" ") = false
5339 * StringUtils.isNumeric("123") = true
5340 * StringUtils.isNumeric("12 3") = false
5341 * StringUtils.isNumeric("ab2c") = false
5342 * StringUtils.isNumeric("12-3") = false
5343 * StringUtils.isNumeric("12.3") = false
5344 * </pre>
5345 *
5346 * @param cs the CharSequence to check, may be null
5347 * @return {@code true} if only contains digits, and is non-null
5348 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
5349 * @since 3.0 Changed "" to return false and not true
5350 */
5351 public static boolean isNumeric(CharSequence cs) {
5352 if (cs == null || cs.length() == 0) {
5353 return false;
5354 }
5355 int sz = cs.length();
5356 for (int i = 0; i < sz; i++) {
5357 if (Character.isDigit(cs.charAt(i)) == false) {
5358 return false;
5359 }
5360 }
5361 return true;
5362 }
5363
5364 /**
5365 * <p>Checks if the CharSequence contains only Unicode digits or space
5366 * ({@code ' '}).
5367 * A decimal point is not a Unicode digit and returns false.</p>
5368 *
5369 * <p>{@code null} will return {@code false}.
5370 * An empty CharSequence (length()=0) will return {@code true}.</p>
5371 *
5372 * <pre>
5373 * StringUtils.isNumericSpace(null) = false
5374 * StringUtils.isNumericSpace("") = true
5375 * StringUtils.isNumericSpace(" ") = true
5376 * StringUtils.isNumericSpace("123") = true
5377 * StringUtils.isNumericSpace("12 3") = true
5378 * StringUtils.isNumericSpace("ab2c") = false
5379 * StringUtils.isNumericSpace("12-3") = false
5380 * StringUtils.isNumericSpace("12.3") = false
5381 * </pre>
5382 *
5383 * @param cs the CharSequence to check, may be null
5384 * @return {@code true} if only contains digits or space,
5385 * and is non-null
5386 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
5387 */
5388 public static boolean isNumericSpace(CharSequence cs) {
5389 if (cs == null) {
5390 return false;
5391 }
5392 int sz = cs.length();
5393 for (int i = 0; i < sz; i++) {
5394 if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5395 return false;
5396 }
5397 }
5398 return true;
5399 }
5400
5401 /**
5402 * <p>Checks if the CharSequence contains only whitespace.</p>
5403 *
5404 * <p>{@code null} will return {@code false}.
5405 * An empty CharSequence (length()=0) will return {@code true}.</p>
5406 *
5407 * <pre>
5408 * StringUtils.isWhitespace(null) = false
5409 * StringUtils.isWhitespace("") = true
5410 * StringUtils.isWhitespace(" ") = true
5411 * StringUtils.isWhitespace("abc") = false
5412 * StringUtils.isWhitespace("ab2c") = false
5413 * StringUtils.isWhitespace("ab-c") = false
5414 * </pre>
5415 *
5416 * @param cs the CharSequence to check, may be null
5417 * @return {@code true} if only contains whitespace, and is non-null
5418 * @since 2.0
5419 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
5420 */
5421 public static boolean isWhitespace(CharSequence cs) {
5422 if (cs == null) {
5423 return false;
5424 }
5425 int sz = cs.length();
5426 for (int i = 0; i < sz; i++) {
5427 if ((Character.isWhitespace(cs.charAt(i)) == false)) {
5428 return false;
5429 }
5430 }
5431 return true;
5432 }
5433
5434 /**
5435 * <p>Checks if the CharSequence contains only lowercase characters.</p>
5436 *
5437 * <p>{@code null} will return {@code false}.
5438 * An empty CharSequence (length()=0) will return {@code false}.</p>
5439 *
5440 * <pre>
5441 * StringUtils.isAllLowerCase(null) = false
5442 * StringUtils.isAllLowerCase("") = false
5443 * StringUtils.isAllLowerCase(" ") = false
5444 * StringUtils.isAllLowerCase("abc") = true
5445 * StringUtils.isAllLowerCase("abC") = false
5446 * </pre>
5447 *
5448 * @param cs the CharSequence to check, may be null
5449 * @return {@code true} if only contains lowercase characters, and is non-null
5450 * @since 2.5
5451 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
5452 */
5453 public static boolean isAllLowerCase(CharSequence cs) {
5454 if (cs == null || isEmpty(cs)) {
5455 return false;
5456 }
5457 int sz = cs.length();
5458 for (int i = 0; i < sz; i++) {
5459 if (Character.isLowerCase(cs.charAt(i)) == false) {
5460 return false;
5461 }
5462 }
5463 return true;
5464 }
5465
5466 /**
5467 * <p>Checks if the CharSequence contains only uppercase characters.</p>
5468 *
5469 * <p>{@code null} will return {@code false}.
5470 * An empty String (length()=0) will return {@code false}.</p>
5471 *
5472 * <pre>
5473 * StringUtils.isAllUpperCase(null) = false
5474 * StringUtils.isAllUpperCase("") = false
5475 * StringUtils.isAllUpperCase(" ") = false
5476 * StringUtils.isAllUpperCase("ABC") = true
5477 * StringUtils.isAllUpperCase("aBC") = false
5478 * </pre>
5479 *
5480 * @param cs the CharSequence to check, may be null
5481 * @return {@code true} if only contains uppercase characters, and is non-null
5482 * @since 2.5
5483 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
5484 */
5485 public static boolean isAllUpperCase(CharSequence cs) {
5486 if (cs == null || isEmpty(cs)) {
5487 return false;
5488 }
5489 int sz = cs.length();
5490 for (int i = 0; i < sz; i++) {
5491 if (Character.isUpperCase(cs.charAt(i)) == false) {
5492 return false;
5493 }
5494 }
5495 return true;
5496 }
5497
5498 // Defaults
5499 //-----------------------------------------------------------------------
5500 /**
5501 * <p>Returns either the passed in String,
5502 * or if the String is {@code null}, an empty String ("").</p>
5503 *
5504 * <pre>
5505 * StringUtils.defaultString(null) = ""
5506 * StringUtils.defaultString("") = ""
5507 * StringUtils.defaultString("bat") = "bat"
5508 * </pre>
5509 *
5510 * @see ObjectUtils#toString(Object)
5511 * @see String#valueOf(Object)
5512 * @param str the String to check, may be null
5513 * @return the passed in String, or the empty String if it
5514 * was {@code null}
5515 */
5516 public static String defaultString(String str) {
5517 return str == null ? EMPTY : str;
5518 }
5519
5520 /**
5521 * <p>Returns either the passed in String, or if the String is
5522 * {@code null}, the value of {@code defaultStr}.</p>
5523 *
5524 * <pre>
5525 * StringUtils.defaultString(null, "NULL") = "NULL"
5526 * StringUtils.defaultString("", "NULL") = ""
5527 * StringUtils.defaultString("bat", "NULL") = "bat"
5528 * </pre>
5529 *
5530 * @see ObjectUtils#toString(Object,String)
5531 * @see String#valueOf(Object)
5532 * @param str the String to check, may be null
5533 * @param defaultStr the default String to return
5534 * if the input is {@code null}, may be null
5535 * @return the passed in String, or the default if it was {@code null}
5536 */
5537 public static String defaultString(String str, String defaultStr) {
5538 return str == null ? defaultStr : str;
5539 }
5540
5541 /**
5542 * <p>Returns either the passed in CharSequence, or if the CharSequence is
5543 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
5544 *
5545 * <pre>
5546 * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
5547 * StringUtils.defaultIfBlank("", "NULL") = "NULL"
5548 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
5549 * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
5550 * StringUtils.defaultIfBlank("", null) = null
5551 * </pre>
5552 * @param <T> the specific kind of CharSequence
5553 * @param str the CharSequence to check, may be null
5554 * @param defaultStr the default CharSequence to return
5555 * if the input is whitespace, empty ("") or {@code null}, may be null
5556 * @return the passed in CharSequence, or the default
5557 * @see StringUtils#defaultString(String, String)
5558 */
5559 public static <T extends CharSequence> T defaultIfBlank(T str, T defaultStr) {
5560 return StringUtils.isBlank(str) ? defaultStr : str;
5561 }
5562
5563 /**
5564 * <p>Returns either the passed in CharSequence, or if the CharSequence is
5565 * empty or {@code null}, the value of {@code defaultStr}.</p>
5566 *
5567 * <pre>
5568 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
5569 * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
5570 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
5571 * StringUtils.defaultIfEmpty("", null) = null
5572 * </pre>
5573 * @param <T> the specific kind of CharSequence
5574 * @param str the CharSequence to check, may be null
5575 * @param defaultStr the default CharSequence to return
5576 * if the input is empty ("") or {@code null}, may be null
5577 * @return the passed in CharSequence, or the default
5578 * @see StringUtils#defaultString(String, String)
5579 */
5580 public static <T extends CharSequence> T defaultIfEmpty(T str, T defaultStr) {
5581 return StringUtils.isEmpty(str) ? defaultStr : str;
5582 }
5583
5584 // Reversing
5585 //-----------------------------------------------------------------------
5586 /**
5587 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
5588 *
5589 * <p>A {@code null} String returns {@code null}.</p>
5590 *
5591 * <pre>
5592 * StringUtils.reverse(null) = null
5593 * StringUtils.reverse("") = ""
5594 * StringUtils.reverse("bat") = "tab"
5595 * </pre>
5596 *
5597 * @param str the String to reverse, may be null
5598 * @return the reversed String, {@code null} if null String input
5599 */
5600 public static String reverse(String str) {
5601 if (str == null) {
5602 return null;
5603 }
5604 return new StringBuilder(str).reverse().toString();
5605 }
5606
5607 /**
5608 * <p>Reverses a String that is delimited by a specific character.</p>
5609 *
5610 * <p>The Strings between the delimiters are not reversed.
5611 * Thus java.lang.String becomes String.lang.java (if the delimiter
5612 * is {@code '.'}).</p>
5613 *
5614 * <pre>
5615 * StringUtils.reverseDelimited(null, *) = null
5616 * StringUtils.reverseDelimited("", *) = ""
5617 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
5618 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
5619 * </pre>
5620 *
5621 * @param str the String to reverse, may be null
5622 * @param separatorChar the separator character to use
5623 * @return the reversed String, {@code null} if null String input
5624 * @since 2.0
5625 */
5626 public static String reverseDelimited(String str, char separatorChar) {
5627 if (str == null) {
5628 return null;
5629 }
5630 // could implement manually, but simple way is to reuse other,
5631 // probably slower, methods.
5632 String[] strs = split(str, separatorChar);
5633 ArrayUtils.reverse(strs);
5634 return join(strs, separatorChar);
5635 }
5636
5637 // Abbreviating
5638 //-----------------------------------------------------------------------
5639 /**
5640 * <p>Abbreviates a String using ellipses. This will turn
5641 * "Now is the time for all good men" into "Now is the time for..."</p>
5642 *
5643 * <p>Specifically:
5644 * <ul>
5645 * <li>If {@code str} is less than {@code maxWidth} characters
5646 * long, return it.</li>
5647 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
5648 * <li>If {@code maxWidth} is less than {@code 4}, throw an
5649 * {@code IllegalArgumentException}.</li>
5650 * <li>In no case will it return a String of length greater than
5651 * {@code maxWidth}.</li>
5652 * </ul>
5653 * </p>
5654 *
5655 * <pre>
5656 * StringUtils.abbreviate(null, *) = null
5657 * StringUtils.abbreviate("", 4) = ""
5658 * StringUtils.abbreviate("abcdefg", 6) = "abc..."
5659 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
5660 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
5661 * StringUtils.abbreviate("abcdefg", 4) = "a..."
5662 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
5663 * </pre>
5664 *
5665 * @param str the String to check, may be null
5666 * @param maxWidth maximum length of result String, must be at least 4
5667 * @return abbreviated String, {@code null} if null String input
5668 * @throws IllegalArgumentException if the width is too small
5669 * @since 2.0
5670 */
5671 public static String abbreviate(String str, int maxWidth) {
5672 return abbreviate(str, 0, maxWidth);
5673 }
5674
5675 /**
5676 * <p>Abbreviates a String using ellipses. This will turn
5677 * "Now is the time for all good men" into "...is the time for..."</p>
5678 *
5679 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
5680 * a "left edge" offset. Note that this left edge is not necessarily going to
5681 * be the leftmost character in the result, or the first character following the
5682 * ellipses, but it will appear somewhere in the result.
5683 *
5684 * <p>In no case will it return a String of length greater than
5685 * {@code maxWidth}.</p>
5686 *
5687 * <pre>
5688 * StringUtils.abbreviate(null, *, *) = null
5689 * StringUtils.abbreviate("", 0, 4) = ""
5690 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
5691 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
5692 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
5693 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
5694 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
5695 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
5696 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
5697 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
5698 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
5699 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
5700 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
5701 * </pre>
5702 *
5703 * @param str the String to check, may be null
5704 * @param offset left edge of source String
5705 * @param maxWidth maximum length of result String, must be at least 4
5706 * @return abbreviated String, {@code null} if null String input
5707 * @throws IllegalArgumentException if the width is too small
5708 * @since 2.0
5709 */
5710 public static String abbreviate(String str, int offset, int maxWidth) {
5711 if (str == null) {
5712 return null;
5713 }
5714 if (maxWidth < 4) {
5715 throw new IllegalArgumentException("Minimum abbreviation width is 4");
5716 }
5717 if (str.length() <= maxWidth) {
5718 return str;
5719 }
5720 if (offset > str.length()) {
5721 offset = str.length();
5722 }
5723 if ((str.length() - offset) < (maxWidth - 3)) {
5724 offset = str.length() - (maxWidth - 3);
5725 }
5726 final String abrevMarker = "...";
5727 if (offset <= 4) {
5728 return str.substring(0, maxWidth - 3) + abrevMarker;
5729 }
5730 if (maxWidth < 7) {
5731 throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
5732 }
5733 if ((offset + (maxWidth - 3)) < str.length()) {
5734 return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
5735 }
5736 return abrevMarker + str.substring(str.length() - (maxWidth - 3));
5737 }
5738
5739 /**
5740 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
5741 * replacement String.</p>
5742 *
5743 * <p>This abbreviation only occurs if the following criteria is met:
5744 * <ul>
5745 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
5746 * <li>The length to truncate to is less than the length of the supplied String</li>
5747 * <li>The length to truncate to is greater than 0</li>
5748 * <li>The abbreviated String will have enough room for the length supplied replacement String
5749 * and the first and last characters of the supplied String for abbreviation</li>
5750 * </ul>
5751 * Otherwise, the returned String will be the same as the supplied String for abbreviation.
5752 * </p>
5753 *
5754 * <pre>
5755 * StringUtils.abbreviateMiddle(null, null, 0) = null
5756 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
5757 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
5758 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
5759 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
5760 * </pre>
5761 *
5762 * @param str the String to abbreviate, may be null
5763 * @param middle the String to replace the middle characters with, may be null
5764 * @param length the length to abbreviate {@code str} to.
5765 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
5766 * @since 2.5
5767 */
5768 public static String abbreviateMiddle(String str, String middle, int length) {
5769 if (isEmpty(str) || isEmpty(middle)) {
5770 return str;
5771 }
5772
5773 if (length >= str.length() || length < (middle.length()+2)) {
5774 return str;
5775 }
5776
5777 int targetSting = length-middle.length();
5778 int startOffset = targetSting/2+targetSting%2;
5779 int endOffset = str.length()-targetSting/2;
5780
5781 StringBuilder builder = new StringBuilder(length);
5782 builder.append(str.substring(0,startOffset));
5783 builder.append(middle);
5784 builder.append(str.substring(endOffset));
5785
5786 return builder.toString();
5787 }
5788
5789 // Difference
5790 //-----------------------------------------------------------------------
5791 /**
5792 * <p>Compares two Strings, and returns the portion where they differ.
5793 * (More precisely, return the remainder of the second String,
5794 * starting from where it's different from the first.)</p>
5795 *
5796 * <p>For example,
5797 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
5798 *
5799 * <pre>
5800 * StringUtils.difference(null, null) = null
5801 * StringUtils.difference("", "") = ""
5802 * StringUtils.difference("", "abc") = "abc"
5803 * StringUtils.difference("abc", "") = ""
5804 * StringUtils.difference("abc", "abc") = ""
5805 * StringUtils.difference("ab", "abxyz") = "xyz"
5806 * StringUtils.difference("abcde", "abxyz") = "xyz"
5807 * StringUtils.difference("abcde", "xyz") = "xyz"
5808 * </pre>
5809 *
5810 * @param str1 the first String, may be null
5811 * @param str2 the second String, may be null
5812 * @return the portion of str2 where it differs from str1; returns the
5813 * empty String if they are equal
5814 * @since 2.0
5815 */
5816 public static String difference(String str1, String str2) {
5817 if (str1 == null) {
5818 return str2;
5819 }
5820 if (str2 == null) {
5821 return str1;
5822 }
5823 int at = indexOfDifference(str1, str2);
5824 if (at == INDEX_NOT_FOUND) {
5825 return EMPTY;
5826 }
5827 return str2.substring(at);
5828 }
5829
5830 /**
5831 * <p>Compares two CharSequences, and returns the index at which the
5832 * CharSequences begin to differ.</p>
5833 *
5834 * <p>For example,
5835 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
5836 *
5837 * <pre>
5838 * StringUtils.indexOfDifference(null, null) = -1
5839 * StringUtils.indexOfDifference("", "") = -1
5840 * StringUtils.indexOfDifference("", "abc") = 0
5841 * StringUtils.indexOfDifference("abc", "") = 0
5842 * StringUtils.indexOfDifference("abc", "abc") = -1
5843 * StringUtils.indexOfDifference("ab", "abxyz") = 2
5844 * StringUtils.indexOfDifference("abcde", "abxyz") = 2
5845 * StringUtils.indexOfDifference("abcde", "xyz") = 0
5846 * </pre>
5847 *
5848 * @param cs1 the first CharSequence, may be null
5849 * @param cs2 the second CharSequence, may be null
5850 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
5851 * @since 2.0
5852 * @since 3.0 Changed signature from indexOfDifference(String, String) to
5853 * indexOfDifference(CharSequence, CharSequence)
5854 */
5855 public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
5856 if (cs1 == cs2) {
5857 return INDEX_NOT_FOUND;
5858 }
5859 if (cs1 == null || cs2 == null) {
5860 return 0;
5861 }
5862 int i;
5863 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
5864 if (cs1.charAt(i) != cs2.charAt(i)) {
5865 break;
5866 }
5867 }
5868 if (i < cs2.length() || i < cs1.length()) {
5869 return i;
5870 }
5871 return INDEX_NOT_FOUND;
5872 }
5873
5874 /**
5875 * <p>Compares all CharSequences in an array and returns the index at which the
5876 * CharSequences begin to differ.</p>
5877 *
5878 * <p>For example,
5879 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p>
5880 *
5881 * <pre>
5882 * StringUtils.indexOfDifference(null) = -1
5883 * StringUtils.indexOfDifference(new String[] {}) = -1
5884 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
5885 * StringUtils.indexOfDifference(new String[] {null, null}) = -1
5886 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
5887 * StringUtils.indexOfDifference(new String[] {"", null}) = 0
5888 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
5889 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
5890 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
5891 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
5892 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
5893 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
5894 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
5895 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
5896 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
5897 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
5898 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
5899 * </pre>
5900 *
5901 * @param css array of CharSequences, entries may be null
5902 * @return the index where the strings begin to differ; -1 if they are all equal
5903 * @since 2.4
5904 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
5905 */
5906 public static int indexOfDifference(CharSequence... css) {
5907 if (css == null || css.length <= 1) {
5908 return INDEX_NOT_FOUND;
5909 }
5910 boolean anyStringNull = false;
5911 boolean allStringsNull = true;
5912 int arrayLen = css.length;
5913 int shortestStrLen = Integer.MAX_VALUE;
5914 int longestStrLen = 0;
5915
5916 // find the min and max string lengths; this avoids checking to make
5917 // sure we are not exceeding the length of the string each time through
5918 // the bottom loop.
5919 for (int i = 0; i < arrayLen; i++) {
5920 if (css[i] == null) {
5921 anyStringNull = true;
5922 shortestStrLen = 0;
5923 } else {
5924 allStringsNull = false;
5925 shortestStrLen = Math.min(css[i].length(), shortestStrLen);
5926 longestStrLen = Math.max(css[i].length(), longestStrLen);
5927 }
5928 }
5929
5930 // handle lists containing all nulls or all empty strings
5931 if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) {
5932 return INDEX_NOT_FOUND;
5933 }
5934
5935 // handle lists containing some nulls or some empty strings
5936 if (shortestStrLen == 0) {
5937 return 0;
5938 }
5939
5940 // find the position with the first difference across all strings
5941 int firstDiff = -1;
5942 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
5943 char comparisonChar = css[0].charAt(stringPos);
5944 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
5945 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
5946 firstDiff = stringPos;
5947 break;
5948 }
5949 }
5950 if (firstDiff != -1) {
5951 break;
5952 }
5953 }
5954
5955 if (firstDiff == -1 && shortestStrLen != longestStrLen) {
5956 // we compared all of the characters up to the length of the
5957 // shortest string and didn't find a match, but the string lengths
5958 // vary, so return the length of the shortest string.
5959 return shortestStrLen;
5960 }
5961 return firstDiff;
5962 }
5963
5964 /**
5965 * <p>Compares all Strings in an array and returns the initial sequence of
5966 * characters that is common to all of them.</p>
5967 *
5968 * <p>For example,
5969 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p>
5970 *
5971 * <pre>
5972 * StringUtils.getCommonPrefix(null) = ""
5973 * StringUtils.getCommonPrefix(new String[] {}) = ""
5974 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
5975 * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
5976 * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
5977 * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
5978 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
5979 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
5980 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
5981 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
5982 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
5983 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
5984 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
5985 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
5986 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
5987 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
5988 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
5989 * </pre>
5990 *
5991 * @param strs array of String objects, entries may be null
5992 * @return the initial sequence of characters that are common to all Strings
5993 * in the array; empty String if the array is null, the elements are all null
5994 * or if there is no common prefix.
5995 * @since 2.4
5996 */
5997 public static String getCommonPrefix(String... strs) {
5998 if (strs == null || strs.length == 0) {
5999 return EMPTY;
6000 }
6001 int smallestIndexOfDiff = indexOfDifference(strs);
6002 if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
6003 // all strings were identical
6004 if (strs[0] == null) {
6005 return EMPTY;
6006 }
6007 return strs[0];
6008 } else if (smallestIndexOfDiff == 0) {
6009 // there were no common initial characters
6010 return EMPTY;
6011 } else {
6012 // we found a common initial character sequence
6013 return strs[0].substring(0, smallestIndexOfDiff);
6014 }
6015 }
6016
6017 // Misc
6018 //-----------------------------------------------------------------------
6019 /**
6020 * <p>Find the Levenshtein distance between two Strings.</p>
6021 *
6022 * <p>This is the number of changes needed to change one String into
6023 * another, where each change is a single character modification (deletion,
6024 * insertion or substitution).</p>
6025 *
6026 * <p>The previous implementation of the Levenshtein distance algorithm
6027 * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
6028 *
6029 * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
6030 * which can occur when my Java implementation is used with very large strings.<br>
6031 * This implementation of the Levenshtein distance algorithm
6032 * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
6033 *
6034 * <pre>
6035 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
6036 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
6037 * StringUtils.getLevenshteinDistance("","") = 0
6038 * StringUtils.getLevenshteinDistance("","a") = 1
6039 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7
6040 * StringUtils.getLevenshteinDistance("frog", "fog") = 1
6041 * StringUtils.getLevenshteinDistance("fly", "ant") = 3
6042 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
6043 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
6044 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
6045 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1
6046 * </pre>
6047 *
6048 * @param s the first String, must not be null
6049 * @param t the second String, must not be null
6050 * @return result distance
6051 * @throws IllegalArgumentException if either String input {@code null}
6052 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
6053 * getLevenshteinDistance(CharSequence, CharSequence)
6054 */
6055 public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
6056 if (s == null || t == null) {
6057 throw new IllegalArgumentException("Strings must not be null");
6058 }
6059
6060 /*
6061 The difference between this impl. and the previous is that, rather
6062 than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
6063 we maintain two single-dimensional arrays of length s.length() + 1. The first, d,
6064 is the 'current working' distance array that maintains the newest distance cost
6065 counts as we iterate through the characters of String s. Each time we increment
6066 the index of String t we are comparing, d is copied to p, the second int[]. Doing so
6067 allows us to retain the previous cost counts as required by the algorithm (taking
6068 the minimum of the cost count to the left, up one, and diagonally up and to the left
6069 of the current cost count being calculated). (Note that the arrays aren't really
6070 copied anymore, just switched...this is clearly much better than cloning an array
6071 or doing a System.arraycopy() each time through the outer loop.)
6072
6073 Effectively, the difference between the two implementations is this one does not
6074 cause an out of memory condition when calculating the LD over two very large strings.
6075 */
6076
6077 int n = s.length(); // length of s
6078 int m = t.length(); // length of t
6079
6080 if (n == 0) {
6081 return m;
6082 } else if (m == 0) {
6083 return n;
6084 }
6085
6086 if (n > m) {
6087 // swap the input strings to consume less memory
6088 CharSequence tmp = s;
6089 s = t;
6090 t = tmp;
6091 n = m;
6092 m = t.length();
6093 }
6094
6095 int p[] = new int[n + 1]; //'previous' cost array, horizontally
6096 int d[] = new int[n + 1]; // cost array, horizontally
6097 int _d[]; //placeholder to assist in swapping p and d
6098
6099 // indexes into strings s and t
6100 int i; // iterates through s
6101 int j; // iterates through t
6102
6103 char t_j; // jth character of t
6104
6105 int cost; // cost
6106
6107 for (i = 0; i <= n; i++) {
6108 p[i] = i;
6109 }
6110
6111 for (j = 1; j <= m; j++) {
6112 t_j = t.charAt(j - 1);
6113 d[0] = j;
6114
6115 for (i = 1; i <= n; i++) {
6116 cost = s.charAt(i - 1) == t_j ? 0 : 1;
6117 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
6118 d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
6119 }
6120
6121 // copy current distance counts to 'previous row' distance counts
6122 _d = p;
6123 p = d;
6124 d = _d;
6125 }
6126
6127 // our last action in the above loop was to switch d and p, so p now
6128 // actually has the most recent cost counts
6129 return p[n];
6130 }
6131
6132 /**
6133 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
6134 * threshold.</p>
6135 *
6136 * <p>This is the number of changes needed to change one String into
6137 * another, where each change is a single character modification (deletion,
6138 * insertion or substitution).</p>
6139 *
6140 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
6141 * and Chas Emerick's implementation of the Levenshtein distance algorithm from
6142 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
6143 *
6144 * <pre>
6145 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
6146 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
6147 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
6148 * StringUtils.getLevenshteinDistance("","", 0) = 0
6149 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
6150 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
6151 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
6152 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
6153 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
6154 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
6155 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
6156 * </pre>
6157 *
6158 * @param s the first String, must not be null
6159 * @param t the second String, must not be null
6160 * @param threshold the target threshold, must not be negative
6161 * @return result distance, or {@code -1} if the distance would be greater than the threshold
6162 * @throws IllegalArgumentException if either String input {@code null} or negative threshold
6163 */
6164 public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
6165 if (s == null || t == null) {
6166 throw new IllegalArgumentException("Strings must not be null");
6167 }
6168 if (threshold < 0) {
6169 throw new IllegalArgumentException("Threshold must not be negative");
6170 }
6171
6172 /*
6173 This implementation only computes the distance if it's less than or equal to the
6174 threshold value, returning -1 if it's greater. The advantage is performance: unbounded
6175 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
6176 computing a diagonal stripe of width 2k + 1 of the cost table.
6177 It is also possible to use this to compute the unbounded Levenshtein distance by starting
6178 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
6179 d is the distance.
6180
6181 One subtlety comes from needing to ignore entries on the border of our stripe
6182 eg.
6183 p[] = |#|#|#|*
6184 d[] = *|#|#|#|
6185 We must ignore the entry to the left of the leftmost member
6186 We must ignore the entry above the rightmost member
6187
6188 Another subtlety comes from our stripe running off the matrix if the strings aren't
6189 of the same size. Since string s is always swapped to be the shorter of the two,
6190 the stripe will always run off to the upper right instead of the lower left of the matrix.
6191
6192 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
6193 In this case we're going to walk a stripe of length 3. The matrix would look like so:
6194
6195 1 2 3 4 5
6196 1 |#|#| | | |
6197 2 |#|#|#| | |
6198 3 | |#|#|#| |
6199 4 | | |#|#|#|
6200 5 | | | |#|#|
6201 6 | | | | |#|
6202 7 | | | | | |
6203
6204 Note how the stripe leads off the table as there is no possible way to turn a string of length 5
6205 into one of length 7 in edit distance of 1.
6206
6207 Additionally, this implementation decreases memory usage by using two
6208 single-dimensional arrays and swapping them back and forth instead of allocating
6209 an entire n by m matrix. This requires a few minor changes, such as immediately returning
6210 when it's detected that the stripe has run off the matrix and initially filling the arrays with
6211 large values so that entries we don't compute are ignored.
6212
6213 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
6214 */
6215
6216 int n = s.length(); // length of s
6217 int m = t.length(); // length of t
6218
6219 // if one string is empty, the edit distance is necessarily the length of the other
6220 if (n == 0) {
6221 return m <= threshold ? m : -1;
6222 } else if (m == 0) {
6223 return n <= threshold ? n : -1;
6224 }
6225
6226 if (n > m) {
6227 // swap the two strings to consume less memory
6228 CharSequence tmp = s;
6229 s = t;
6230 t = tmp;
6231 n = m;
6232 m = t.length();
6233 }
6234
6235 int p[] = new int[n + 1]; // 'previous' cost array, horizontally
6236 int d[] = new int[n + 1]; // cost array, horizontally
6237 int _d[]; // placeholder to assist in swapping p and d
6238
6239 // fill in starting table values
6240 int boundary = Math.min(n, threshold) + 1;
6241 for (int i = 0; i < boundary; i++) {
6242 p[i] = i;
6243 }
6244 // these fills ensure that the value above the rightmost entry of our
6245 // stripe will be ignored in following loop iterations
6246 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
6247 Arrays.fill(d, Integer.MAX_VALUE);
6248
6249 // iterates through t
6250 for (int j = 1; j <= m; j++) {
6251 char t_j = t.charAt(j - 1); // jth character of t
6252 d[0] = j;
6253
6254 // compute stripe indices, constrain to array size
6255 int min = Math.max(1, j - threshold);
6256 int max = Math.min(n, j + threshold);
6257
6258 // the stripe may lead off of the table if s and t are of different sizes
6259 if (min > max) {
6260 return -1;
6261 }
6262
6263 // ignore entry left of leftmost
6264 if (min > 1) {
6265 d[min - 1] = Integer.MAX_VALUE;
6266 }
6267
6268 // iterates through [min, max] in s
6269 for (int i = min; i <= max; i++) {
6270 if (s.charAt(i - 1) == t_j) {
6271 // diagonally left and up
6272 d[i] = p[i - 1];
6273 } else {
6274 // 1 + minimum of cell to the left, to the top, diagonally left and up
6275 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
6276 }
6277 }
6278
6279 // copy current distance counts to 'previous row' distance counts
6280 _d = p;
6281 p = d;
6282 d = _d;
6283 }
6284
6285 // if p[n] is greater than the threshold, there's no guarantee on it being the correct
6286 // distance
6287 if (p[n] <= threshold) {
6288 return p[n];
6289 } else {
6290 return -1;
6291 }
6292 }
6293
6294 // startsWith
6295 //-----------------------------------------------------------------------
6296
6297 /**
6298 * <p>Check if a CharSequence starts with a specified prefix.</p>
6299 *
6300 * <p>{@code null}s are handled without exceptions. Two {@code null}
6301 * references are considered to be equal. The comparison is case sensitive.</p>
6302 *
6303 * <pre>
6304 * StringUtils.startsWith(null, null) = true
6305 * StringUtils.startsWith(null, "abc") = false
6306 * StringUtils.startsWith("abcdef", null) = false
6307 * StringUtils.startsWith("abcdef", "abc") = true
6308 * StringUtils.startsWith("ABCDEF", "abc") = false
6309 * </pre>
6310 *
6311 * @see java.lang.String#startsWith(String)
6312 * @param str the CharSequence to check, may be null
6313 * @param prefix the prefix to find, may be null
6314 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
6315 * both {@code null}
6316 * @since 2.4
6317 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
6318 */
6319 public static boolean startsWith(CharSequence str, CharSequence prefix) {
6320 return startsWith(str, prefix, false);
6321 }
6322
6323 /**
6324 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
6325 *
6326 * <p>{@code null}s are handled without exceptions. Two {@code null}
6327 * references are considered to be equal. The comparison is case insensitive.</p>
6328 *
6329 * <pre>
6330 * StringUtils.startsWithIgnoreCase(null, null) = true
6331 * StringUtils.startsWithIgnoreCase(null, "abc") = false
6332 * StringUtils.startsWithIgnoreCase("abcdef", null) = false
6333 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
6334 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
6335 * </pre>
6336 *
6337 * @see java.lang.String#startsWith(String)
6338 * @param str the CharSequence to check, may be null
6339 * @param prefix the prefix to find, may be null
6340 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
6341 * both {@code null}
6342 * @since 2.4
6343 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
6344 */
6345 public static boolean startsWithIgnoreCase(CharSequence str, CharSequence prefix) {
6346 return startsWith(str, prefix, true);
6347 }
6348
6349 /**
6350 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
6351 *
6352 * @see java.lang.String#startsWith(String)
6353 * @param str the CharSequence to check, may be null
6354 * @param prefix the prefix to find, may be null
6355 * @param ignoreCase indicates whether the compare should ignore case
6356 * (case insensitive) or not.
6357 * @return {@code true} if the CharSequence starts with the prefix or
6358 * both {@code null}
6359 */
6360 private static boolean startsWith(CharSequence str, CharSequence prefix, boolean ignoreCase) {
6361 if (str == null || prefix == null) {
6362 return (str == null && prefix == null);
6363 }
6364 if (prefix.length() > str.length()) {
6365 return false;
6366 }
6367 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
6368 }
6369
6370 /**
6371 * <p>Check if a CharSequence starts with any of an array of specified strings.</p>
6372 *
6373 * <pre>
6374 * StringUtils.startsWithAny(null, null) = false
6375 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
6376 * StringUtils.startsWithAny("abcxyz", null) = false
6377 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false
6378 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
6379 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
6380 * </pre>
6381 *
6382 * @param string the CharSequence to check, may be null
6383 * @param searchStrings the CharSequences to find, may be null or empty
6384 * @return {@code true} if the CharSequence starts with any of the the prefixes, case insensitive, or
6385 * both {@code null}
6386 * @since 2.5
6387 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
6388 */
6389 public static boolean startsWithAny(CharSequence string, CharSequence... searchStrings) {
6390 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
6391 return false;
6392 }
6393 for (CharSequence searchString : searchStrings) {
6394 if (StringUtils.startsWith(string, searchString)) {
6395 return true;
6396 }
6397 }
6398 return false;
6399 }
6400
6401 // endsWith
6402 //-----------------------------------------------------------------------
6403
6404 /**
6405 * <p>Check if a CharSequence ends with a specified suffix.</p>
6406 *
6407 * <p>{@code null}s are handled without exceptions. Two {@code null}
6408 * references are considered to be equal. The comparison is case sensitive.</p>
6409 *
6410 * <pre>
6411 * StringUtils.endsWith(null, null) = true
6412 * StringUtils.endsWith(null, "def") = false
6413 * StringUtils.endsWith("abcdef", null) = false
6414 * StringUtils.endsWith("abcdef", "def") = true
6415 * StringUtils.endsWith("ABCDEF", "def") = false
6416 * StringUtils.endsWith("ABCDEF", "cde") = false
6417 * </pre>
6418 *
6419 * @see java.lang.String#endsWith(String)
6420 * @param str the CharSequence to check, may be null
6421 * @param suffix the suffix to find, may be null
6422 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
6423 * both {@code null}
6424 * @since 2.4
6425 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
6426 */
6427 public static boolean endsWith(CharSequence str, CharSequence suffix) {
6428 return endsWith(str, suffix, false);
6429 }
6430
6431 /**
6432 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
6433 *
6434 * <p>{@code null}s are handled without exceptions. Two {@code null}
6435 * references are considered to be equal. The comparison is case insensitive.</p>
6436 *
6437 * <pre>
6438 * StringUtils.endsWithIgnoreCase(null, null) = true
6439 * StringUtils.endsWithIgnoreCase(null, "def") = false
6440 * StringUtils.endsWithIgnoreCase("abcdef", null) = false
6441 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
6442 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
6443 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
6444 * </pre>
6445 *
6446 * @see java.lang.String#endsWith(String)
6447 * @param str the CharSequence to check, may be null
6448 * @param suffix the suffix to find, may be null
6449 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
6450 * both {@code null}
6451 * @since 2.4
6452 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
6453 */
6454 public static boolean endsWithIgnoreCase(CharSequence str, CharSequence suffix) {
6455 return endsWith(str, suffix, true);
6456 }
6457
6458 /**
6459 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
6460 *
6461 * @see java.lang.String#endsWith(String)
6462 * @param str the CharSequence to check, may be null
6463 * @param suffix the suffix to find, may be null
6464 * @param ignoreCase indicates whether the compare should ignore case
6465 * (case insensitive) or not.
6466 * @return {@code true} if the CharSequence starts with the prefix or
6467 * both {@code null}
6468 */
6469 private static boolean endsWith(CharSequence str, CharSequence suffix, boolean ignoreCase) {
6470 if (str == null || suffix == null) {
6471 return str == null && suffix == null;
6472 }
6473 if (suffix.length() > str.length()) {
6474 return false;
6475 }
6476 int strOffset = str.length() - suffix.length();
6477 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
6478 }
6479
6480 /**
6481 * <p>
6482 * Similar to <a
6483 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
6484 * -space</a>
6485 * </p>
6486 * <p>
6487 * The function returns the argument string with whitespace normalized by using
6488 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
6489 * and then replacing sequences of whitespace characters by a single space.
6490 * </p>
6491 * In XML Whitespace characters are the same as those allowed by the <a
6492 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
6493 * <p>
6494 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
6495 * <p>
6496 * For reference:
6497 * <ul>
6498 * <li>\x0B = vertical tab</li>
6499 * <li>\f = #xC = form feed</li>
6500 * <li>#x20 = space</li>
6501 * <li>#x9 = \t</li>
6502 * <li>#xA = \n</li>
6503 * <li>#xD = \r</li>
6504 * </ul>
6505 * </p>
6506 * <p>
6507 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
6508 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both
6509 * ends of this String.
6510 * </p>
6511 *
6512 * @see Pattern
6513 * @see #trim(String)
6514 * @see <a
6515 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
6516 * @param str the source String to normalize whitespaces from, may be null
6517 * @return the modified string with whitespace normalized, {@code null} if null String input
6518 *
6519 * @since 3.0
6520 */
6521 public static String normalizeSpace(String str) {
6522 if (str == null) {
6523 return null;
6524 }
6525 return WHITESPACE_BLOCK.matcher(trim(str)).replaceAll(" ");
6526 }
6527
6528 /**
6529 * <p>Check if a CharSequence ends with any of an array of specified strings.</p>
6530 *
6531 * <pre>
6532 * StringUtils.endsWithAny(null, null) = false
6533 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
6534 * StringUtils.endsWithAny("abcxyz", null) = false
6535 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
6536 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
6537 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
6538 * </pre>
6539 *
6540 * @param string the CharSequence to check, may be null
6541 * @param searchStrings the CharSequences to find, may be null or empty
6542 * @return {@code true} if the CharSequence ends with any of the the prefixes, case insensitive, or
6543 * both {@code null}
6544 * @since 3.0
6545 */
6546 public static boolean endsWithAny(CharSequence string, CharSequence... searchStrings) {
6547 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
6548 return false;
6549 }
6550 for (CharSequence searchString : searchStrings) {
6551 if (StringUtils.endsWith(string, searchString)) {
6552 return true;
6553 }
6554 }
6555 return false;
6556 }
6557
6558 }