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