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