StringUtils_英文
来源:互联网 发布:进口软件涉及的税种 编辑:程序博客网 时间:2024/05/01 17:55
001/*
002 * Licensed to the Apache SoftwareFoundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional informationregarding copyright ownership.
005 * The ASF licenses this file to Youunder the Apache License, Version 2.0
006 * (the "License"); you maynot 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 oragreed to in writing, software
012 * distributed under the License isdistributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OFANY KIND, either express or implied.
014 * See the License for the specificlanguage governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.charset.Charset;
021import java.text.Normalizer;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Locale;
027import java.util.Objects;
028import java.util.regex.Pattern;
029
030/**
031 * <p>Operations on {@linkjava.lang.String} that are
032 * {@code null} safe.</p>
033 *
034 * <ul>
035 * <li><b>IsEmpty/IsBlank</b>
036 * - checks if a String contains text</li>
037 * <li><b>Trim/Strip</b>
038 * - removes leading and trailing whitespace</li>
039 * <li><b>Equals/Compare</b>
040 * - compares two strings null-safe</li>
041 * <li><b>startsWith</b>
042 * - check if a String starts with a prefix null-safe</li>
043 * <li><b>endsWith</b>
044 * - check if a String ends with a suffix null-safe</li>
045 * <li><b>IndexOf/LastIndexOf/Contains</b>
046 * - null-safe index-of checks
047 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
048 * - index-of any of a set of Strings</li>
049 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
050 * - does String contains only/none/any of these characters</li>
051 * <li><b>Substring/Left/Right/Mid</b>
052 * - null-safe substring extractions</li>
053 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
054 * - substring extraction relative to other strings</li>
055 * <li><b>Split/Join</b>
056 * - splits a String into an array of substrings and vice versa</li>
057 * <li><b>Remove/Delete</b>
058 * - removes part of a String</li>
059 * <li><b>Replace/Overlay</b>
060 * - Searches a String and replaces one String with another</li>
061 * <li><b>Chomp/Chop</b>
062 * - removes the last part of a String</li>
063 * <li><b>AppendIfMissing</b>
064 * - appends a suffix to the end of the String if not present</li>
065 * <li><b>PrependIfMissing</b>
066 * - prepends a prefix to the start of the String if not present</li>
067 * <li><b>LeftPad/RightPad/Center/Repeat</b>
068 * - pads a String</li>
069 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
070 * - changes the case of a String</li>
071 * <li><b>CountMatches</b>
072 * - counts the number of occurrences of one String in another</li>
073 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
074 * - checks the characters in a String</li>
075 * <li><b>DefaultString</b>
076 * - protects against a null input String</li>
077 * <li><b>Rotate</b>
078 * - rotate (circular shift) a String</li>
079 * <li><b>Reverse/ReverseDelimited</b>
080 * - reverses a String</li>
081 * <li><b>Abbreviate</b>
082 * - abbreviates a string using ellipsis or another given String</li>
083 * <li><b>Difference</b>
084 * - compares Strings and reports on their differences</li>
085 * <li><b>LevenshteinDistance</b>
086 * - the number of changes needed to change one String intoanother</li>
087 * </ul>
088 *
089 * <p>The {@code StringUtils}class defines certain words related to
090 * String handling.</p>
091 *
092 * <ul>
093 * <li>null - {@code null}</li>
094 * <li>empty - a zero-length string ({@code ""})</li>
095 * <li>space - the space character ({@code ' '}, char 32)</li>
096 * <li>whitespace - the characters defined by {@linkCharacter#isWhitespace(char)}</li>
097 * <li>trim - the characters <= 32 as in {@linkString#trim()}</li>
098 * </ul>
099 *
100 * <p>{@code StringUtils} handles{@code null} input Strings quietly.
101 * That is to say that a {@code null}input will return {@code null}.
102 * Where a {@code boolean} or {@codeint} is being returned
103 * details vary by method.</p>
104 *
105 * <p>A side effect of the {@codenull} handling is that a
106 * {@code NullPointerException} shouldbe considered a bug in
107 * {@code StringUtils}.</p>
108 *
109 * <p>Methods in this class givesample code to explain their operation.
110 * The symbol {@code *} is used toindicate any input including {@code null}.</p>
111 *
112 * <p>#ThreadSafe#</p>
113 * @see java.lang.String
114 * @since 1.0
115 */
116//@Immutable
117public class StringUtils {
118 // Performance testing notes (JDK 1.4, Jul03, scolebourne)
119 // Whitespace:
120 // Character.isWhitespace() is faster than WHITESPACE.indexOf()
121 // where WHITESPACE is a string of all whitespace characters
122 //
123 // Character access:
124 // String.charAt(n) versus toCharArray(), then array[n]
125 // String.charAt(n) is about 15% worse for a 10K string
126 // They are about equal for a length 50 string
127 // String.charAt(n) is about 4 times better for a length 3 string
128 // String.charAt(n) is best bet overall
129 //
130 // Append:
131 // String.concat about twice as fast as StringBuffer.append
132 // (not sure who tested this)
133
134 /**
135 * A String for a space character.
136 *
137 * @since 3.2
138 */
139 public static final String SPACE = " ";
140
141 /**
142 * The empty String {@code ""}.
143 * @since 2.0
144 */
145 public static final String EMPTY = "";
146
147 /**
148 * A String for linefeed LF ("\n").
149 *
150 * @see <ahref="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF:Escape Sequences
151 * for Character and StringLiterals</a>
152 * @since 3.2
153 */
154 public static final String LF = "\n";
155
156 /**
157 * A String for carriage return CR ("\r").
158 *
159 * @see <ahref="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF:Escape Sequences
160 * for Character and StringLiterals</a>
161 * @since 3.2
162 */
163 public static final String CR = "\r";
164
165 /**
166 * Represents a failed index search.
167 * @since 2.1
168 */
169 public static final int INDEX_NOT_FOUND = -1;
170
171 /**
172 * <p>The maximum size to which the padding constant(s) canexpand.</p>
173 */
174 private static final int PAD_LIMIT = 8192;
175
176 /**
177 * <p>{@code StringUtils} instances should NOT be constructed in
178 * standard programming. Instead, the class should be used as
179 * {@code StringUtils.trim(" foo ");}.</p>
180 *
181 * <p>This constructor is public to permit tools that require aJavaBean
182 * instance to operate.</p>
183 */
184 public StringUtils() {
185 super();
186 }
187
188 // Empty checks
189 //-----------------------------------------------------------------------
190 /**
191 * <p>Checks if a CharSequence is empty ("") ornull.</p>
192 *
193 * <pre>
194 * StringUtils.isEmpty(null) =true
195 * StringUtils.isEmpty("") = true
196 * StringUtils.isEmpty(" ") = false
197 * StringUtils.isEmpty("bob") = false
198 * StringUtils.isEmpty(" bob ") = false
199 * </pre>
200 *
201 * <p>NOTE: This method changed in Lang version 2.0.
202 * It no longer trims the CharSequence.
203 * That functionality is available in isBlank().</p>
204 *
205 * @param cs the CharSequence tocheck, may be null
206 * @return {@code true} if the CharSequence is empty or null
207 * @since 3.0 Changed signature from isEmpty(String) toisEmpty(CharSequence)
208 */
209 public static boolean isEmpty(final CharSequence cs) {
210 return cs == null || cs.length() == 0;
211 }
212
213 /**
214 * <p>Checks if a CharSequence is not empty ("") and notnull.</p>
215 *
216 * <pre>
217 * StringUtils.isNotEmpty(null) = false
218 * StringUtils.isNotEmpty("") = false
219 * StringUtils.isNotEmpty(" ") = true
220 * StringUtils.isNotEmpty("bob") = true
221 * StringUtils.isNotEmpty(" bob ") = true
222 * </pre>
223 *
224 * @param cs the CharSequence tocheck, may be null
225 * @return {@code true} if the CharSequence is not empty and not null
226 * @since 3.0 Changed signature from isNotEmpty(String) toisNotEmpty(CharSequence)
227 */
228 public static boolean isNotEmpty(final CharSequence cs) {
229 return !isEmpty(cs);
230 }
231
232 /**
233 * <p>Checks if any of the CharSequences are empty ("")or null.</p>
234 *
235 * <pre>
236 * StringUtils.isAnyEmpty(null) = true
237 * StringUtils.isAnyEmpty(null, "foo") = true
238 * StringUtils.isAnyEmpty("", "bar") = true
239 * StringUtils.isAnyEmpty("bob", "") = true
240 * StringUtils.isAnyEmpty(" bob ", null) = true
241 * StringUtils.isAnyEmpty(" ", "bar") = false
242 * StringUtils.isAnyEmpty("foo", "bar") = false
243 * StringUtils.isAnyEmpty(new String[]{}) = false
244 * StringUtils.isAnyEmpty(new String[]{""}) = true
245 * </pre>
246 *
247 * @param css the CharSequences tocheck, may be null or empty
248 * @return {@code true} if any of the CharSequences are empty or null
249 * @since 3.2
250 */
251 public static boolean isAnyEmpty(final CharSequence... css) {
252 if (ArrayUtils.isEmpty(css)) {
253 return false;
254 }
255 for (final CharSequence cs : css){
256 if (isEmpty(cs)) {
257 return true;
258 }
259 }
260 return false;
261 }
262
263 /**
264 * <p>Checks if none of the CharSequences are empty ("")or null.</p>
265 *
266 * <pre>
267 * StringUtils.isNoneEmpty(null) = false
268 * StringUtils.isNoneEmpty(null, "foo") = false
269 * StringUtils.isNoneEmpty("", "bar") =false
270 * StringUtils.isNoneEmpty("bob", "") = false
271 * StringUtils.isNoneEmpty(" bob ", null) = false
272 * StringUtils.isNoneEmpty(new String[] {}) = true
273 * StringUtils.isNoneEmpty(new String[]{""}) = false
274 * StringUtils.isNoneEmpty(" ", "bar") = true
275 * StringUtils.isNoneEmpty("foo", "bar") = true
276 * </pre>
277 *
278 * @param css the CharSequences tocheck, may be null or empty
279 * @return {@code true} if none of the CharSequences are empty or null
280 * @since 3.2
281 */
282 public static boolean isNoneEmpty(final CharSequence... css) {
283 return !isAnyEmpty(css);
284 }
285
286 /**
287 * <p>Checks if all of the CharSequences are empty ("")or null.</p>
288 *
289 * <pre>
290 * StringUtils.isAllEmpty(null) = true
291 * StringUtils.isAllEmpty(null, "") = true
292 * StringUtils.isAllEmpty(new String[] {}) = true
293 * StringUtils.isAllEmpty(null, "foo") = false
294 * StringUtils.isAllEmpty("", "bar") = false
295 * StringUtils.isAllEmpty("bob", "") = false
296 * StringUtils.isAllEmpty(" bob ", null) = false
297 * StringUtils.isAllEmpty(" ", "bar") = false
298 * StringUtils.isAllEmpty("foo", "bar") = false
299 * </pre>
300 *
301 * @param css the CharSequences tocheck, may be null or empty
302 * @return {@code true} if all of the CharSequences are empty or null
303 * @since 3.6
304 */
305 public static boolean isAllEmpty(final CharSequence... css) {
306 if (ArrayUtils.isEmpty(css)) {
307 return true;
308 }
309 for (final CharSequence cs : css) {
310 if (isNotEmpty(cs)) {
311 return false;
312 }
313 }
314 return true;
315 }
316
317 /**
318 * <p>Checks if a CharSequence is empty (""), null orwhitespace only.</p>
319 *
320 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
321 *
322 * <pre>
323 * StringUtils.isBlank(null) =true
324 * StringUtils.isBlank("") = true
325 * StringUtils.isBlank(" ") = true
326 * StringUtils.isBlank("bob") = false
327 * StringUtils.isBlank(" bob ") = false
328 * </pre>
329 *
330 * @param cs the CharSequence tocheck, may be null
331 * @return {@code true} if the CharSequence is null, empty or whitespaceonly
332 * @since 2.0
333 * @since 3.0 Changed signature from isBlank(String) toisBlank(CharSequence)
334 */
335 public static boolean isBlank(final CharSequence cs) {
336 int strLen;
337 if (cs == null || (strLen = cs.length()) == 0) {
338 return true;
339 }
340 for (int i = 0; i < strLen; i++) {
341 if(Character.isWhitespace(cs.charAt(i)) == false) {
342 return false;
343 }
344 }
345 return true;
346 }
347
348 /**
349 * <p>Checks if a CharSequence is not empty (""), notnull and not whitespace only.</p>
350 *
351 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
352 *
353 * <pre>
354 * StringUtils.isNotBlank(null) = false
355 * StringUtils.isNotBlank("") = false
356 * StringUtils.isNotBlank(" ") = false
357 * StringUtils.isNotBlank("bob") = true
358 * StringUtils.isNotBlank(" bob ") = true
359 * </pre>
360 *
361 * @param cs the CharSequence tocheck, may be null
362 * @return {@code true} if the CharSequence is
363 * not empty and not null and notwhitespace only
364 * @since 2.0
365 * @since 3.0 Changed signature from isNotBlank(String) toisNotBlank(CharSequence)
366 */
367 public static boolean isNotBlank(final CharSequence cs) {
368 return !isBlank(cs);
369 }
370
371 /**
372 * <p>Checks if any of the CharSequences are empty ("")or null or whitespace only.</p>
373 *
374 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
375 *
376 * <pre>
377 * StringUtils.isAnyBlank(null) = true
378 * StringUtils.isAnyBlank(null, "foo") = true
379 * StringUtils.isAnyBlank(null, null) = true
380 * StringUtils.isAnyBlank("", "bar") = true
381 * StringUtils.isAnyBlank("bob", "") = true
382 * StringUtils.isAnyBlank(" bob ", null) = true
383 * StringUtils.isAnyBlank(" ", "bar") = true
384 * StringUtils.isAnyBlank(new String[] {}) = false
385 * StringUtils.isAnyBlank(new String[]{""}) = true
386 * StringUtils.isAnyBlank("foo", "bar") = false
387 * </pre>
388 *
389 * @param css the CharSequences tocheck, may be null or empty
390 * @return {@code true} if any of the CharSequences are empty or null orwhitespace only
391 * @since 3.2
392 */
393 public static boolean isAnyBlank(final CharSequence... css) {
394 if (ArrayUtils.isEmpty(css)) {
395 return false;
396 }
397 for (final CharSequence cs : css){
398 if (isBlank(cs)) {
399 return true;
400 }
401 }
402 return false;
403 }
404
405 /**
406 * <p>Checks if none of the CharSequences are empty (""),null or whitespace only.</p>
407 *
408 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
409 *
410 * <pre>
411 * StringUtils.isNoneBlank(null) = false
412 * StringUtils.isNoneBlank(null, "foo") = false
413 * StringUtils.isNoneBlank(null, null) = false
414 * StringUtils.isNoneBlank("", "bar") = false
415 * StringUtils.isNoneBlank("bob", "") = false
416 * StringUtils.isNoneBlank(" bob ", null) = false
417 * StringUtils.isNoneBlank(" ", "bar") = false
418 * StringUtils.isNoneBlank(new String[] {}) = true
419 * StringUtils.isNoneBlank(new String[]{""}) = false
420 * StringUtils.isNoneBlank("foo", "bar") = true
421 * </pre>
422 *
423 * @param css the CharSequences tocheck, may be null or empty
424 * @return {@code true} if none of the CharSequences are empty or null orwhitespace only
425 * @since 3.2
426 */
427 public static boolean isNoneBlank(final CharSequence... css) {
428 return !isAnyBlank(css);
429 }
430
431 /**
432 * <p>Checks if all of the CharSequences are empty (""),null or whitespace only.</p>
433 *
434 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
435 *
436 * <pre>
437 * StringUtils.isAllBlank(null) = true
438 * StringUtils.isAllBlank(null, "foo") = false
439 * StringUtils.isAllBlank(null, null) = true
440 * StringUtils.isAllBlank("", "bar") = false
441 * StringUtils.isAllBlank("bob", "") =false
442 * StringUtils.isAllBlank(" bob ", null) = false
443 * StringUtils.isAllBlank(" ", "bar") = false
444 * StringUtils.isAllBlank("foo", "bar") = false
445 * StringUtils.isAllBlank(new String[] {}) = true
446 * </pre>
447 *
448 * @param css the CharSequences tocheck, may be null or empty
449 * @return {@code true} if all of the CharSequences are empty or null orwhitespace only
450 * @since 3.6
451 */
452 public static boolean isAllBlank(final CharSequence... css) {
453 if (ArrayUtils.isEmpty(css)) {
454 return true;
455 }
456 for (final CharSequence cs : css) {
457 if (isNotBlank(cs)) {
458 return false;
459 }
460 }
461 return true;
462 }
463
464 // Trim
465 //-----------------------------------------------------------------------
466 /**
467 * <p>Removes control characters (char <= 32) from both
468 * ends of this String, handling{@code null} by returning
469 * {@code null}.</p>
470 *
471 * <p>The String is trimmed using {@link String#trim()}.
472 * Trim removes start and end characters <= 32.
473 * To strip whitespace use {@link #strip(String)}.</p>
474 *
475 * <p>To trim your choice of characters, use the
476 * {@link #strip(String, String)} methods.</p>
477 *
478 * <pre>
479 * StringUtils.trim(null) = null
480 * StringUtils.trim("") = ""
481 * StringUtils.trim(" ") = ""
482 * StringUtils.trim("abc") = "abc"
483 * StringUtils.trim(" abc ") = "abc"
484 * </pre>
485 *
486 * @param str the String to betrimmed, may be null
487 * @return the trimmed string, {@code null} if null String input
488 */
489 public static String trim(final String str) {
490 return str == null ? null : str.trim();
491 }
492
493 /**
494 * <p>Removes control characters (char <= 32) from both
495 * ends of this String returning {@code null} if the String is
496 * empty ("") after the trim or if it is {@code null}.
497 *
498 * <p>The String is trimmed using {@link String#trim()}.
499 * Trim removes start and end characters <= 32.
500 * To strip whitespace use {@link #stripToNull(String)}.</p>
501 *
502 * <pre>
503 * StringUtils.trimToNull(null) = null
504 * StringUtils.trimToNull("") = null
505 * StringUtils.trimToNull(" ") = null
506 * StringUtils.trimToNull("abc") = "abc"
507 * StringUtils.trimToNull(" abc ") = "abc"
508 * </pre>
509 *
510 * @param str the String to be trimmed, may be null
511 * @return the trimmed String,
512 * {@code null} if only chars<= 32, empty or null String input
513 * @since 2.0
514 */
515 public static String trimToNull(final String str) {
516 final String ts = trim(str);
517 return isEmpty(ts) ? null : ts;
518 }
519
520 /**
521 * <p>Removes control characters (char <= 32) from both
522 * ends of this String returning an empty String ("") if theString
523 * is empty ("") after the trim or if it is {@code null}.
524 *
525 * <p>The String is trimmed using {@link String#trim()}.
526 * Trim removes start and end characters <= 32.
527 * To strip whitespace use {@link #stripToEmpty(String)}.</p>
528 *
529 * <pre>
530 * StringUtils.trimToEmpty(null) = ""
531 * StringUtils.trimToEmpty("") = ""
532 * StringUtils.trimToEmpty(" ") = ""
533 * StringUtils.trimToEmpty("abc") = "abc"
534 * StringUtils.trimToEmpty(" abc ") = "abc"
535 * </pre>
536 *
537 * @param str the String to betrimmed, may be null
538 * @return the trimmed String, or an empty String if {@code null} input
539 * @since 2.0
540 */
541 public static String trimToEmpty(finalString str) {
542 return str == null ? EMPTY : str.trim();
543 }
544
545 /**
546 * <p>Truncates a String. This will turn
547 * "Now is the time for all good men" into "Now is thetime for".</p>
548 *
549 * <p>Specifically:</p>
550 * <ul>
551 * <li>If {@code str} isless than {@code maxWidth} characters
552 * long, returnit.</li>
553 * <li>Else truncate it to{@code substring(str, 0, maxWidth)}.</li>
554 * <li>If {@code maxWidth} is less than{@code 0}, throw an
555 * {@codeIllegalArgumentException}.</li>
556 * <li>In no case will itreturn a String of length greater than
557 * {@codemaxWidth}.</li>
558 * </ul>
559 *
560 * <pre>
561 * StringUtils.truncate(null, 0) = null
562 * StringUtils.truncate(null, 2) = null
563 * StringUtils.truncate("", 4) = ""
564 * StringUtils.truncate("abcdefg", 4) = "abcd"
565 * StringUtils.truncate("abcdefg", 6) = "abcdef"
566 * StringUtils.truncate("abcdefg", 7) = "abcdefg"
567 * StringUtils.truncate("abcdefg", 8) = "abcdefg"
568 * StringUtils.truncate("abcdefg", -1) = throws anIllegalArgumentException
569 * </pre>
570 *
571 * @param str the String totruncate, may be null
572 * @param maxWidth maximum lengthof result String, must be positive
573 * @return truncated String, {@code null} if null String input
574 * @since 3.5
575 */
576 public static String truncate(final String str, final int maxWidth) {
577 return truncate(str, 0, maxWidth);
578 }
579
580 /**
581 * <p>Truncates a String. This will turn
582 * "Now is the time for all good men" into "is the time forall".</p>
583 *
584 * <p>Works like {@code truncate(String, int)}, but allows you tospecify
585 * a "left edge" offset.
586 *
587 * <p>Specifically:</p>
588 * <ul>
589 * <li>If {@code str} isless than {@code maxWidth} characters
590 * long, returnit.</li>
591 * <li>Else truncate it to{@code substring(str, offset, maxWidth)}.</li>
592 * <li>If {@code maxWidth}is less than {@code 0}, throw an
593 * {@codeIllegalArgumentException}.</li>
594 * <li>If {@code offset} isless than {@code 0}, throw an
595 * {@codeIllegalArgumentException}.</li>
596 * <li>In no case will itreturn a String of length greater than
597 * {@codemaxWidth}.</li>
598 * </ul>
599 *
600 * <pre>
601 * StringUtils.truncate(null, 0, 0) = null
602 * StringUtils.truncate(null, 2, 4) = null
603 * StringUtils.truncate("", 0, 10) = ""
604 * StringUtils.truncate("", 2, 10) = ""
605 * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
606 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
607 * StringUtils.truncate("raspberry peach", 10, 15) ="peach"
608 * StringUtils.truncate("abcdefghijklmno", 0, 10) ="abcdefghij"
609 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws anIllegalArgumentException
610 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE,10) = "abcdefghij"
611 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE,Integer.MAX_VALUE) = "abcdefghijklmno"
612 *StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) ="abcdefghijklmno"
613 * StringUtils.truncate("abcdefghijklmno", 1, 10) ="bcdefghijk"
614 * StringUtils.truncate("abcdefghijklmno", 2, 10) ="cdefghijkl"
615 * StringUtils.truncate("abcdefghijklmno", 3, 10) ="defghijklm"
616 * StringUtils.truncate("abcdefghijklmno", 4, 10) ="efghijklmn"
617 * StringUtils.truncate("abcdefghijklmno", 5, 10) ="fghijklmno"
618 * StringUtils.truncate("abcdefghijklmno", 5, 5) ="fghij"
619 * StringUtils.truncate("abcdefghijklmno", 5, 3) ="fgh"
620 * StringUtils.truncate("abcdefghijklmno", 10, 3) ="klm"
621 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE)= "klmno"
622 * StringUtils.truncate("abcdefghijklmno", 13, 1) ="n"
623 * StringUtils.truncate("abcdefghijklmno", 13,Integer.MAX_VALUE) = "no"
624 * StringUtils.truncate("abcdefghijklmno", 14, 1) ="o"
625 * StringUtils.truncate("abcdefghijklmno", 14,Integer.MAX_VALUE) = "o"
626 * StringUtils.truncate("abcdefghijklmno", 15, 1) =""
627 * StringUtils.truncate("abcdefghijklmno", 15,Integer.MAX_VALUE) = ""
628 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE,Integer.MAX_VALUE) = ""
629 * StringUtils.truncate("abcdefghij", 3, -1) = throws anIllegalArgumentException
630 * StringUtils.truncate("abcdefghij", -2, 4) = throws anIllegalArgumentException
631 * </pre>
632 *
633 * @param str the String to check,may be null
634 * @param offset left edge ofsource String
635 * @param maxWidth maximum lengthof result String, must be positive
636 * @return truncated String, {@code null} if null String input
637 * @since 3.5
638 */
639 public static String truncate(final String str, final int offset, finalint maxWidth) {
640 if (offset < 0) {
641 throw newIllegalArgumentException("offset cannot be negative");
642 }
643 if (maxWidth < 0) {
644 throw newIllegalArgumentException("maxWith cannot be negative");
645 }
646 if (str == null) {
647 return null;
648 }
649 if (offset > str.length()) {
650 return EMPTY;
651 }
652 if (str.length() > maxWidth) {
653 final int ix = offset + maxWidth> str.length() ? str.length() : offset + maxWidth;
654 return str.substring(offset, ix);
655 }
656 return str.substring(offset);
657 }
658
659 // Stripping
660 //-----------------------------------------------------------------------
661 /**
662 * <p>Strips whitespace from the start and end of aString.</p>
663 *
664 * <p>This is similar to {@link #trim(String)} but removes whitespace.
665 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
666 *
667 * <p>A {@code null} input String returns {@code null}.</p>
668 *
669 * <pre>
670 * StringUtils.strip(null) =null
671 * StringUtils.strip("") = ""
672 * StringUtils.strip(" ") = ""
673 * StringUtils.strip("abc") = "abc"
674 * StringUtils.strip(" abc") = "abc"
675 * StringUtils.strip("abc ") = "abc"
676 * StringUtils.strip(" abc ") = "abc"
677 * StringUtils.strip(" ab c ") = "ab c"
678 * </pre>
679 *
680 * @param str the String to removewhitespace from, may be null
681 * @return the stripped String, {@code null} if null String input
682 */
683 public static String strip(final String str) {
684 return strip(str, null);
685 }
686
687 /**
688 * <p>Strips whitespace from the start and end of a String returning
689 * {@code null} if the String is empty ("") after thestrip.</p>
690 *
691 * <p>This is similar to {@link #trimToNull(String)} but removeswhitespace.
692 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
693 *
694 * <pre>
695 * StringUtils.stripToNull(null) = null
696 * StringUtils.stripToNull("") = null
697 * StringUtils.stripToNull(" ") = null
698 * StringUtils.stripToNull("abc") = "abc"
699 * StringUtils.stripToNull(" abc") = "abc"
700 * StringUtils.stripToNull("abc ") = "abc"
701 * StringUtils.stripToNull(" abc ") = "abc"
702 * StringUtils.stripToNull(" ab c ") = "ab c"
703 * </pre>
704 *
705 * @param str the String to bestripped, may be null
706 * @return the stripped String,
707 * {@code null} if whitespace,empty or null String input
708 * @since 2.0
709 */
710 public static String stripToNull(String str) {
711 if (str == null) {
712 return null;
713 }
714 str = strip(str, null);
715 return str.isEmpty() ? null : str;
716 }
717
718 /**
719 * <p>Strips whitespace from the start and end of a String returning
720 * an empty String if {@code null} input.</p>
721 *
722 * <p>This is similar to {@link #trimToEmpty(String)} but removeswhitespace.
723 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
724 *
725 * <pre>
726 * StringUtils.stripToEmpty(null) = ""
727 * StringUtils.stripToEmpty("") = ""
728 * StringUtils.stripToEmpty(" ") = ""
729 * StringUtils.stripToEmpty("abc") = "abc"
730 * StringUtils.stripToEmpty(" abc") = "abc"
731 * StringUtils.stripToEmpty("abc ") = "abc"
732 * StringUtils.stripToEmpty(" abc ") = "abc"
733 * StringUtils.stripToEmpty(" ab c ") = "ab c"
734 * </pre>
735 *
736 * @param str the String to bestripped, may be null
737 * @return the trimmed String, or an empty String if {@code null} input
738 * @since 2.0
739 */
740 public static String stripToEmpty(final String str) {
741 return str == null ? EMPTY : strip(str, null);
742 }
743
744 /**
745 * <p>Strips any of a set of characters from the start and end of aString.
746 * This is similar to {@link String#trim()} but allows the characters
747 * to be stripped to be controlled.</p>
748 *
749 * <p>A {@code null} input String returns {@code null}.
750 * An empty string ("") input returns the emptystring.</p>
751 *
752 * <p>If the stripChars String is {@code null}, whitespace is
753 * stripped as defined by {@link Character#isWhitespace(char)}.
754 * Alternatively use {@link #strip(String)}.</p>
755 *
756 * <pre>
757 * StringUtils.strip(null, *) = null
758 * StringUtils.strip("", *) = ""
759 * StringUtils.strip("abc", null) = "abc"
760 * StringUtils.strip(" abc", null) ="abc"
761 * StringUtils.strip("abc ", null) = "abc"
762 * StringUtils.strip(" abc ", null) = "abc"
763 * StringUtils.strip(" abcyx", "xyz") = " abc"
764 * </pre>
765 *
766 * @param str the String to removecharacters from, may be null
767 * @param stripChars thecharacters to remove, null treated as whitespace
768 * @return the stripped String, {@code null} if null String input
769 */
770 public static String strip(String str, final String stripChars) {
771 if (isEmpty(str)) {
772 return str;
773 }
774 str = stripStart(str, stripChars);
775 return stripEnd(str, stripChars);
776 }
777
778 /**
779 * <p>Strips any of a set of characters from the start of aString.</p>
780 *
781 * <p>A {@code null} input String returns {@code null}.
782 * An empty string ("") input returns the emptystring.</p>
783 *
784 * <p>If the stripChars String is {@code null}, whitespace is
785 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
786 *
787 * <pre>
788 * StringUtils.stripStart(null, *) = null
789 * StringUtils.stripStart("", *) = ""
790 * StringUtils.stripStart("abc", "") = "abc"
791 * StringUtils.stripStart("abc", null) = "abc"
792 * StringUtils.stripStart(" abc", null) ="abc"
793 * StringUtils.stripStart("abc ", null) = "abc "
794 * StringUtils.stripStart(" abc ", null) = "abc "
795 * StringUtils.stripStart("yxabc ", "xyz") = "abc "
796 * </pre>
797 *
798 * @param str the String to removecharacters from, may be null
799 * @param stripChars thecharacters to remove, null treated as whitespace
800 * @return the stripped String, {@code null} if null String input
801 */
802 public static String stripStart(final String str, final StringstripChars) {
803 int strLen;
804 if (str == null || (strLen = str.length()) == 0) {
805 return str;
806 }
807 int start = 0;
808 if (stripChars == null) {
809 while (start != strLen &&Character.isWhitespace(str.charAt(start))) {
810 start++;
811 }
812 } else if (stripChars.isEmpty()) {
813 return str;
814 } else {
815 while (start != strLen &&stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
816 start++;
817 }
818 }
819 return str.substring(start);
820 }
821
822 /**
823 * <p>Strips any of a set of characters from the end of aString.</p>
824 *
825 * <p>A {@code null} input String returns {@code null}.
826 * An empty string ("") input returns the emptystring.</p>
827 *
828 * <p>If the stripChars String is {@code null}, whitespace is
829 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
830 *
831 * <pre>
832 * StringUtils.stripEnd(null, *) = null
833 * StringUtils.stripEnd("", *) = ""
834 * StringUtils.stripEnd("abc", "") = "abc"
835 * StringUtils.stripEnd("abc", null) = "abc"
836 * StringUtils.stripEnd(" abc", null) = " abc"
837 * StringUtils.stripEnd("abc ", null) = "abc"
838 * StringUtils.stripEnd(" abc ", null) = " abc"
839 * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
840 * StringUtils.stripEnd("120.00", ".0") = "12"
841 * </pre>
842 *
843 * @param str the String to removecharacters from, may be null
844 * @param stripChars the set ofcharacters to remove, null treated as whitespace
845 * @return the stripped String, {@code null} if null String input
846 */
847 public static String stripEnd(final String str, final String stripChars){
848 int end;
849 if (str == null || (end = str.length()) == 0) {
850 return str;
851 }
852
853 if (stripChars == null) {
854 while (end != 0 &&Character.isWhitespace(str.charAt(end - 1))) {
855 end--;
856 }
857 } else if (stripChars.isEmpty()) {
858 return str;
859 } else {
860 while (end != 0 &&stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
861 end--;
862 }
863 }
864 return str.substring(0, end);
865 }
866
867 // StripAll
868 //-----------------------------------------------------------------------
869 /**
870 * <p>Strips whitespace from the start and end of every String inan array.
871 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
872 *
873 * <p>A new array is returned each time, except for length zero.
874 * A {@code null} array will return {@code null}.
875 * An empty array will return itself.
876 * A {@code null} array entry will be ignored.</p>
877 *
878 * <pre>
879 * StringUtils.stripAll(null) = null
880 * StringUtils.stripAll([]) = []
881 * StringUtils.stripAll(["abc", " abc"]) = ["abc","abc"]
882 * StringUtils.stripAll(["abc ", null]) =["abc", null]
883 * </pre>
884 *
885 * @param strs the array to removewhitespace from, may be null
886 * @return the stripped Strings, {@code null} if null array input
887 */
888 public static String[] stripAll(final String... strs) {
889 return stripAll(strs, null);
890 }
891
892 /**
893 * <p>Strips any of a set of characters from the start and end ofevery
894 * String in an array.</p>
895 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
896 *
897 * <p>A new array is returned each time, except for length zero.
898 * A {@code null} array will return {@code null}.
899 * An empty array will return itself.
900 * A {@code null} array entry will be ignored.
901 * A {@code null} stripChars will strip whitespace as defined by
902 * {@link Character#isWhitespace(char)}.</p>
903 *
904 * <pre>
905 * StringUtils.stripAll(null, *) = null
906 * StringUtils.stripAll([], *) = []
907 * StringUtils.stripAll(["abc", " abc"], null) = ["abc","abc"]
908 * StringUtils.stripAll(["abc ", null], null) =["abc", null]
909 * StringUtils.stripAll(["abc ", null], "yz") =["abc ", null]
910 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null]
911 * </pre>
912 *
913 * @param strs the array to removecharacters from, may be null
914 * @param stripChars thecharacters to remove, null treated as whitespace
915 * @return the stripped Strings, {@code null} if null array input
916 */
917 public static String[] stripAll(final String[] strs, final StringstripChars) {
918 int strsLen;
919 if (strs == null || (strsLen = strs.length) == 0) {
920 return strs;
921 }
922 final String[] newArr = new String[strsLen];
923 for (int i = 0; i < strsLen; i++) {
924 newArr[i] = strip(strs[i],stripChars);
925 }
926 return newArr;
927 }
928
929 /**
930 * <p>Removes diacritics (~= accents) from a string. The case willnot be altered.</p>
931 * <p>For instance, 'à' will be replaced by'a'.</p>
932 * <p>Note that ligatures will be left as is.</p>
933 *
934 * <pre>
935 * StringUtils.stripAccents(null) = null
936 * StringUtils.stripAccents("") = ""
937 * StringUtils.stripAccents("control") = "control"
938 * StringUtils.stripAccents("éclair") = "eclair"
939 * </pre>
940 *
941 * @param input String to be stripped
942 * @return input text with diacritics removed
943 *
944 * @since 3.0
945 */
946 // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replacesaccented characters by their unaccented equivalent (and uncommitted bug fix:https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
947 public static String stripAccents(final String input) {
948 if(input == null) {
949 return null;
950 }
951 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
952 final StringBuilder decomposed = newStringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
953 convertRemainingAccentCharacters(decomposed);
954 // Note that this doesn't correctly remove ligatures...
955 return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY);
956 }
957
958 private static void convertRemainingAccentCharacters(final StringBuilderdecomposed) {
959 for (int i = 0; i <decomposed.length(); i++) {
960 if (decomposed.charAt(i) =='\u0141') {
961 decomposed.deleteCharAt(i);
962 decomposed.insert(i, 'L');
963 } else if (decomposed.charAt(i) =='\u0142') {
964 decomposed.deleteCharAt(i);
965 decomposed.insert(i, 'l');
966 }
967 }
968 }
969
970 // Equals
971 //-----------------------------------------------------------------------
972 /**
973 * <p>Compares twoCharSequences, returning {@code true} if they represent
974 * equal sequences of characters.</p>
975 *
976 * <p>{@code null}s are handled without exceptions. Two {@codenull}
977 * references are considered to be equal. The comparison is casesensitive.</p>
978 *
979 * <pre>
980 * StringUtils.equals(null, null) = true
981 * StringUtils.equals(null, "abc") = false
982 * StringUtils.equals("abc", null) = false
983 * StringUtils.equals("abc", "abc") = true
984 * StringUtils.equals("abc", "ABC") = false
985 * </pre>
986 *
987 * @see Object#equals(Object)
988 * @param cs1 the firstCharSequence, may be {@code null}
989 * @param cs2 the secondCharSequence, may be {@code null}
990 * @return {@code true} if the CharSequences are equal (case-sensitive),or both {@code null}
991 * @since 3.0 Changed signature from equals(String, String) toequals(CharSequence, CharSequence)
992 */
993 public static boolean equals(final CharSequence cs1, final CharSequencecs2) {
994 if (cs1 == cs2) {
995 return true;
996 }
997 if (cs1 == null || cs2 == null) {
998 return false;
999 }
1000 if (cs1.length() != cs2.length()) {
1001 return false;
1002 }
1003 if (cs1 instanceof String && cs2 instanceof String) {
1004 return cs1.equals(cs2);
1005 }
1006 return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0,cs1.length());
1007 }
1008
1009 /**
1010 * <p>Compares two CharSequences, returning {@code true} if theyrepresent
1011 * equal sequences of characters, ignoring case.</p>
1012 *
1013 * <p>{@code null}s are handled without exceptions. Two {@codenull}
1014 * references are considered equal. Comparison is caseinsensitive.</p>
1015 *
1016 * <pre>
1017 * StringUtils.equalsIgnoreCase(null, null) = true
1018 * StringUtils.equalsIgnoreCase(null, "abc") = false
1019 * StringUtils.equalsIgnoreCase("abc", null) = false
1020 * StringUtils.equalsIgnoreCase("abc", "abc") = true
1021 * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1022 * </pre>
1023 *
1024 * @param str1 the firstCharSequence, may be null
1025 * @param str2 the secondCharSequence, may be null
1026 * @return {@code true} if the CharSequence are equal, case insensitive,or
1027 * both {@code null}
1028 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) toequalsIgnoreCase(CharSequence, CharSequence)
1029 */
1030 public static boolean equalsIgnoreCase(final CharSequence str1, finalCharSequence str2) {
1031 if (str1 == null || str2 == null) {
1032 return str1 == str2;
1033 } else if (str1 == str2) {
1034 return true;
1035 } else if (str1.length() != str2.length()) {
1036 return false;
1037 } else {
1038 returnCharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length());
1039 }
1040 }
1041
1042 // Compare
1043 //-----------------------------------------------------------------------
1044 /**
1045 * <p>Compare two Strings lexicographically, as per {@linkString#compareTo(String)}, returning :</p>
1046 * <ul>
1047 * <li>{@code int = 0}, if{@code str1} is equal to {@code str2} (or both {@code null})</li>
1048 * <li>{@code int < 0},if {@code str1} is less than {@code str2}</li>
1049 * <li>{@code int > 0},if {@code str1} is greater than {@code str2}</li>
1050 * </ul>
1051 *
1052 * <p>This is a {@code null} safe version of :</p>
1053 *<blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1054 *
1055 * <p>{@code null} value is considered less than non-{@code null}value.
1056 * Two {@code null} references are considered equal.</p>
1057 *
1058 * <pre>
1059 * StringUtils.compare(null, null) = 0
1060 * StringUtils.compare(null , "a") < 0
1061 * StringUtils.compare("a", null) > 0
1062 * StringUtils.compare("abc", "abc") = 0
1063 * StringUtils.compare("a", "b") < 0
1064 * StringUtils.compare("b", "a") > 0
1065 * StringUtils.compare("a", "B") > 0
1066 * StringUtils.compare("ab", "abc") < 0
1067 * </pre>
1068 *
1069 * @see #compare(String, String, boolean)
1070 * @see String#compareTo(String)
1071 * @param str1 the String tocompare from
1072 * @param str2 the String tocompare to
1073 * @return < 0, 0, > 0, if {@code str1} is respectivelyless, equal or greater than {@code str2}
1074 * @since 3.5
1075 */
1076 public static int compare(final String str1, final String str2) {
1077 return compare(str1, str2, true);
1078 }
1079
1080 /**
1081 * <p>Compare two Strings lexicographically, as per {@linkString#compareTo(String)}, returning :</p>
1082 * <ul>
1083 * <li>{@code int = 0}, if{@code str1} is equal to {@code str2} (or both {@code null})</li>
1084 * <li>{@code int < 0},if {@code str1} is less than {@code str2}</li>
1085 * <li>{@code int > 0},if {@code str1} is greater than {@code str2}</li>
1086 * </ul>
1087 *
1088 * <p>This is a {@code null} safe version of :</p>
1089 *<blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1090 *
1091 * <p>{@code null} inputs are handled according to the {@codenullIsLess} parameter.
1092 * Two {@code null} references are considered equal.</p>
1093 *
1094 * <pre>
1095 * StringUtils.compare(null, null, *) = 0
1096 * StringUtils.compare(null , "a", true) < 0
1097 * StringUtils.compare(null , "a", false) > 0
1098 * StringUtils.compare("a", null, true) > 0
1099 * StringUtils.compare("a", null, false) < 0
1100 * StringUtils.compare("abc", "abc", *) = 0
1101 * StringUtils.compare("a", "b", *) < 0
1102 * StringUtils.compare("b", "a", *) > 0
1103 * StringUtils.compare("a", "B", *) > 0
1104 * StringUtils.compare("ab", "abc", *) < 0
1105 * </pre>
1106 *
1107 * @see String#compareTo(String)
1108 * @param str1 the String tocompare from
1109 * @param str2 the String tocompare to
1110 * @param nullIsLess whetherconsider {@code null} value less than non-{@code null} value
1111 * @return < 0, 0, > 0, if {@code str1} is respectivelyless, equal ou greater than {@code str2}
1112 * @since 3.5
1113 */
1114 public static int compare(final String str1, final String str2, finalboolean nullIsLess) {
1115 if (str1 == str2) {
1116 return 0;
1117 }
1118 if (str1 == null) {
1119 return nullIsLess ? -1 : 1;
1120 }
1121 if (str2 == null) {
1122 return nullIsLess ? 1 : - 1;
1123 }
1124 return str1.compareTo(str2);
1125 }
1126
1127 /**
1128 * <p>Compare two Strings lexicographically, ignoring casedifferences,
1129 * as per {@link String#compareToIgnoreCase(String)}, returning:</p>
1130 * <ul>
1131 * <li>{@code int = 0}, if{@code str1} is equal to {@code str2} (or both {@code null})</li>
1132 * <li>{@code int < 0},if {@code str1} is less than {@code str2}</li>
1133 * <li>{@code int > 0},if {@code str1} is greater than {@code str2}</li>
1134 * </ul>
1135 *
1136 * <p>This is a {@code null} safe version of :</p>
1137 *<blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1138 *
1139 * <p>{@code null} value is considered less than non-{@code null}value.
1140 * Two {@code null} references areconsidered equal.
1141 * Comparison is case insensitive.</p>
1142 *
1143 * <pre>
1144 * StringUtils.compareIgnoreCase(null, null) = 0
1145 * StringUtils.compareIgnoreCase(null , "a") < 0
1146 * StringUtils.compareIgnoreCase("a", null) > 0
1147 * StringUtils.compareIgnoreCase("abc", "abc") = 0
1148 * StringUtils.compareIgnoreCase("abc", "ABC") = 0
1149 * StringUtils.compareIgnoreCase("a", "b") < 0
1150 * StringUtils.compareIgnoreCase("b", "a") > 0
1151 * StringUtils.compareIgnoreCase("a", "B") < 0
1152 * StringUtils.compareIgnoreCase("A", "b") < 0
1153 * StringUtils.compareIgnoreCase("ab", "ABC") < 0
1154 * </pre>
1155 *
1156 * @see #compareIgnoreCase(String, String, boolean)
1157 * @see String#compareToIgnoreCase(String)
1158 * @param str1 the String tocompare from
1159 * @param str2 the String tocompare to
1160 * @return < 0, 0, > 0, if {@code str1} is respectivelyless, equal ou greater than {@code str2},
1161 * ignoring casedifferences.
1162 * @since 3.5
1163 */
1164 public static int compareIgnoreCase(final String str1, final Stringstr2) {
1165 return compareIgnoreCase(str1, str2, true);
1166 }
1167
1168 /**
1169 * <p>Compare two Strings lexicographically, ignoring casedifferences,
1170 * as per {@link String#compareToIgnoreCase(String)}, returning:</p>
1171 * <ul>
1172 * <li>{@code int = 0}, if{@code str1} is equal to {@code str2} (or both {@code null})</li>
1173 * <li>{@code int < 0},if {@code str1} is less than {@code str2}</li>
1174 * <li>{@code int > 0},if {@code str1} is greater than {@code str2}</li>
1175 * </ul>
1176 *
1177 * <p>This is a {@code null} safe version of :</p>
1178 *<blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1179 *
1180 * <p>{@code null} inputs are handled according to the {@codenullIsLess} parameter.
1181 * Two {@code null} references are considered equal.
1182 * Comparison is case insensitive.</p>
1183 *
1184 * <pre>
1185 * StringUtils.compareIgnoreCase(null, null, *) = 0
1186 * StringUtils.compareIgnoreCase(null , "a", true) < 0
1187 * StringUtils.compareIgnoreCase(null , "a", false) > 0
1188 * StringUtils.compareIgnoreCase("a", null, true) > 0
1189 * StringUtils.compareIgnoreCase("a", null, false) < 0
1190 * StringUtils.compareIgnoreCase("abc", "abc",*) = 0
1191 * StringUtils.compareIgnoreCase("abc", "ABC",*) = 0
1192 * StringUtils.compareIgnoreCase("a", "b", *) < 0
1193 * StringUtils.compareIgnoreCase("b", "a", *) > 0
1194 * StringUtils.compareIgnoreCase("a", "B", *) < 0
1195 * StringUtils.compareIgnoreCase("A", "b", *) < 0
1196 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0
1197 * </pre>
1198 *
1199 * @see String#compareToIgnoreCase(String)
1200 * @param str1 the String tocompare from
1201 * @param str2 the String tocompare to
1202 * @param nullIsLess whetherconsider {@code null} value less than non-{@code null} value
1203 * @return < 0, 0, > 0, if {@code str1} is respectivelyless, equal ou greater than {@code str2},
1204 * ignoring casedifferences.
1205 * @since 3.5
1206 */
1207 public static int compareIgnoreCase(final String str1, final Stringstr2, final boolean nullIsLess) {
1208 if (str1 == str2) {
1209 return 0;
1210 }
1211 if (str1 == null) {
1212 return nullIsLess ? -1 : 1;
1213 }
1214 if (str2 == null) {
1215 return nullIsLess ? 1 : - 1;
1216 }
1217 return str1.compareToIgnoreCase(str2);
1218 }
1219
1220 /**
1221 * <p>Compares given <code>string</code> to aCharSequences vararg of <code>searchStrings</code>,
1222 * returning {@code true} if the <code>string</code> is equalto any of the <code>searchStrings</code>.</p>
1223 *
1224 * <pre>
1225 * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1226 * StringUtils.equalsAny(null, null, null) = true
1227 * StringUtils.equalsAny(null, "abc", "def") = false
1228 * StringUtils.equalsAny("abc", null, "def") = false
1229 * StringUtils.equalsAny("abc", "abc","def") = true
1230 * StringUtils.equalsAny("abc", "ABC","DEF") = false
1231 * </pre>
1232 *
1233 * @param string to compare, may be {@code null}.
1234 * @param searchStrings a vararg of strings, may be {@code null}.
1235 * @return {@code true} if the string is equal (case-sensitive) to anyother element of <code>searchStrings</code>;
1236 * {@code false} if <code>searchStrings</code> is null orcontains no matches.
1237 * @since 3.5
1238 */
1239 public static boolean equalsAny(final CharSequence string, finalCharSequence... searchStrings) {
1240 if (ArrayUtils.isNotEmpty(searchStrings)) {
1241 for (final CharSequence next :searchStrings) {
1242 if (equals(string, next)) {
1243 return true;
1244 }
1245 }
1246 }
1247 return false;
1248 }
1249
1250
1251 /**
1252 * <p>Compares given <code>string</code> to aCharSequences vararg of <code>searchStrings</code>,
1253 * returning {@code true} if the <code>string</code> is equalto any of the <code>searchStrings</code>, ignoring case.</p>
1254 *
1255 * <pre>
1256 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1257 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true
1258 * StringUtils.equalsAnyIgnoreCase(null, "abc","def") = false
1259 * StringUtils.equalsAnyIgnoreCase("abc", null,"def") = false
1260 * StringUtils.equalsAnyIgnoreCase("abc", "abc","def") = true
1261 * StringUtils.equalsAnyIgnoreCase("abc", "ABC","DEF") = true
1262 * </pre>
1263 *
1264 * @param string to compare, may be {@code null}.
1265 * @param searchStrings a vararg of strings, may be {@code null}.
1266 * @return {@code true} if the string is equal (case-insensitive) to anyother element of <code>searchStrings</code>;
1267 * {@code false} if <code>searchStrings</code> is null orcontains no matches.
1268 * @since 3.5
1269 */
1270 public static boolean equalsAnyIgnoreCase(final CharSequence string,final CharSequence...searchStrings) {
1271 if (ArrayUtils.isNotEmpty(searchStrings)) {
1272 for (final CharSequence next :searchStrings) {
1273 if (equalsIgnoreCase(string,next)) {
1274 return true;
1275 }
1276 }
1277 }
1278 return false;
1279 }
1280
1281 // IndexOf
1282 //-----------------------------------------------------------------------
1283 /**
1284 * Returns the index within <code>seq</code> of the firstoccurrence of
1285 * the specified character. If a character with value
1286 * <code>searchChar</code> occurs in the character sequencerepresented by
1287 * <code>seq</code> <code>CharSequence</code>object, then the index (in Unicode
1288 * code units) of the first such occurrence is returned. For
1289 * values of <code>searchChar</code> in the range from 0 to0xFFFF
1290 * (inclusive), this is the smallest value <i>k</i> suchthat:
1291 * <blockquote><pre>
1292 * this.charAt(<i>k</i>) == searchChar
1293 * </pre></blockquote>
1294 * is true. For other values of <code>searchChar</code>, itis the
1295 * smallest value <i>k</i> such that:
1296 * <blockquote><pre>
1297 * this.codePointAt(<i>k</i>) == searchChar
1298 * </pre></blockquote>
1299 * is true. In either case, if no such character occurs in<code>seq</code>,
1300 * then {@code INDEX_NOT_FOUND (-1)} is returned.
1301 *
1302 * <p>Furthermore, a {@code null} or empty ("")CharSequence will
1303 * return {@code INDEX_NOT_FOUND (-1)}.</p>
1304 *
1305 * <pre>
1306 * StringUtils.indexOf(null, *) = -1
1307 * StringUtils.indexOf("", *) = -1
1308 * StringUtils.indexOf("aabaabaa", 'a') = 0
1309 * StringUtils.indexOf("aabaabaa", 'b') = 2
1310 * </pre>
1311 *
1312 * @param seq the CharSequence tocheck, may be null
1313 * @param searchChar the characterto find
1314 * @return the first index of the search character,
1315 * -1 if no match or {@code null}string input
1316 * @since 2.0
1317 * @since 3.0 Changed signature from indexOf(String, int) toindexOf(CharSequence, int)
1318 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like<code>String</code>
1319 */
1320 public static int indexOf(final CharSequence seq, final int searchChar){
1321 if (isEmpty(seq)) {
1322 return INDEX_NOT_FOUND;
1323 }
1324 return CharSequenceUtils.indexOf(seq, searchChar, 0);
1325 }
1326
1327 /**
1328 *
1329 * Returns the index within <code>seq</code> of the firstoccurrence of the
1330 * specified character, starting the search at the specified index.
1331 * <p>
1332 * If a character with value <code>searchChar</code> occursin the
1333 * character sequence represented by the <code>seq</code><code>CharSequence</code>
1334 * object at an index no smaller than <code>startPos</code>,then
1335 * the index of the first such occurrence is returned. For values
1336 * of <code>searchChar</code> in the range from 0 to 0xFFFF(inclusive),
1337 * this is the smallest value <i>k</i> such that:
1338 * <blockquote><pre>
1339 * (this.charAt(<i>k</i>) == searchChar) &&(<i>k</i> >= startPos)
1340 * </pre></blockquote>
1341 * is true. For other values of <code>searchChar</code>, itis the
1342 * smallest value <i>k</i> such that:
1343 * <blockquote><pre>
1344 * (this.codePointAt(<i>k</i>) == searchChar) &&(<i>k</i> >= startPos)
1345 * </pre></blockquote>
1346 * is true. In either case, if no such character occurs in<code>seq</code>
1347 * at or after position <code>startPos</code>, then
1348 * <code>-1</code> is returned.
1349 *
1350 * <p>
1351 * There is no restriction on the value of<code>startPos</code>. If it
1352 * is negative, it has the same effect as if it were zero: this entire
1353 * string may be searched. If it is greater than the length of this
1354 * string, it has the same effect as if it were equal to the length of
1355 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
1356 * {@code null} or empty ("") CharSequence will
1357 * return {@code (INDEX_NOT_FOUND) -1}.
1358 *
1359 * <p>All indices are specified in <code>char</code>values
1360 * (Unicode code units).
1361 *
1362 * <pre>
1363 * StringUtils.indexOf(null, *, *) = -1
1364 * StringUtils.indexOf("", *, *) = -1
1365 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
1366 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
1367 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
1368 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
1369 * </pre>
1370 *
1371 * @param seq the CharSequence tocheck, may be null
1372 * @param searchChar the characterto find
1373 * @param startPos the startposition, negative treated as zero
1374 * @return the first index of the search character (always ≥startPos),
1375 * -1 if no match or {@code null}string input
1376 * @since 2.0
1377 * @since 3.0 Changed signature from indexOf(String, int, int) toindexOf(CharSequence, int, int)
1378 * @since 3.6 Updated {@linkCharSequenceUtils} call to behave more like <code>String</code>
1379 */
1380 public static int indexOf(final CharSequence seq, final int searchChar,final int startPos) {
1381 if (isEmpty(seq)) {
1382 return INDEX_NOT_FOUND;
1383 }
1384 return CharSequenceUtils.indexOf(seq, searchChar, startPos);
1385 }
1386
1387 /**
1388 * <p>Finds the first index within a CharSequence, handling {@codenull}.
1389 * This method uses {@link String#indexOf(String, int)} ifpossible.</p>
1390 *
1391 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1392 *
1393 * <pre>
1394 * StringUtils.indexOf(null, *) = -1
1395 * StringUtils.indexOf(*, null) = -1
1396 * StringUtils.indexOf("", "") = 0
1397 * StringUtils.indexOf("", *) = -1 (except when * = "")
1398 * StringUtils.indexOf("aabaabaa", "a") = 0
1399 * StringUtils.indexOf("aabaabaa", "b") = 2
1400 * StringUtils.indexOf("aabaabaa", "ab") = 1
1401 * StringUtils.indexOf("aabaabaa", "") = 0
1402 * </pre>
1403 *
1404 * @param seq the CharSequence tocheck, may be null
1405 * @param searchSeq theCharSequence to find, may be null
1406 * @return the first index of the search CharSequence,
1407 * -1 if no match or {@code null}string input
1408 * @since 2.0
1409 * @since 3.0 Changed signature from indexOf(String, String) toindexOf(CharSequence, CharSequence)
1410 */
1411 public static int indexOf(final CharSequence seq, final CharSequencesearchSeq) {
1412 if (seq == null || searchSeq == null) {
1413 return INDEX_NOT_FOUND;
1414 }
1415 return CharSequenceUtils.indexOf(seq, searchSeq, 0);
1416 }
1417
1418 /**
1419 * <p>Finds the first index within a CharSequence, handling {@codenull}.
1420 * This method uses {@link String#indexOf(String, int)} ifpossible.</p>
1421 *
1422 * <p>A {@code null} CharSequence will return {@code -1}.
1423 * A negative start position is treated as zero.
1424 * An empty ("") search CharSequence always matches.
1425 * A start position greater than the stringlength only matches
1426 * an empty search CharSequence.</p>
1427 *
1428 * <pre>
1429 * StringUtils.indexOf(null, *, *) = -1
1430 * StringUtils.indexOf(*, null, *) = -1
1431 * StringUtils.indexOf("", "", 0) = 0
1432 * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
1433 * StringUtils.indexOf("aabaabaa", "a", 0) = 0
1434 * StringUtils.indexOf("aabaabaa", "b", 0) = 2
1435 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
1436 * StringUtils.indexOf("aabaabaa", "b", 3) = 5
1437 * StringUtils.indexOf("aabaabaa", "b", 9) = -1
1438 * StringUtils.indexOf("aabaabaa", "b", -1) = 2
1439 * StringUtils.indexOf("aabaabaa", "", 2) = 2
1440 * StringUtils.indexOf("abc", "", 9) = 3
1441 * </pre>
1442 *
1443 * @param seq the CharSequence tocheck, may be null
1444 * @param searchSeq theCharSequence to find, may be null
1445 * @param startPos the startposition, negative treated as zero
1446 * @return the first index of the search CharSequence (always ≥startPos),
1447 * -1 if no match or {@code null}string input
1448 * @since 2.0
1449 * @since 3.0 Changed signature from indexOf(String, String, int) toindexOf(CharSequence, CharSequence, int)
1450 */
1451 public static int indexOf(final CharSequence seq, final CharSequencesearchSeq, final int startPos) {
1452 if (seq == null || searchSeq == null) {
1453 return INDEX_NOT_FOUND;
1454 }
1455 return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
1456 }
1457
1458 /**
1459 * <p>Finds the n-th index within a CharSequence, handling {@codenull}.
1460 * This method uses {@link String#indexOf(String)} if possible.</p>
1461 * <p><b>Note:</b> The code starts looking for a matchat the start of the target,
1462 * incrementing the starting index by one after each successful match
1463 * (unless {@code searchStr} is an empty string in which case theposition
1464 * is never incremented and {@code 0} is returned immediately).
1465 * This means that matches may overlap.</p>
1466 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1467 *
1468 * <pre>
1469 * StringUtils.ordinalIndexOf(null, *, *) = -1
1470 * StringUtils.ordinalIndexOf(*, null, *) = -1
1471 * StringUtils.ordinalIndexOf("", "", *) = 0
1472 * StringUtils.ordinalIndexOf("aabaabaa", "a",1) = 0
1473 * StringUtils.ordinalIndexOf("aabaabaa", "a",2) = 1
1474 * StringUtils.ordinalIndexOf("aabaabaa", "b",1) = 2
1475 * StringUtils.ordinalIndexOf("aabaabaa", "b",2) = 5
1476 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) =1
1477 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) =4
1478 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
1479 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
1480 * </pre>
1481 *
1482 * <p>Matches may overlap:</p>
1483 * <pre>
1484 * StringUtils.ordinalIndexOf("ababab","aba", 1) = 0
1485 * StringUtils.ordinalIndexOf("ababab","aba", 2) = 2
1486 * StringUtils.ordinalIndexOf("ababab","aba", 3) = -1
1487 *
1488 * StringUtils.ordinalIndexOf("abababab", "abab", 1)= 0
1489 * StringUtils.ordinalIndexOf("abababab", "abab", 2)= 2
1490 * StringUtils.ordinalIndexOf("abababab", "abab", 3)= 4
1491 * StringUtils.ordinalIndexOf("abababab", "abab", 4)= -1
1492 * </pre>
1493 *
1494 * <p>Note that 'head(CharSequence str, int n)' may be implementedas: </p>
1495 *
1496 * <pre>
1497 * str.substring(0, lastOrdinalIndexOf(str,"\n", n))
1498 * </pre>
1499 *
1500 * @param str the CharSequence tocheck, may be null
1501 * @param searchStr theCharSequence to find, may be null
1502 * @param ordinal the n-th {@codesearchStr} to find
1503 * @return the n-th index of the search CharSequence,
1504 * {@code -1} ({@codeINDEX_NOT_FOUND}) if no match or {@code null} string input
1505 * @since 2.1
1506 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int)to ordinalIndexOf(CharSequence, CharSequence, int)
1507 */
1508 public static int ordinalIndexOf(final CharSequence str, finalCharSequence searchStr, final int ordinal) {
1509 return ordinalIndexOf(str, searchStr, ordinal, false);
1510 }
1511
1512 /**
1513 * <p>Finds the n-th index within a String, handling {@code null}.
1514 * This method uses {@link String#indexOf(String)} if possible.</p>
1515 * <p>Note that matches may overlap<p>
1516 *
1517 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1518 *
1519 * @param str the CharSequence tocheck, may be null
1520 * @param searchStr theCharSequence to find, may be null
1521 * @param ordinal the n-th {@codesearchStr} to find, overlapping matches are allowed.
1522 * @param lastIndex true if lastOrdinalIndexOf() otherwise false ifordinalIndexOf()
1523 * @return the n-th index of the search CharSequence,
1524 * {@code -1} ({@codeINDEX_NOT_FOUND}) if no match or {@code null} string input
1525 */
1526 // Shared code between ordinalIndexOf(String,String,int) andlastOrdinalIndexOf(String,String,int)
1527 private static int ordinalIndexOf(final CharSequence str, finalCharSequence searchStr, final int ordinal, final boolean lastIndex) {
1528 if (str == null || searchStr == null || ordinal <= 0) {
1529 return INDEX_NOT_FOUND;
1530 }
1531 if (searchStr.length() == 0) {
1532 return lastIndex ? str.length() :0;
1533 }
1534 int found = 0;
1535 // set the initial index beyond the end of the string
1536 // this is to allow for the initial index decrement/increment
1537 int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
1538 do {
1539 if (lastIndex) {
1540 index =CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwardsthru string
1541 } else {
1542 index = CharSequenceUtils.indexOf(str,searchStr, index + 1); // step forwards through string
1543 }
1544 if (index < 0) {
1545 return index;
1546 }
1547 found++;
1548 } while (found < ordinal);
1549 return index;
1550 }
1551
1552 /**
1553 * <p>Case in-sensitive find of the first index within aCharSequence.</p>
1554 *
1555 * <p>A {@code null} CharSequence will return {@code -1}.
1556 * A negative start position is treated as zero.
1557 * An empty ("") search CharSequence always matches.
1558 * A start position greater than the string length only matches
1559 * an empty search CharSequence.</p>
1560 *
1561 * <pre>
1562 * StringUtils.indexOfIgnoreCase(null, *) = -1
1563 * StringUtils.indexOfIgnoreCase(*, null) = -1
1564 * StringUtils.indexOfIgnoreCase("", "") = 0
1565 * StringUtils.indexOfIgnoreCase("aabaabaa","a") = 0
1566 * StringUtils.indexOfIgnoreCase("aabaabaa","b") = 2
1567 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") =1
1568 * </pre>
1569 *
1570 * @param str the CharSequence tocheck, may be null
1571 * @param searchStr the CharSequenceto find, may be null
1572 * @return the first index of the search CharSequence,
1573 * -1 if no match or {@code null}string input
1574 * @since 2.5
1575 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) toindexOfIgnoreCase(CharSequence, CharSequence)
1576 */
1577 public static int indexOfIgnoreCase(final CharSequence str, finalCharSequence searchStr) {
1578 return indexOfIgnoreCase(str, searchStr, 0);
1579 }
1580
1581 /**
1582 * <p>Case in-sensitive find of the first index within aCharSequence
1583 * from the specified position.</p>
1584 *
1585 * <p>A {@code null} CharSequence will return {@code -1}.
1586 * A negative start position is treated as zero.
1587 * An empty ("") search CharSequence always matches.
1588 * A start position greater than the string length only matches
1589 * an empty search CharSequence.</p>
1590 *
1591 * <pre>
1592 * StringUtils.indexOfIgnoreCase(null, *, *) = -1
1593 * StringUtils.indexOfIgnoreCase(*, null, *) = -1
1594 * StringUtils.indexOfIgnoreCase("", "", 0) = 0
1595 * StringUtils.indexOfIgnoreCase("aabaabaa", "A",0) = 0
1596 * StringUtils.indexOfIgnoreCase("aabaabaa", "B",0) = 2
1597 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0)= 1
1598 * StringUtils.indexOfIgnoreCase("aabaabaa", "B",3) = 5
1599 * StringUtils.indexOfIgnoreCase("aabaabaa", "B",9) = -1
1600 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1)= 2
1601 * StringUtils.indexOfIgnoreCase("aabaabaa", "",2) = 2
1602 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1
1603 * </pre>
1604 *
1605 * @param str the CharSequence tocheck, may be null
1606 * @param searchStr theCharSequence to find, may be null
1607 * @param startPos the startposition, negative treated as zero
1608 * @return the first index of the search CharSequence (always ≥startPos),
1609 * -1 if no match or {@code null}string input
1610 * @since 2.5
1611 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String,int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1612 */
1613 public static int indexOfIgnoreCase(final CharSequence str, finalCharSequence searchStr, int startPos) {
1614 if (str == null || searchStr == null) {
1615 return INDEX_NOT_FOUND;
1616 }
1617 if (startPos < 0) {
1618 startPos = 0;
1619 }
1620 final int endLimit = str.length() - searchStr.length() + 1;
1621 if (startPos > endLimit) {
1622 return INDEX_NOT_FOUND;
1623 }
1624 if (searchStr.length() == 0) {
1625 return startPos;
1626 }
1627 for (int i = startPos; i < endLimit; i++) {
1628 if(CharSequenceUtils.regionMatches(str, true, i, searchStr, 0,searchStr.length())) {
1629 return i;
1630 }
1631 }
1632 return INDEX_NOT_FOUND;
1633 }
1634
1635 // LastIndexOf
1636 //-----------------------------------------------------------------------
1637 /**
1638 * Returns the index within <code>seq</code> of the lastoccurrence of
1639 * the specified character. For values of<code>searchChar</code> in the
1640 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
1641 * units) returned is the largest value <i>k</i> such that:
1642 * <blockquote><pre>
1643 * this.charAt(<i>k</i>) == searchChar
1644 * </pre></blockquote>
1645 * is true. For other values of <code>searchChar</code>, itis the
1646 * largest value <i>k</i> such that:
1647 * <blockquote><pre>
1648 * this.codePointAt(<i>k</i>) == searchChar
1649 * </pre></blockquote>
1650 * is true. In either case, if nosuch character occurs in this
1651 * string, then <code>-1</code> is returned. Furthermore, a{@code null} or empty ("")
1652 * <code>CharSequence</code> will return {@code -1}. The
1653 * <code>seq</code> <code>CharSequence</code>object is searched backwards
1654 * starting at the last character.
1655 *
1656 * <pre>
1657 * StringUtils.lastIndexOf(null, *) = -1
1658 * StringUtils.lastIndexOf("", *) = -1
1659 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1660 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1661 * </pre>
1662 *
1663 * @param seq the<code>CharSequence</code> to check, may be null
1664 * @param searchChar the characterto find
1665 * @return the last index of the search character,
1666 * -1 if no match or {@code null}string input
1667 * @since 2.0
1668 * @since 3.0 Changed signature from lastIndexOf(String, int) tolastIndexOf(CharSequence, int)
1669 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like<code>String</code>
1670 */
1671 public static int lastIndexOf(final CharSequence seq, final intsearchChar) {
1672 if (isEmpty(seq)) {
1673 return INDEX_NOT_FOUND;
1674 }
1675 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1676 }
1677
1678 /**
1679 * Returns the index within <code>seq</code> of the lastoccurrence of
1680 * the specified character, searching backward starting at the
1681 * specified index. For values of <code>searchChar</code> inthe range
1682 * from 0 to 0xFFFF (inclusive), the index returned is the largest
1683 * value <i>k</i> such that:
1684 * <blockquote><pre>
1685 * (this.charAt(<i>k</i>) == searchChar) &&(<i>k</i> <= startPos)
1686 * </pre></blockquote>
1687 * is true. For other values of <code>searchChar</code>, itis the
1688 * largest value <i>k</i> such that:
1689 * <blockquote><pre>
1690 * (this.codePointAt(<i>k</i>) == searchChar)&& (<i>k</i> <= startPos)
1691 * </pre></blockquote>
1692 * is true. In either case, if no such character occurs in<code>seq</code>
1693 * at or before position<code>startPos</code>, then
1694 * <code>-1</code> is returned. Furthermore, a {@code null}or empty ("")
1695 * <code>CharSequence</code> will return {@code -1}. A startposition greater
1696 * than the string length searches the whole string.
1697 * The search starts at the <code>startPos</code> and worksbackwards;
1698 * matches starting after the start position are ignored.
1699 *
1700 * <p>All indices are specified in <code>char</code>values
1701 * (Unicode code units).
1702 *
1703 * <pre>
1704 * StringUtils.lastIndexOf(null, *, *) = -1
1705 * StringUtils.lastIndexOf("", *, *) = -1
1706 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
1707 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
1708 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
1709 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
1710 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1711 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
1712 * </pre>
1713 *
1714 * @param seq the CharSequence tocheck, may be null
1715 * @param searchChar the characterto find
1716 * @param startPos the startposition
1717 * @return the last index of the search character (always ≤startPos),
1718 * -1 if no match or {@code null}string input
1719 * @since 2.0
1720 * @since 3.0 Changed signature from lastIndexOf(String, int, int) tolastIndexOf(CharSequence, int, int)
1721 */
1722 public static int lastIndexOf(final CharSequence seq, final intsearchChar, final int startPos) {
1723 if (isEmpty(seq)) {
1724 return INDEX_NOT_FOUND;
1725 }
1726 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1727 }
1728
1729 /**
1730 * <p>Finds the last index within a CharSequence, handling {@codenull}.
1731 * This method uses {@link String#lastIndexOf(String)} ifpossible.</p>
1732 *
1733 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1734 *
1735 * <pre>
1736 * StringUtils.lastIndexOf(null, *) = -1
1737 * StringUtils.lastIndexOf(*, null) = -1
1738 * StringUtils.lastIndexOf("", "") = 0
1739 * StringUtils.lastIndexOf("aabaabaa", "a") = 7
1740 * StringUtils.lastIndexOf("aabaabaa", "b") = 5
1741 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1742 * StringUtils.lastIndexOf("aabaabaa", "") = 8
1743 * </pre>
1744 *
1745 * @param seq the CharSequence tocheck, may be null
1746 * @param searchSeq theCharSequence to find, may be null
1747 * @return the last index of the search String,
1748 * -1 if no match or {@code null}string input
1749 * @since 2.0
1750 * @since 3.0 Changed signature from lastIndexOf(String, String) tolastIndexOf(CharSequence, CharSequence)
1751 */
1752 public static int lastIndexOf(final CharSequence seq, final CharSequencesearchSeq) {
1753 if (seq == null || searchSeq == null) {
1754 return INDEX_NOT_FOUND;
1755 }
1756 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1757 }
1758
1759 /**
1760 * <p>Finds the n-th last index within a String, handling {@code null}.
1761 * This method uses {@link String#lastIndexOf(String)}.</p>
1762 *
1763 * <p>A {@code null} String will return {@code -1}.</p>
1764 *
1765 * <pre>
1766 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
1767 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
1768 * StringUtils.lastOrdinalIndexOf("", "", *) = 0
1769 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a",1) = 7
1770 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a",2) = 6
1771 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b",1) = 5
1772 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b",2) = 2
1773 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab",1) = 4
1774 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab",2) = 1
1775 * StringUtils.lastOrdinalIndexOf("aabaabaa", "",1) = 8
1776 * StringUtils.lastOrdinalIndexOf("aabaabaa", "",2) = 8
1777 * </pre>
1778 *
1779 * <p>Note that 'tail(CharSequence str, int n)' may be implementedas: </p>
1780 *
1781 * <pre>
1782 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1783 * </pre>
1784 *
1785 * @param str the CharSequence tocheck, may be null
1786 * @param searchStr the CharSequence to find, may be null
1787 * @param ordinal the n-th last{@code searchStr} to find
1788 * @return the n-th last index of the search CharSequence,
1789 * {@code -1} ({@codeINDEX_NOT_FOUND}) if no match or {@code null} string input
1790 * @since 2.5
1791 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String,int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1792 */
1793 public static int lastOrdinalIndexOf(final CharSequence str, finalCharSequence searchStr, final int ordinal) {
1794 return ordinalIndexOf(str, searchStr, ordinal, true);
1795 }
1796
1797 /**
1798 * <p>Finds the last index within a CharSequence, handling {@codenull}.
1799 * This method uses {@link String#lastIndexOf(String, int)} ifpossible.</p>
1800 *
1801 * <p>A {@code null} CharSequence will return {@code -1}.
1802 * A negative start position returns {@code -1}.
1803 * An empty ("") search CharSequence always matches unless thestart position is negative.
1804 * A start position greater than the string length searches the wholestring.
1805 * The search starts at the startPos and works backwards; matchesstarting after the start
1806 * position are ignored.
1807 * </p>
1808 *
1809 * <pre>
1810 * StringUtils.lastIndexOf(null, *, *) = -1
1811 * StringUtils.lastIndexOf(*, null, *) = -1
1812 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
1813 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
1814 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1815 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
1816 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1817 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
1818 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
1819 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1
1820 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2
1821 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = -1
1822 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2
1823 * </pre>
1824 *
1825 * @param seq the CharSequence tocheck, may be null
1826 * @param searchSeq theCharSequence to find, may be null
1827 * @param startPos the startposition, negative treated as zero
1828 * @return the last index of the search CharSequence (always ≤startPos),
1829 * -1 if no match or {@code null}string input
1830 * @since 2.0
1831 * @since 3.0 Changed signature from lastIndexOf(String, String, int) tolastIndexOf(CharSequence, CharSequence, int)
1832 */
1833 public static int lastIndexOf(final CharSequence seq, final CharSequencesearchSeq, final int startPos) {
1834 if (seq == null || searchSeq == null) {
1835 return INDEX_NOT_FOUND;
1836 }
1837 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1838 }
1839
1840 /**
1841 * <p>Case in-sensitive find of the last index within aCharSequence.</p>
1842 *
1843 * <p>A {@code null} CharSequence will return {@code -1}.
1844 * A negative start position returns {@code -1}.
1845 * An empty ("") search CharSequence always matches unless thestart position is negative.
1846 * A start position greater than the string length searches the wholestring.</p>
1847 *
1848 * <pre>
1849 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
1850 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
1851 * StringUtils.lastIndexOfIgnoreCase("aabaabaa","A") = 7
1852 * StringUtils.lastIndexOfIgnoreCase("aabaabaa","B") = 5
1853 * StringUtils.lastIndexOfIgnoreCase("aabaabaa","AB") = 4
1854 * </pre>
1855 *
1856 * @param str the CharSequence tocheck, may be null
1857 * @param searchStr theCharSequence to find, may be null
1858 * @return the first index of the search CharSequence,
1859 * -1 if no match or {@code null}string input
1860 * @since 2.5
1861 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String,String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1862 */
1863 public static int lastIndexOfIgnoreCase(final CharSequence str, finalCharSequence searchStr) {
1864 if (str == null || searchStr == null) {
1865 return INDEX_NOT_FOUND;
1866 }
1867 return lastIndexOfIgnoreCase(str, searchStr, str.length());
1868 }
1869
1870 /**
1871 * <p>Case in-sensitive find of the last index within aCharSequence
1872 * from the specified position.</p>
1873 *
1874 * <p>A {@code null} CharSequence will return {@code -1}.
1875 * A negative start position returns {@code -1}.
1876 * An empty ("") search CharSequence always matches unless thestart position is negative.
1877 * A start position greater than the string length searches the wholestring.
1878 * The search starts at the startPos and works backwards; matchesstarting after the start
1879 * position are ignored.
1880 * </p>
1881 *
1882 * <pre>
1883 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
1884 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
1885 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A",8) = 7
1886 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B",8) = 5
1887 * StringUtils.lastIndexOfIgnoreCase("aabaabaa","AB", 8) = 4
1888 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B",9) = 5
1889 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B",-1) = -1
1890 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A",0) = 0
1891 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B",0) = -1
1892 * </pre>
1893 *
1894 * @param str the CharSequence tocheck, may be null
1895 * @param searchStr theCharSequence to find, may be null
1896 * @param startPos the startposition
1897 * @return the last index of the search CharSequence (always ≤startPos),
1898 * -1 if no match or {@code null}input
1899 * @since 2.5
1900 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String,String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1901 */
1902 public static int lastIndexOfIgnoreCase(final CharSequence str, finalCharSequence searchStr, int startPos) {
1903 if (str == null || searchStr == null) {
1904 return INDEX_NOT_FOUND;
1905 }
1906 if (startPos > str.length() - searchStr.length()) {
1907 startPos = str.length() -searchStr.length();
1908 }
1909 if (startPos < 0) {
1910 return INDEX_NOT_FOUND;
1911 }
1912 if (searchStr.length() == 0) {
1913 return startPos;
1914 }
1915
1916 for (int i = startPos; i >= 0; i--) {
1917 if(CharSequenceUtils.regionMatches(str, true, i, searchStr, 0,searchStr.length())) {
1918 return i;
1919 }
1920 }
1921 return INDEX_NOT_FOUND;
1922 }
1923
1924 // Contains
1925 //-----------------------------------------------------------------------
1926 /**
1927 * <p>Checks if CharSequence contains a search character, handling{@code null}.
1928 * This method uses {@link String#indexOf(int)} if possible.</p>
1929 *
1930 * <p>A {@code null} or empty ("") CharSequence willreturn {@code false}.</p>
1931 *
1932 * <pre>
1933 * StringUtils.contains(null, *) = false
1934 * StringUtils.contains("", *) = false
1935 * StringUtils.contains("abc", 'a') = true
1936 * StringUtils.contains("abc", 'z') = false
1937 * </pre>
1938 *
1939 * @param seq the CharSequence tocheck, may be null
1940 * @param searchChar the characterto find
1941 * @return true if the CharSequence contains the search character,
1942 * false if not or {@code null}string input
1943 * @since 2.0
1944 * @since 3.0 Changed signature from contains(String, int) tocontains(CharSequence, int)
1945 */
1946 public static boolean contains(final CharSequence seq, final intsearchChar) {
1947 if (isEmpty(seq)) {
1948 return false;
1949 }
1950 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1951 }
1952
1953 /**
1954 * <p>Checks if CharSequence contains a search CharSequence,handling {@code null}.
1955 * This method uses {@link String#indexOf(String)} if possible.</p>
1956 *
1957 * <p>A {@code null} CharSequence will return {@code false}.</p>
1958 *
1959 * <pre>
1960 * StringUtils.contains(null, *) = false
1961 * StringUtils.contains(*, null) = false
1962 * StringUtils.contains("", "") = true
1963 * StringUtils.contains("abc", "") = true
1964 * StringUtils.contains("abc", "a") = true
1965 * StringUtils.contains("abc", "z") = false
1966 * </pre>
1967 *
1968 * @param seq the CharSequence tocheck, may be null
1969 * @param searchSeq theCharSequence to find, may be null
1970 * @return true if the CharSequence contains the search CharSequence,
1971 * false if not or {@code null}string input
1972 * @since 2.0
1973 * @since 3.0 Changed signature from contains(String, String) tocontains(CharSequence, CharSequence)
1974 */
1975 public static boolean contains(final CharSequence seq, finalCharSequence searchSeq) {
1976 if (seq == null || searchSeq == null) {
1977 return false;
1978 }
1979 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1980 }
1981
1982 /**
1983 * <p>Checks if CharSequence contains a search CharSequenceirrespective of case,
1984 * handling {@code null}. Case-insensitivity is defined as by
1985 * {@link String#equalsIgnoreCase(String)}.
1986 *
1987 * <p>A {@code null} CharSequence will return {@codefalse}.</p>
1988 *
1989 * <pre>
1990 * StringUtils.containsIgnoreCase(null, *) = false
1991 * StringUtils.containsIgnoreCase(*, null) = false
1992 * StringUtils.containsIgnoreCase("", "") = true
1993 * StringUtils.containsIgnoreCase("abc", "") = true
1994 * StringUtils.containsIgnoreCase("abc", "a") = true
1995 * StringUtils.containsIgnoreCase("abc", "z") = false
1996 * StringUtils.containsIgnoreCase("abc", "A") = true
1997 * StringUtils.containsIgnoreCase("abc", "Z") = false
1998 * </pre>
1999 *
2000 * @param str the CharSequence tocheck, may be null
2001 * @param searchStr theCharSequence to find, may be null
2002 * @return true if the CharSequence contains the search CharSequenceirrespective of
2003 * case or false if not or {@code null} string input
2004 * @since 3.0 Changed signature from containsIgnoreCase(String, String)to containsIgnoreCase(CharSequence, CharSequence)
2005 */
2006 public static boolean containsIgnoreCase(final CharSequence str, finalCharSequence searchStr) {
2007 if (str == null || searchStr == null) {
2008 return false;
2009 }
2010 final int len = searchStr.length();
2011 final int max = str.length() - len;
2012 for (int i = 0; i <= max; i++) {
2013 if(CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
2014 return true;
2015 }
2016 }
2017 return false;
2018 }
2019
2020 /**
2021 * <p>Check whether the given CharSequence contains any whitespacecharacters.</p>
2022 *
2023 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
2024 *
2025 * @param seq the CharSequence to check (may be {@code null})
2026 * @return {@code true} if the CharSequence is not empty and
2027 * contains at least 1 (breaking) whitespace character
2028 * @since 3.0
2029 */
2030 // From org.springframework.util.StringUtils, under Apache License 2.0
2031 public static boolean containsWhitespace(final CharSequence seq) {
2032 if (isEmpty(seq)) {
2033 return false;
2034 }
2035 final int strLen = seq.length();
2036 for (int i = 0; i < strLen; i++) {
2037 if(Character.isWhitespace(seq.charAt(i))) {
2038 return true;
2039 }
2040 }
2041 return false;
2042 }
2043
2044 // IndexOfAny chars
2045 //-----------------------------------------------------------------------
2046 /**
2047 * <p>Search a CharSequence to find the first index of any
2048 * character in the given set of characters.</p>
2049 *
2050 * <p>A {@code null} String will return {@code -1}.
2051 * A {@code null} or zero length search array will return {@code-1}.</p>
2052 *
2053 * <pre>
2054 * StringUtils.indexOfAny(null, *) = -1
2055 * StringUtils.indexOfAny("", *) = -1
2056 * StringUtils.indexOfAny(*, null) = -1
2057 * StringUtils.indexOfAny(*, []) = -1
2058 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
2059 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
2060 * StringUtils.indexOfAny("aba", ['z']) = -1
2061 * </pre>
2062 *
2063 * @param cs the CharSequence tocheck, may be null
2064 * @param searchChars the chars tosearch for, may be null
2065 * @return the index of any of the chars, -1 if no match or null input
2066 * @since 2.0
2067 * @since 3.0 Changed signaturefrom indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2068 */
2069 public static int indexOfAny(final CharSequence cs, final char...searchChars) {
2070 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2071 return INDEX_NOT_FOUND;
2072 }
2073 final int csLen = cs.length();
2074 final int csLast = csLen - 1;
2075 final int searchLen = searchChars.length;
2076 final int searchLast = searchLen - 1;
2077 for (int i = 0; i < csLen; i++) {
2078 final char ch = cs.charAt(i);
2079 for (int j = 0; j < searchLen;j++) {
2080 if (searchChars[j] == ch) {
2081 if (i < csLast&& j < searchLast && Character.isHighSurrogate(ch)) {
2082 // ch is asupplementary character
2083 if (searchChars[j + 1]== cs.charAt(i + 1)) {
2084 return i;
2085 }
2086 } else {
2087 return i;
2088 }
2089 }
2090 }
2091 }
2092 return INDEX_NOT_FOUND;
2093 }
2094
2095 /**
2096 * <p>Search a CharSequence to find the first index of any
2097 * character in the given set of characters.</p>
2098 *
2099 * <p>A {@code null} String will return {@code -1}.
2100 * A {@code null} search string will return {@code -1}.</p>
2101 *
2102 * <pre>
2103 * StringUtils.indexOfAny(null, *) = -1
2104 * StringUtils.indexOfAny("", *) = -1
2105 * StringUtils.indexOfAny(*, null) = -1
2106 * StringUtils.indexOfAny(*, "") = -1
2107 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2108 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2109 * StringUtils.indexOfAny("aba","z") = -1
2110 * </pre>
2111 *
2112 * @param cs the CharSequence tocheck, may be null
2113 * @param searchChars the chars tosearch for, may be null
2114 * @return the index of any of the chars, -1 if no match or null input
2115 * @since 2.0
2116 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence,String)
2117 */
2118 public static int indexOfAny(final CharSequence cs, final StringsearchChars) {
2119 if (isEmpty(cs) || isEmpty(searchChars)) {
2120 return INDEX_NOT_FOUND;
2121 }
2122 return indexOfAny(cs, searchChars.toCharArray());
2123 }
2124
2125 // ContainsAny
2126 //-----------------------------------------------------------------------
2127 /**
2128 * <p>Checks if the CharSequence contains any character in thegiven
2129 * set of characters.</p>
2130 *
2131 * <p>A {@code null} CharSequence will return {@code false}.
2132 * A {@code null} or zero length search array will return {@codefalse}.</p>
2133 *
2134 * <pre>
2135 * StringUtils.containsAny(null, *) = false
2136 * StringUtils.containsAny("", *) = false
2137 * StringUtils.containsAny(*, null) = false
2138 * StringUtils.containsAny(*, []) = false
2139 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
2140 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
2141 * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
2142 * StringUtils.containsAny("aba", ['z']) = false
2143 * </pre>
2144 *
2145 * @param cs the CharSequence tocheck, may be null
2146 * @param searchChars the chars tosearch for, may be null
2147 * @return the {@code true} if any of the chars are found,
2148 * {@code false} if no match or null input
2149 * @since 2.4
2150 * @since 3.0 Changed signature from containsAny(String, char[]) tocontainsAny(CharSequence, char...)
2151 */
2152 public static boolean containsAny(final CharSequence cs, final char...searchChars) {
2153 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2154 return false;
2155 }
2156 final int csLength = cs.length();
2157 final int searchLength = searchChars.length;
2158 final int csLast = csLength - 1;
2159 final int searchLast = searchLength - 1;
2160 for (int i = 0; i < csLength; i++) {
2161 final char ch = cs.charAt(i);
2162 for (int j = 0; j <searchLength; j++) {
2163 if (searchChars[j] ==ch) {
2164 if(Character.isHighSurrogate(ch)) {
2165 if (j == searchLast) {
2166 // missing lowsurrogate, fine, like String.indexOf(String)
2167 return true;
2168 }
2169 if (i < csLast&& searchChars[j + 1] == cs.charAt(i + 1)) {
2170 return true;
2171 }
2172 } else {
2173 // ch is in the BasicMultilingual Plane
2174 return true;
2175 }
2176 }
2177 }
2178 }
2179 return false;
2180 }
2181
2182 /**
2183 * <p>
2184 * Checks if the CharSequence contains any character in the given set ofcharacters.
2185 * </p>
2186 *
2187 * <p>
2188 * A {@code null} CharSequence will return {@code false}. A {@code null}search CharSequence will return
2189 * {@code false}.
2190 * </p>
2191 *
2192 * <pre>
2193 * StringUtils.containsAny(null, *) = false
2194 * StringUtils.containsAny("", *) = false
2195 * StringUtils.containsAny(*, null) = false
2196 * StringUtils.containsAny(*, "") = false
2197 * StringUtils.containsAny("zzabyycdxx", "za") = true
2198 * StringUtils.containsAny("zzabyycdxx", "by") = true
2199 * StringUtils.containsAny("zzabyycdxx", "zy") = true
2200 * StringUtils.containsAny("zzabyycdxx", "\tx") = true
2201 * StringUtils.containsAny("zzabyycdxx", "$.#yF") =true
2202 * StringUtils.containsAny("aba","z") = false
2203 * </pre>
2204 *
2205 * @param cs
2206 * the CharSequence tocheck, may be null
2207 * @param searchChars
2208 * the chars to searchfor, may be null
2209 * @return the {@code true} if any of the chars are found, {@code false}if no match or null input
2210 * @since 2.4
2211 * @since 3.0 Changed signature from containsAny(String, String) tocontainsAny(CharSequence, CharSequence)
2212 */
2213 public static boolean containsAny(final CharSequence cs, finalCharSequence searchChars) {
2214 if (searchChars == null) {
2215 return false;
2216 }
2217 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
2218 }
2219
2220 /**
2221 * <p>Checks if the CharSequence contains any of the CharSequencesin the given array.</p>
2222 *
2223 * <p>
2224 * A {@code null} {@code cs} CharSequence will return {@code false}. A{@code null} or zero
2225 * length search array will return {@code false}.
2226 * </p>
2227 *
2228 * <pre>
2229 * StringUtils.containsAny(null, *) = false
2230 * StringUtils.containsAny("", *) = false
2231 * StringUtils.containsAny(*, null) = false
2232 * StringUtils.containsAny(*, []) = false
2233 * StringUtils.containsAny("abcd", "ab", null) = true
2234 * StringUtils.containsAny("abcd", "ab","cd") = true
2235 * StringUtils.containsAny("abc", "d","abc") = true
2236 * </pre>
2237 *
2238 *
2239 * @param cs The CharSequence to check, may be null
2240 * @param searchCharSequences The array of CharSequences to search for,may be null.
2241 * Individual CharSequences may be null as well.
2242 * @return {@code true} if any of the search CharSequences are found,{@code false} otherwise
2243 * @since 3.4
2244 */
2245 public static boolean containsAny(final CharSequence cs, finalCharSequence... searchCharSequences) {
2246 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
2247 return false;
2248 }
2249 for (final CharSequence searchCharSequence : searchCharSequences) {
2250 if (contains(cs,searchCharSequence)) {
2251 return true;
2252 }
2253 }
2254 return false;
2255 }
2256
2257 // IndexOfAnyBut chars
2258 //-----------------------------------------------------------------------
2259 /**
2260 * <p>Searches a CharSequence to find the first index of any
2261 * character not in the given set of characters.</p>
2262 *
2263 * <p>A {@code null} CharSequence will return {@code -1}.
2264 * A {@code null} or zero length search array will return {@code-1}.</p>
2265 *
2266 * <pre>
2267 * StringUtils.indexOfAnyBut(null, *) = -1
2268 * StringUtils.indexOfAnyBut("", *) = -1
2269 * StringUtils.indexOfAnyBut(*, null) = -1
2270 * StringUtils.indexOfAnyBut(*, []) = -1
2271 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z','a'} ) = 3
2272 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
2273 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'}) = -1
2274
2275 * </pre>
2276 *
2277 * @param cs the CharSequence tocheck, may be null
2278 * @param searchChars the chars tosearch for, may be null
2279 * @return the index of any of the chars, -1 if no match or null input
2280 * @since 2.0
2281 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) toindexOfAnyBut(CharSequence, char...)
2282 */
2283 public static int indexOfAnyBut(final CharSequence cs, final char...searchChars) {
2284 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2285 return INDEX_NOT_FOUND;
2286 }
2287 final int csLen = cs.length();
2288 final int csLast = csLen - 1;
2289 final int searchLen = searchChars.length;
2290 final int searchLast = searchLen - 1;
2291 outer:
2292 for (int i = 0; i < csLen; i++) {
2293 final char ch = cs.charAt(i);
2294 for (int j = 0; j < searchLen;j++) {
2295 if (searchChars[j] == ch) {
2296 if (i < csLast&& j < searchLast && Character.isHighSurrogate(ch)) {
2297 if (searchChars[j + 1]== cs.charAt(i + 1)) {
2298 continue outer;
2299 }
2300 } else {
2301 continue outer;
2302 }
2303 }
2304 }
2305 return i;
2306 }
2307 return INDEX_NOT_FOUND;
2308 }
2309
2310 /**
2311 * <p>Search a CharSequence to find the first index of any
2312 * character not in the given set of characters.</p>
2313 *
2314 * <p>A {@code null} CharSequence will return {@code -1}.
2315 * A {@code null} or empty search string will return {@code-1}.</p>
2316 *
2317 * <pre>
2318 * StringUtils.indexOfAnyBut(null, *) = -1
2319 * StringUtils.indexOfAnyBut("", *) = -1
2320 * StringUtils.indexOfAnyBut(*, null) = -1
2321 * StringUtils.indexOfAnyBut(*, "") = -1
2322 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2323 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
2324 * StringUtils.indexOfAnyBut("aba","ab") = -1
2325 * </pre>
2326 *
2327 * @param seq the CharSequence tocheck, may be null
2328 * @param searchChars the chars tosearch for, may be null
2329 * @return the index of any of the chars, -1 if no match or null input
2330 * @since 2.0
2331 * @since 3.0 Changed signature from indexOfAnyBut(String, String) toindexOfAnyBut(CharSequence, CharSequence)
2332 */
2333 public static int indexOfAnyBut(final CharSequence seq, finalCharSequence searchChars) {
2334 if (isEmpty(seq) || isEmpty(searchChars)) {
2335 return INDEX_NOT_FOUND;
2336 }
2337 final int strLen = seq.length();
2338 for (int i = 0; i < strLen; i++) {
2339 final char ch = seq.charAt(i);
2340 final boolean chFound =CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2341 if (i + 1 < strLen &&Character.isHighSurrogate(ch)) {
2342 final char ch2 = seq.charAt(i +1);
2343 if (chFound &&CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2344 return i;
2345 }
2346 } else {
2347 if (!chFound) {
2348 return i;
2349 }
2350 }
2351 }
2352 return INDEX_NOT_FOUND;
2353 }
2354
2355 // ContainsOnly
2356 //-----------------------------------------------------------------------
2357 /**
2358 * <p>Checks if the CharSequence contains only certaincharacters.</p>
2359 *
2360 * <p>A {@code null} CharSequence will return {@code false}.
2361 * A {@code null} valid character array will return {@code false}.
2362 * An empty CharSequence (length()=0) always returns {@codetrue}.</p>
2363 *
2364 * <pre>
2365 * StringUtils.containsOnly(null, *) = false
2366 * StringUtils.containsOnly(*, null) = false
2367 * StringUtils.containsOnly("", *) = true
2368 * StringUtils.containsOnly("ab", '') = false
2369 * StringUtils.containsOnly("abab", 'abc') = true
2370 * StringUtils.containsOnly("ab1", 'abc') = false
2371 * StringUtils.containsOnly("abz", 'abc') = false
2372 * </pre>
2373 *
2374 * @param cs the String to check,may be null
2375 * @param valid an array of validchars, may be null
2376 * @return true if it only contains valid chars and is non-null
2377 * @since 3.0 Changed signature from containsOnly(String, char[]) tocontainsOnly(CharSequence, char...)
2378 */
2379 public static boolean containsOnly(final CharSequence cs, final char...valid) {
2380 // All these pre-checks are to maintain API with an older version
2381 if (valid == null || cs == null) {
2382 return false;
2383 }
2384 if (cs.length() == 0) {
2385 return true;
2386 }
2387 if (valid.length == 0) {
2388 return false;
2389 }
2390 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
2391 }
2392
2393 /**
2394 * <p>Checks if the CharSequence contains only certaincharacters.</p>
2395 *
2396 * <p>A {@code null} CharSequence will return {@code false}.
2397 * A {@code null} valid character String will return {@code false}.
2398 * An empty String (length()=0) always returns {@code true}.</p>
2399 *
2400 * <pre>
2401 * StringUtils.containsOnly(null, *) = false
2402 * StringUtils.containsOnly(*, null) = false
2403 * StringUtils.containsOnly("", *) = true
2404 * StringUtils.containsOnly("ab", "") = false
2405 * StringUtils.containsOnly("abab", "abc") = true
2406 * StringUtils.containsOnly("ab1", "abc") = false
2407 * StringUtils.containsOnly("abz", "abc") = false
2408 * </pre>
2409 *
2410 * @param cs the CharSequence tocheck, may be null
2411 * @param validChars a String ofvalid chars, may be null
2412 * @return true if it only contains valid chars and is non-null
2413 * @since 2.0
2414 * @since 3.0 Changed signature from containsOnly(String, String) tocontainsOnly(CharSequence, String)
2415 */
2416 public static boolean containsOnly(final CharSequence cs, final StringvalidChars) {
2417 if (cs == null || validChars == null) {
2418 return false;
2419 }
2420 return containsOnly(cs, validChars.toCharArray());
2421 }
2422
2423 // ContainsNone
2424 //-----------------------------------------------------------------------
2425 /**
2426 * <p>Checks that the CharSequence does not contain certaincharacters.</p>
2427 *
2428 * <p>A {@code null} CharSequence will return {@code true}.
2429 * A {@code null} invalid character array will return {@code true}.
2430 * An empty CharSequence (length()=0) always returns true.</p>
2431 *
2432 * <pre>
2433 * StringUtils.containsNone(null, *) = true
2434 * StringUtils.containsNone(*, null) = true
2435 * StringUtils.containsNone("", *) = true
2436 * StringUtils.containsNone("ab", '') = true
2437 * StringUtils.containsNone("abab", 'xyz') = true
2438 * StringUtils.containsNone("ab1", 'xyz') = true
2439 * StringUtils.containsNone("abz", 'xyz') = false
2440 * </pre>
2441 *
2442 * @param cs the CharSequence tocheck, may be null
2443 * @param searchChars an array ofinvalid chars, may be null
2444 * @return true if it contains none of the invalid chars, or is null
2445 * @since 2.0
2446 * @since 3.0 Changed signature from containsNone(String, char[]) tocontainsNone(CharSequence, char...)
2447 */
2448 public static boolean containsNone(final CharSequence cs, final char...searchChars) {
2449 if (cs == null || searchChars == null) {
2450 return true;
2451 }
2452 final int csLen = cs.length();
2453 final int csLast = csLen - 1;
2454 final int searchLen = searchChars.length;
2455 final int searchLast = searchLen - 1;
2456 for (int i = 0; i < csLen; i++) {
2457 final char ch = cs.charAt(i);
2458 for (int j = 0; j < searchLen;j++) {
2459 if (searchChars[j] == ch) {
2460 if(Character.isHighSurrogate(ch)) {
2461 if (j == searchLast) {
2462 // missing lowsurrogate, fine, like String.indexOf(String)
2463 return false;
2464 }
2465 if (i < csLast&& searchChars[j + 1] == cs.charAt(i + 1)) {
2466 return false;
2467 }
2468 } else {
2469 // ch is in the BasicMultilingual Plane
2470 return false;
2471 }
2472 }
2473 }
2474 }
2475 return true;
2476 }
2477
2478 /**
2479 * <p>Checks that the CharSequence does not contain certaincharacters.</p>
2480 *
2481 * <p>A {@code null} CharSequence will return {@code true}.
2482 * A {@code null} invalid character array will return {@code true}.
2483 * An empty String ("") always returns true.</p>
2484 *
2485 * <pre>
2486 * StringUtils.containsNone(null, *) = true
2487 * StringUtils.containsNone(*, null) = true
2488 * StringUtils.containsNone("", *) = true
2489 * StringUtils.containsNone("ab", "") = true
2490 * StringUtils.containsNone("abab", "xyz") = true
2491 * StringUtils.containsNone("ab1", "xyz") = true
2492 * StringUtils.containsNone("abz", "xyz") = false
2493 * </pre>
2494 *
2495 * @param cs the CharSequence tocheck, may be null
2496 * @param invalidChars a String ofinvalid chars, may be null
2497 * @return true if it contains none of the invalid chars, or is null
2498 * @since 2.0
2499 * @since 3.0 Changed signature from containsNone(String, String) tocontainsNone(CharSequence, String)
2500 */
2501 public static boolean containsNone(final CharSequence cs, final StringinvalidChars) {
2502 if (cs == null || invalidChars == null) {
2503 return true;
2504 }
2505 return containsNone(cs, invalidChars.toCharArray());
2506 }
2507
2508 // IndexOfAny strings
2509 //-----------------------------------------------------------------------
2510 /**
2511 * <p>Find the first index of any of a set of potentialsubstrings.</p>
2512 *
2513 * <p>A {@code null} CharSequence will return {@code -1}.
2514 * A {@code null} or zero length search array will return {@code -1}.
2515 * A {@code null} search array entry will be ignored, but a search
2516 * array containing "" will return {@code 0} if {@code str} isnot
2517 * null. This method uses {@link String#indexOf(String)} ifpossible.</p>
2518 *
2519 * <pre>
2520 * StringUtils.indexOfAny(null, *) = -1
2521 * StringUtils.indexOfAny(*, null) = -1
2522 * StringUtils.indexOfAny(*, []) = -1
2523 * StringUtils.indexOfAny("zzabyycdxx",["ab","cd"]) = 2
2524 * StringUtils.indexOfAny("zzabyycdxx",["cd","ab"]) = 2
2525 * StringUtils.indexOfAny("zzabyycdxx",["mn","op"]) = -1
2526 * StringUtils.indexOfAny("zzabyycdxx",["zab","aby"]) = 1
2527 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
2528 * StringUtils.indexOfAny("", [""]) = 0
2529 * StringUtils.indexOfAny("", ["a"]) = -1
2530 * </pre>
2531 *
2532 * @param str the CharSequence tocheck, may be null
2533 * @param searchStrs theCharSequences to search for, may be null
2534 * @return the first index of any of the searchStrs in str, -1 if nomatch
2535 * @since 3.0 Changed signature from indexOfAny(String, String[]) toindexOfAny(CharSequence, CharSequence...)
2536 */
2537 public static int indexOfAny(final CharSequence str, finalCharSequence... searchStrs) {
2538 if (str == null || searchStrs == null) {
2539 return INDEX_NOT_FOUND;
2540 }
2541
2542 // String's can't have a MAX_VALUEth index.
2543 int ret = Integer.MAX_VALUE;
2544
2545 int tmp = 0;
2546 for (final CharSequence search : searchStrs) {
2547 if (search == null) {
2548 continue;
2549 }
2550 tmp =CharSequenceUtils.indexOf(str, search, 0);
2551 if (tmp == INDEX_NOT_FOUND) {
2552 continue;
2553 }
2554
2555 if (tmp < ret) {
2556 ret = tmp;
2557 }
2558 }
2559
2560 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2561 }
2562
2563 /**
2564 * <p>Find the latest index of any of a set of potentialsubstrings.</p>
2565 *
2566 * <p>A {@code null} CharSequence will return {@code -1}.
2567 * A {@code null} search array will return {@code -1}.
2568 * A {@code null} or zero length search array entry will be ignored,
2569 * but a search array containing "" will return the length of{@code str}
2570 * if {@code str} is not null. This method uses {@linkString#indexOf(String)} if possible</p>
2571 *
2572 * <pre>
2573 * StringUtils.lastIndexOfAny(null, *) = -1
2574 * StringUtils.lastIndexOfAny(*, null) = -1
2575 * StringUtils.lastIndexOfAny(*, []) = -1
2576 * StringUtils.lastIndexOfAny(*, [null]) = -1
2577 * StringUtils.lastIndexOfAny("zzabyycdxx",["ab","cd"]) = 6
2578 * StringUtils.lastIndexOfAny("zzabyycdxx",["cd","ab"]) = 6
2579 * StringUtils.lastIndexOfAny("zzabyycdxx",["mn","op"]) = -1
2580 * StringUtils.lastIndexOfAny("zzabyycdxx",["mn","op"]) = -1
2581 * StringUtils.lastIndexOfAny("zzabyycdxx",["mn",""]) = 10
2582 * </pre>
2583 *
2584 * @param str the CharSequence tocheck, may be null
2585 * @param searchStrs theCharSequences to search for, may be null
2586 * @return the last index of any of the CharSequences, -1 if no match
2587 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) tolastIndexOfAny(CharSequence, CharSequence)
2588 */
2589 public static int lastIndexOfAny(final CharSequence str, finalCharSequence... searchStrs) {
2590 if (str == null || searchStrs == null) {
2591 return INDEX_NOT_FOUND;
2592 }
2593 int ret = INDEX_NOT_FOUND;
2594 int tmp = 0;
2595 for (final CharSequence search : searchStrs) {
2596 if (search == null) {
2597 continue;
2598 }
2599 tmp =CharSequenceUtils.lastIndexOf(str, search, str.length());
2600 if (tmp > ret) {
2601 ret = tmp;
2602 }
2603 }
2604 return ret;
2605 }
2606
2607 // Substring
2608 //-----------------------------------------------------------------------
2609 /**
2610 * <p>Gets a substring from the specified String avoidingexceptions.</p>
2611 *
2612 * <p>A negative start position can be used to start {@code n}
2613 * characters from the end of the String.</p>
2614 *
2615 * <p>A {@code null} String will return {@code null}.
2616 * An empty ("") String will return "".</p>
2617 *
2618 * <pre>
2619 * StringUtils.substring(null, *) = null
2620 * StringUtils.substring("", *) = ""
2621 * StringUtils.substring("abc", 0) = "abc"
2622 * StringUtils.substring("abc", 2) = "c"
2623 * StringUtils.substring("abc", 4) = ""
2624 * StringUtils.substring("abc", -2) = "bc"
2625 * StringUtils.substring("abc", -4) = "abc"
2626 * </pre>
2627 *
2628 * @param str the String to getthe substring from, may be null
2629 * @param start the position tostart from, negative means
2630 * count back from the end of theString by this many characters
2631 * @return substring from start position, {@code null} if null Stringinput
2632 */
2633 public static String substring(final String str, int start) {
2634 if (str == null) {
2635 return null;
2636 }
2637
2638 // handle negatives, which means last n characters
2639 if (start < 0) {
2640 start = str.length() + start; //remember start is negative
2641 }
2642
2643 if (start < 0) {
2644 start = 0;
2645 }
2646 if (start > str.length()) {
2647 return EMPTY;
2648 }
2649
2650 return str.substring(start);
2651 }
2652
2653 /**
2654 * <p>Gets a substring from the specified String avoidingexceptions.</p>
2655 *
2656 * <p>A negative start position can be used to start/end {@code n}
2657 * characters from the end of the String.</p>
2658 *
2659 * <p>The returned substring starts with the character in the{@code start}
2660 * position and ends before the {@code end} position. All positioncounting is
2661 * zero-based -- i.e., to start at the beginning of the string use
2662 * {@code start = 0}. Negative start and end positions can be used to
2663 * specify offsets relative to the end of the String.</p>
2664 *
2665 * <p>If {@code start} is not strictly to the left of {@code end},""
2666 * is returned.</p>
2667 *
2668 * <pre>
2669 * StringUtils.substring(null, *, *) = null
2670 * StringUtils.substring("", * , *) ="";
2671 * StringUtils.substring("abc", 0, 2) = "ab"
2672 * StringUtils.substring("abc", 2, 0) = ""
2673 * StringUtils.substring("abc", 2, 4) = "c"
2674 * StringUtils.substring("abc", 4, 6) = ""
2675 * StringUtils.substring("abc", 2, 2) = ""
2676 * StringUtils.substring("abc", -2, -1) = "b"
2677 * StringUtils.substring("abc", -4, 2) = "ab"
2678 * </pre>
2679 *
2680 * @param str the String to getthe substring from, may be null
2681 * @param start the position tostart from, negative means
2682 * count back from the end of theString by this many characters
2683 * @param end the position to endat (exclusive), negative means
2684 * count back from the end of theString by this many characters
2685 * @return substring from start position to end position,
2686 * {@code null} if null Stringinput
2687 */
2688 public static String substring(final String str, int start, int end) {
2689 if (str == null) {
2690 return null;
2691 }
2692
2693 // handle negatives
2694 if (end < 0) {
2695 end = str.length() + end; //remember end is negative
2696 }
2697 if (start < 0) {
2698 start = str.length() + start; //remember start is negative
2699 }
2700
2701 // check length next
2702 if (end > str.length()) {
2703 end = str.length();
2704 }
2705
2706 // if start is greater than end, return ""
2707 if (start > end) {
2708 return EMPTY;
2709 }
2710
2711 if (start < 0) {
2712 start = 0;
2713 }
2714 if (end < 0) {
2715 end = 0;
2716 }
2717
2718 return str.substring(start, end);
2719 }
2720
2721 // Left/Right/Mid
2722 //-----------------------------------------------------------------------
2723 /**
2724 * <p>Gets the leftmost {@code len} characters of aString.</p>
2725 *
2726 * <p>If {@code len} characters are not available, or the
2727 * String is {@code null}, the String will be returned without
2728 * an exception. An empty String is returned if len isnegative.</p>
2729 *
2730 * <pre>
2731 * StringUtils.left(null, *) =null
2732 * StringUtils.left(*, -ve) =""
2733 * StringUtils.left("", *) = ""
2734 * StringUtils.left("abc", 0) = ""
2735 * StringUtils.left("abc", 2) = "ab"
2736 * StringUtils.left("abc", 4) = "abc"
2737 * </pre>
2738 *
2739 * @param str the String to getthe leftmost characters from, may be null
2740 * @param len the length of therequired String
2741 * @return the leftmost characters, {@code null} if null String input
2742 */
2743 public static String left(final String str, final int len) {
2744 if (str == null) {
2745 return null;
2746 }
2747 if (len < 0) {
2748 return EMPTY;
2749 }
2750 if (str.length() <= len) {
2751 return str;
2752 }
2753 return str.substring(0, len);
2754 }
2755
2756 /**
2757 * <p>Gets the rightmost {@code len} characters of aString.</p>
2758 *
2759 * <p>If {@code len} characters are not available, or the String
2760 * is {@code null}, the String will be returned without an
2761 * an exception. An empty String is returned if len isnegative.</p>
2762 *
2763 * <pre>
2764 * StringUtils.right(null, *) =null
2765 * StringUtils.right(*, -ve) =""
2766 * StringUtils.right("", *) = ""
2767 * StringUtils.right("abc", 0) = ""
2768 * StringUtils.right("abc", 2) = "bc"
2769 * StringUtils.right("abc", 4) = "abc"
2770 * </pre>
2771 *
2772 * @param str the String to getthe rightmost characters from, may be null
2773 * @param len the length of therequired String
2774 * @return the rightmost characters, {@code null} if null String input
2775 */
2776 public static String right(final String str, final int len) {
2777 if (str == null) {
2778 return null;
2779 }
2780 if (len < 0) {
2781 return EMPTY;
2782 }
2783 if (str.length() <= len) {
2784 return str;
2785 }
2786 return str.substring(str.length() - len);
2787 }
2788
2789 /**
2790 * <p>Gets {@code len} characters from the middle of aString.</p>
2791 *
2792 * <p>If {@code len} characters are not available, the remainder
2793 * of the String will be returned without an exception. If the
2794 * String is {@code null}, {@code null} will be returned.
2795 * An empty String is returned if len is negative or exceeds the
2796 * length of {@code str}.</p>
2797 *
2798 * <pre>
2799 * StringUtils.mid(null, *, *) =null
2800 * StringUtils.mid(*, *, -ve) =""
2801 * StringUtils.mid("", 0, *) = ""
2802 * StringUtils.mid("abc", 0, 2) = "ab"
2803 * StringUtils.mid("abc", 0, 4) = "abc"
2804 * StringUtils.mid("abc", 2, 4) = "c"
2805 * StringUtils.mid("abc", 4, 2) = ""
2806 * StringUtils.mid("abc", -2, 2) = "ab"
2807 * </pre>
2808 *
2809 * @param str the String to getthe characters from, may be null
2810 * @param pos the position tostart from, negative treated as zero
2811 * @param len the length of therequired String
2812 * @return the middle characters, {@code null} if null String input
2813 */
2814 public static String mid(final String str, int pos, final int len) {
2815 if (str == null) {
2816 return null;
2817 }
2818 if (len < 0 || pos > str.length()) {
2819 return EMPTY;
2820 }
2821 if (pos < 0) {
2822 pos = 0;
2823 }
2824 if (str.length() <= pos + len) {
2825 return str.substring(pos);
2826 }
2827 return str.substring(pos, pos + len);
2828 }
2829
2830 // SubStringAfter/SubStringBefore
2831 //-----------------------------------------------------------------------
2832 /**
2833 * <p>Gets the substring before the first occurrence of aseparator.
2834 * The separator is not returned.</p>
2835 *
2836 * <p>A {@code null} string input will return {@code null}.
2837 * An empty ("") string input will return the empty string.
2838 * A {@code null} separator will return the input string.</p>
2839 *
2840 * <p>If nothing is found, the string input is returned.</p>
2841 *
2842 * <pre>
2843 * StringUtils.substringBefore(null, *) = null
2844 * StringUtils.substringBefore("", *) = ""
2845 * StringUtils.substringBefore("abc", "a") = ""
2846 * StringUtils.substringBefore("abcba", "b") ="a"
2847 * StringUtils.substringBefore("abc", "c") = "ab"
2848 * StringUtils.substringBefore("abc", "d") = "abc"
2849 * StringUtils.substringBefore("abc", "") = ""
2850 * StringUtils.substringBefore("abc", null) = "abc"
2851 * </pre>
2852 *
2853 * @param str the String to get asubstring from, may be null
2854 * @param separator the String tosearch for, may be null
2855 * @return the substring before the first occurrence of the separator,
2856 * {@code null} if null Stringinput
2857 * @since 2.0
2858 */
2859 public static String substringBefore(final String str, final Stringseparator) {
2860 if (isEmpty(str) || separator == null) {
2861 return str;
2862 }
2863 if (separator.isEmpty()) {
2864 return EMPTY;
2865 }
2866 final int pos = str.indexOf(separator);
2867 if (pos == INDEX_NOT_FOUND) {
2868 return str;
2869 }
2870 return str.substring(0, pos);
2871 }
2872
2873 /**
2874 * <p>Gets the substring after the first occurrence of a separator.
2875 * The separator is not returned.</p>
2876 *
2877 * <p>A {@code null} string input will return {@code null}.
2878 * An empty ("") string input will return the empty string.
2879 * A {@code null} separator will return the empty string if the
2880 * input string is not {@code null}.</p>
2881 *
2882 * <p>If nothing is found, the empty string is returned.</p>
2883 *
2884 * <pre>
2885 * StringUtils.substringAfter(null, *) = null
2886 * StringUtils.substringAfter("", *) = ""
2887 * StringUtils.substringAfter(*, null) = ""
2888 * StringUtils.substringAfter("abc", "a") = "bc"
2889 * StringUtils.substringAfter("abcba", "b") ="cba"
2890 * StringUtils.substringAfter("abc", "c") = ""
2891 * StringUtils.substringAfter("abc", "d") = ""
2892 * StringUtils.substringAfter("abc", "") = "abc"
2893 * </pre>
2894 *
2895 * @param str the String to get asubstring from, may be null
2896 * @param separator the String tosearch for, may be null
2897 * @return the substring after the first occurrence of the separator,
2898 * {@code null} if null Stringinput
2899 * @since 2.0
2900 */
2901 public static String substringAfter(final String str, final Stringseparator) {
2902 if (isEmpty(str)) {
2903 return str;
2904 }
2905 if (separator == null) {
2906 return EMPTY;
2907 }
2908 final int pos = str.indexOf(separator);
2909 if (pos == INDEX_NOT_FOUND) {
2910 return EMPTY;
2911 }
2912 return str.substring(pos + separator.length());
2913 }
2914
2915 /**
2916 * <p>Gets the substring before the last occurrence of a separator.
2917 * The separator is not returned.</p>
2918 *
2919 * <p>A {@code null} string input will return {@code null}.
2920 * An empty ("") string input will return the empty string.
2921 * An empty or {@code null} separator will return the inputstring.</p>
2922 *
2923 * <p>If nothing is found, the string input is returned.</p>
2924 *
2925 * <pre>
2926 * StringUtils.substringBeforeLast(null, *) = null
2927 * StringUtils.substringBeforeLast("", *) = ""
2928 * StringUtils.substringBeforeLast("abcba", "b") ="abc"
2929 * StringUtils.substringBeforeLast("abc", "c") = "ab"
2930 * StringUtils.substringBeforeLast("a", "a") = ""
2931 * StringUtils.substringBeforeLast("a", "z") = "a"
2932 * StringUtils.substringBeforeLast("a", null) = "a"
2933 * StringUtils.substringBeforeLast("a", "") = "a"
2934 * </pre>
2935 *
2936 * @param str the String to get asubstring from, may be null
2937 * @param separator the String tosearch for, may be null
2938 * @return the substring before the last occurrence of the separator,
2939 * {@code null} if null Stringinput
2940 * @since 2.0
2941 */
2942 public static String substringBeforeLast(final String str, final Stringseparator) {
2943 if (isEmpty(str) || isEmpty(separator)) {
2944 return str;
2945 }
2946 final int pos = str.lastIndexOf(separator);
2947 if (pos == INDEX_NOT_FOUND) {
2948 return str;
2949 }
2950 return str.substring(0, pos);
2951 }
2952
2953 /**
2954 * <p>Gets the substring after the last occurrence of a separator.
2955 * The separator is not returned.</p>
2956 *
2957 * <p>A {@code null} string input will return {@code null}.
2958 * An empty ("") string input will return the empty string.
2959 * An empty or {@code null} separator will return the empty string if
2960 * the input string is not {@code null}.</p>
2961 *
2962 * <p>If nothing is found, the empty string is returned.</p>
2963 *
2964 * <pre>
2965 * StringUtils.substringAfterLast(null, *) = null
2966 * StringUtils.substringAfterLast("", *) = ""
2967 * StringUtils.substringAfterLast(*, "") = ""
2968 * StringUtils.substringAfterLast(*, null) = ""
2969 * StringUtils.substringAfterLast("abc", "a") = "bc"
2970 * StringUtils.substringAfterLast("abcba", "b") ="a"
2971 * StringUtils.substringAfterLast("abc", "c") = ""
2972 * StringUtils.substringAfterLast("a", "a") = ""
2973 * StringUtils.substringAfterLast("a", "z") = ""
2974 * </pre>
2975 *
2976 * @param str the String to get asubstring from, may be null
2977 * @param separator the String tosearch for, may be null
2978 * @return the substring after the last occurrence of the separator,
2979 * {@code null} if null Stringinput
2980 * @since 2.0
2981 */
2982 public static String substringAfterLast(final String str, final Stringseparator) {
2983 if (isEmpty(str)) {
2984 return str;
2985 }
2986 if (isEmpty(separator)) {
2987 return EMPTY;
2988 }
2989 final int pos = str.lastIndexOf(separator);
2990 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()){
2991 return EMPTY;
2992 }
2993 return str.substring(pos + separator.length());
2994 }
2995
2996 // Substring between
2997 //-----------------------------------------------------------------------
2998 /**
2999 * <p>Gets the String that is nested in between two instances ofthe
3000 * same String.</p>
3001 *
3002 * <p>A {@code null} input String returns {@code null}.
3003 * A {@code null} tag returns {@code null}.</p>
3004 *
3005 * <pre>
3006 * StringUtils.substringBetween(null, *) = null
3007 * StringUtils.substringBetween("", "") = ""
3008 * StringUtils.substringBetween("", "tag") = null
3009 * StringUtils.substringBetween("tagabctag", null) = null
3010 * StringUtils.substringBetween("tagabctag", "") = ""
3011 * StringUtils.substringBetween("tagabctag", "tag") ="abc"
3012 * </pre>
3013 *
3014 * @param str the Stringcontaining the substring, may be null
3015 * @param tag the String beforeand after the substring, may be null
3016 * @return the substring, {@code null} if no match
3017 * @since 2.0
3018 */
3019 public static String substringBetween(final String str, final Stringtag) {
3020 return substringBetween(str, tag, tag);
3021 }
3022
3023 /**
3024 * <p>Gets the String that is nested in between two Strings.
3025 * Only the first match is returned.</p>
3026 *
3027 * <p>A {@code null} input String returns {@code null}.
3028 * A {@code null} open/close returns {@code null} (no match).
3029 * An empty ("") open and close returns an emptystring.</p>
3030 *
3031 * <pre>
3032 * StringUtils.substringBetween("wx[b]yz", "[","]") = "b"
3033 * StringUtils.substringBetween(null, *, *) = null
3034 * StringUtils.substringBetween(*, null, *) = null
3035 * StringUtils.substringBetween(*, *, null) = null
3036 * StringUtils.substringBetween("", "","") = ""
3037 * StringUtils.substringBetween("", "","]") = null
3038 * StringUtils.substringBetween("", "[","]") = null
3039 * StringUtils.substringBetween("yabcz", "","") = ""
3040 * StringUtils.substringBetween("yabcz", "y","z") = "abc"
3041 * StringUtils.substringBetween("yabczyabcz", "y","z") = "abc"
3042 * </pre>
3043 *
3044 * @param str the Stringcontaining the substring, may be null
3045 * @param open the String beforethe substring, may be null
3046 * @param close the String afterthe substring, may be null
3047 * @return the substring, {@code null} if no match
3048 * @since 2.0
3049 */
3050 public static String substringBetween(final String str, final Stringopen, final String close) {
3051 if (str == null || open == null || close == null) {
3052 return null;
3053 }
3054 final int start = str.indexOf(open);
3055 if (start != INDEX_NOT_FOUND) {
3056 final int end = str.indexOf(close,start + open.length());
3057 if (end != INDEX_NOT_FOUND) {
3058 return str.substring(start +open.length(), end);
3059 }
3060 }
3061 return null;
3062 }
3063
3064 /**
3065 * <p>Searches a String for substrings delimited by a start and endtag,
3066 * returning all matching substrings in an array.</p>
3067 *
3068 * <p>A {@code null} input String returns {@code null}.
3069 * A {@code null} open/close returns {@code null} (no match).
3070 * An empty ("") open/close returns {@code null} (nomatch).</p>
3071 *
3072 * <pre>
3073 * StringUtils.substringsBetween("[a][b][c]", "[","]") = ["a","b","c"]
3074 * StringUtils.substringsBetween(null, *, *) = null
3075 * StringUtils.substringsBetween(*, null, *) = null
3076 * StringUtils.substringsBetween(*, *, null) = null
3077 * StringUtils.substringsBetween("", "[","]") = []
3078 * </pre>
3079 *
3080 * @param str the Stringcontaining the substrings, null returns null, empty returns empty
3081 * @param open the Stringidentifying the start of the substring, empty returns null
3082 * @param close the Stringidentifying the end of the substring, empty returns null
3083 * @return a String Array of substrings, or {@code null} if no match
3084 * @since 2.3
3085 */
3086 public static String[] substringsBetween(final String str, final Stringopen, final String close) {
3087 if (str == null || isEmpty(open) || isEmpty(close)) {
3088 return null;
3089 }
3090 final int strLen = str.length();
3091 if (strLen == 0) {
3092 returnArrayUtils.EMPTY_STRING_ARRAY;
3093 }
3094 final int closeLen = close.length();
3095 final int openLen = open.length();
3096 final List<String> list = new ArrayList<>();
3097 int pos = 0;
3098 while (pos < strLen - closeLen) {
3099 int start = str.indexOf(open, pos);
3100 if (start < 0) {
3101 break;
3102 }
3103 start += openLen;
3104 final int end = str.indexOf(close,start);
3105 if (end < 0) {
3106 break;
3107 }
3108 list.add(str.substring(start,end));
3109 pos = end + closeLen;
3110 }
3111 if (list.isEmpty()) {
3112 return null;
3113 }
3114 return list.toArray(new String [list.size()]);
3115 }
3116
3117 // Nested extraction
3118 //-----------------------------------------------------------------------
3119
3120 // Splitting
3121 //-----------------------------------------------------------------------
3122 /**
3123 * <p>Splits the provided text into an array, using whitespace asthe
3124 * separator.
3125 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
3126 *
3127 * <p>The separator is not included in the returned String array.
3128 * Adjacent separators are treated as one separator.
3129 * For more control over the split use the StrTokenizer class.</p>
3130 *
3131 * <p>A {@code null} input String returns {@code null}.</p>
3132 *
3133 * <pre>
3134 * StringUtils.split(null) =null
3135 * StringUtils.split("") = []
3136 * StringUtils.split("abc def") = ["abc", "def"]
3137 * StringUtils.split("abc def") = ["abc", "def"]
3138 * StringUtils.split(" abc ") = ["abc"]
3139 * </pre>
3140 *
3141 * @param str the String to parse,may be null
3142 * @return an array of parsed Strings, {@code null} if null String input
3143 */
3144 public static String[] split(final String str) {
3145 return split(str, null, -1);
3146 }
3147
3148 /**
3149 * <p>Splits the provided text into an array, separator specified.
3150 * This is an alternative to using StringTokenizer.</p>
3151 *
3152 * <p>The separator is not included in the returned String array.
3153 * Adjacent separators are treated as one separator.
3154 * For more control over the split use the StrTokenizer class.</p>
3155 *
3156 * <p>A {@code null} input String returns {@code null}.</p>
3157 *
3158 * <pre>
3159 * StringUtils.split(null, *) = null
3160 * StringUtils.split("", *) = []
3161 * StringUtils.split("a.b.c", '.') = ["a", "b","c"]
3162 * StringUtils.split("a..b.c", '.') = ["a", "b","c"]
3163 * StringUtils.split("a:b:c", '.') = ["a:b:c"]
3164 * StringUtils.split("a b c", ' ') = ["a", "b","c"]
3165 * </pre>
3166 *
3167 * @param str the String to parse,may be null
3168 * @param separatorChar thecharacter used as the delimiter
3169 * @return an array of parsed Strings, {@code null} if null String input
3170 * @since 2.0
3171 */
3172 public static String[] split(final String str, final char separatorChar){
3173 return splitWorker(str, separatorChar, false);
3174 }
3175
3176 /**
3177 * <p>Splits the provided text into an array, separators specified.
3178 * This is an alternative to using StringTokenizer.</p>
3179 *
3180 * <p>The separator is not included in the returned String array.
3181 * Adjacent separators are treated as one separator.
3182 * For more control over the split use the StrTokenizer class.</p>
3183 *
3184 * <p>A {@code null} input String returns {@code null}.
3185 * A {@code null} separatorChars splits on whitespace.</p>
3186 *
3187 * <pre>
3188 * StringUtils.split(null, *) = null
3189 * StringUtils.split("", *) = []
3190 * StringUtils.split("abc def", null) = ["abc","def"]
3191 * StringUtils.split("abc def", " ") = ["abc", "def"]
3192 * StringUtils.split("abc def", " ") = ["abc", "def"]
3193 * StringUtils.split("ab:cd:ef", ":") =["ab", "cd", "ef"]
3194 * </pre>
3195 *
3196 * @param str the String to parse,may be null
3197 * @param separatorChars thecharacters used as the delimiters,
3198 * {@code null} splits onwhitespace
3199 * @return an array of parsed Strings, {@code null} if null String input
3200 */
3201 public static String[] split(final String str, final StringseparatorChars) {
3202 return splitWorker(str, separatorChars, -1, false);
3203 }
3204
3205 /**
3206 * <p>Splits the provided text into an array with a maximum length,
3207 * separators specified.</p>
3208 *
3209 * <p>The separator is not included in the returned String array.
3210 * Adjacent separators are treated as one separator.</p>
3211 *
3212 * <p>A {@code null} input String returns {@code null}.
3213 * A {@code null} separatorChars splits on whitespace.</p>
3214 *
3215 * <p>If more than {@code max} delimited substrings are found, thelast
3216 * returned string includes all characters after the first {@code max -1}
3217 * returned strings (including separator characters).</p>
3218 *
3219 * <pre>
3220 * StringUtils.split(null, *, *) = null
3221 * StringUtils.split("", *, *) = []
3222 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd","ef"]
3223 * StringUtils.split("ab cdef", null, 0) = ["ab", "cd", "ef"]
3224 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd","ef"]
3225 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
3226 * </pre>
3227 *
3228 * @param str the String to parse,may be null
3229 * @param separatorChars thecharacters used as the delimiters,
3230 * {@code null} splits onwhitespace
3231 * @param max the maximum numberof elements to include in the
3232 * array. A zero or negative valueimplies no limit
3233 * @return an array of parsed Strings, {@code null} if null String input
3234 */
3235 public static String[] split(final String str, final StringseparatorChars, final int max) {
3236 return splitWorker(str, separatorChars, max, false);
3237 }
3238
3239 /**
3240 * <p>Splits the provided text into an array, separator stringspecified.</p>
3241 *
3242 * <p>The separator(s) will not be included in the returned Stringarray.
3243 * Adjacent separators are treated as one separator.</p>
3244 *
3245 * <p>A {@code null} input String returns {@code null}.
3246 * A {@code null} separator splits on whitespace.</p>
3247 *
3248 * <pre>
3249 * StringUtils.splitByWholeSeparator(null, *) = null
3250 * StringUtils.splitByWholeSeparator("", *) = []
3251 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de","fg"]
3252 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de","fg"]
3253 * StringUtils.splitByWholeSeparator("ab:cd:ef",":") = ["ab","cd", "ef"]
3254 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef","-!-") = ["ab", "cd", "ef"]
3255 * </pre>
3256 *
3257 * @param str the String to parse,may be null
3258 * @param separator Stringcontaining the String to be used as a delimiter,
3259 * {@code null} splits onwhitespace
3260 * @return an array of parsed Strings, {@code null} if null String wasinput
3261 */
3262 public static String[] splitByWholeSeparator(final String str, finalString separator) {
3263 return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
3264 }
3265
3266 /**
3267 * <p>Splits the provided text into an array, separator stringspecified.
3268 * Returns a maximum of {@code max} substrings.</p>
3269 *
3270 * <p>The separator(s) will not be included in the returned Stringarray.
3271 * Adjacent separators are treated as one separator.</p>
3272 *
3273 * <p>A {@code null} input String returns {@code null}.
3274 * A {@code null} separator splits on whitespace.</p>
3275 *
3276 * <pre>
3277 * StringUtils.splitByWholeSeparator(null, *, *) = null
3278 * StringUtils.splitByWholeSeparator("", *, *) = []
3279 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de","fg"]
3280 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de","fg"]
3281 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":",2) = ["ab","cd:ef"]
3282 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef","-!-", 5) = ["ab", "cd", "ef"]
3283 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef","-!-", 2) = ["ab", "cd-!-ef"]
3284 * </pre>
3285 *
3286 * @param str the String to parse,may be null
3287 * @param separator Stringcontaining the String to be used as a delimiter,
3288 * {@code null} splits onwhitespace
3289 * @param max the maximum numberof elements to include in the returned
3290 * array. A zero or negative valueimplies no limit.
3291 * @return an array of parsed Strings, {@code null} if null String wasinput
3292 */
3293 public static String[] splitByWholeSeparator( final String str, finalString separator, final int max) {
3294 return splitByWholeSeparatorWorker(str, separator, max, false);
3295 }
3296
3297 /**
3298 * <p>Splits the provided text into an array, separator stringspecified. </p>
3299 *
3300 * <p>The separator is not included in the returned String array.
3301 * Adjacent separators are treated as separators for empty tokens.
3302 * For more control over the split use the StrTokenizer class.</p>
3303 *
3304 * <p>A {@code null} input String returns {@code null}.
3305 * A {@code null} separator splits on whitespace.</p>
3306 *
3307 * <pre>
3308 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
3309 * StringUtils.splitByWholeSeparatorPreserveAllTokens("",*) = []
3310 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab defg", null) = ["ab","de", "fg"]
3311 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "","", "de", "fg"]
3312 *StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef",":") = ["ab","cd", "ef"]
3313 *StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef","-!-") = ["ab", "cd", "ef"]
3314 * </pre>
3315 *
3316 * @param str the String to parse,may be null
3317 * @param separator Stringcontaining the String to be used as a delimiter,
3318 * {@code null} splits onwhitespace
3319 * @return an array of parsed Strings, {@code null} if null String wasinput
3320 * @since 2.4
3321 */
3322 public static String[] splitByWholeSeparatorPreserveAllTokens(finalString str, final String separator) {
3323 return splitByWholeSeparatorWorker(str, separator, -1, true);
3324 }
3325
3326 /**
3327 * <p>Splits the provided text into an array, separator stringspecified.
3328 * Returns a maximum of {@code max} substrings.</p>
3329 *
3330 * <p>The separator is not included in the returned String array.
3331 * Adjacent separators are treated as separators for empty tokens.
3332 * For more control over the split use the StrTokenizer class.</p>
3333 *
3334 * <p>A {@code null} input String returns {@code null}.
3335 * A {@code null} separator splits on whitespace.</p>
3336 *
3337 * <pre>
3338 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
3339 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *,*) = []
3340 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab defg", null, 0) =["ab", "de", "fg"]
3341 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "","", "de", "fg"]
3342 *StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef",":", 2) =["ab", "cd:ef"]
3343 *StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef","-!-", 5) = ["ab", "cd", "ef"]
3344 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef","-!-", 2) = ["ab", "cd-!-ef"]
3345 * </pre>
3346 *
3347 * @param str the String to parse,may be null
3348 * @param separator Stringcontaining the String to be used as a delimiter,
3349 * {@code null} splits onwhitespace
3350 * @param max the maximum numberof elements to include in the returned
3351 * array. A zero or negative valueimplies no limit.
3352 * @return an array of parsed Strings, {@code null} if null String wasinput
3353 * @since 2.4
3354 */
3355 public static String[] splitByWholeSeparatorPreserveAllTokens(finalString str, final String separator, final int max) {
3356 return splitByWholeSeparatorWorker(str, separator, max, true);
3357 }
3358
3359 /**
3360 * Performs the logic for the {@codesplitByWholeSeparatorPreserveAllTokens} methods.
3361 *
3362 * @param str the String to parse,may be {@code null}
3363 * @param separator Stringcontaining the String to be used as a delimiter,
3364 * {@code null} splits onwhitespace
3365 * @param max the maximum numberof elements to include in the returned
3366 * array. A zero or negative valueimplies no limit.
3367 * @param preserveAllTokens if {@code true}, adjacent separators are
3368 * treated as empty token separators; if {@code false}, adjacent
3369 * separators are treated as one separator.
3370 * @return an array of parsed Strings, {@code null} if null String input
3371 * @since 2.4
3372 */
3373 private static String[] splitByWholeSeparatorWorker(
3374 final String str, final Stringseparator, final int max, final boolean preserveAllTokens) {
3375 if (str == null) {
3376 return null;
3377 }
3378
3379 final int len = str.length();
3380
3381 if (len == 0) {
3382 returnArrayUtils.EMPTY_STRING_ARRAY;
3383 }
3384
3385 if (separator == null || EMPTY.equals(separator)) {
3386 // Split on whitespace.
3387 return splitWorker(str, null, max,preserveAllTokens);
3388 }
3389
3390 final int separatorLength = separator.length();
3391
3392 final ArrayList<String> substrings = new ArrayList<>();
3393 int numberOfSubstrings = 0;
3394 int beg = 0;
3395 int end = 0;
3396 while (end < len) {
3397 end = str.indexOf(separator, beg);
3398
3399 if (end > -1) {
3400 if (end > beg) {
3401 numberOfSubstrings += 1;
3402
3403 if (numberOfSubstrings ==max) {
3404 end = len;
3405 substrings.add(str.substring(beg));
3406 } else {
3407 // The following is OK,because String.substring( beg, end ) excludes
3408 // the character at the position 'end'.
3409 substrings.add(str.substring(beg, end));
3410
3411 // Set the startingpoint for the next search.
3412 // The following isequivalent to beg = end + (separatorLength - 1) + 1,
3413 // which is the rightcalculation:
3414 beg = end +separatorLength;
3415 }
3416 } else {
3417 // We found a consecutiveoccurrence of the separator, so skip it.
3418 if (preserveAllTokens) {
3419 numberOfSubstrings +=1;
3420 if (numberOfSubstrings== max) {
3421 end = len;
3422 substrings.add(str.substring(beg));
3423 } else {
3424 substrings.add(EMPTY);
3425 }
3426 }
3427 beg = end +separatorLength;
3428 }
3429 } else {
3430 // String.substring( beg ) goesfrom 'beg' to the end of the String.
3431 substrings.add(str.substring(beg));
3432 end = len;
3433 }
3434 }
3435
3436 return substrings.toArray(new String[substrings.size()]);
3437 }
3438
3439 //-----------------------------------------------------------------------
3440 /**
3441 * <p>Splits the provided text into an array, using whitespace asthe
3442 * separator, preserving all tokens, including empty tokens created by
3443 * adjacent separators. This is an alternative to using StringTokenizer.
3444 * Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
3445 *
3446 * <p>The separator is not included in the returned String array.
3447 * Adjacent separators are treated as separators for empty tokens.
3448 * For more control over the split use the StrTokenizer class.</p>
3449 *
3450 * <p>A {@code null} input String returns {@code null}.</p>
3451 *
3452 * <pre>
3453 * StringUtils.splitPreserveAllTokens(null) = null
3454 * StringUtils.splitPreserveAllTokens("") = []
3455 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
3456 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "","def"]
3457 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc",""]
3458 * </pre>
3459 *
3460 * @param str the String to parse,may be {@code null}
3461 * @return an array of parsed Strings, {@code null} if null String input
3462 * @since 2.1
3463 */
3464 public static String[] splitPreserveAllTokens(final String str) {
3465 return splitWorker(str, null, -1, true);
3466 }
3467
3468 /**
3469 * <p>Splits the provided text into an array, separator specified,
3470 * preserving all tokens, including empty tokens created by adjacent
3471 * separators. This is an alternative to using StringTokenizer.</p>
3472 *
3473 * <p>The separator is not included in the returned String array.
3474 * Adjacent separators are treated as separators for empty tokens.
3475 * For more control over the split use the StrTokenizer class.</p>
3476 *
3477 * <p>A {@code null} input String returns {@code null}.</p>
3478 *
3479 * <pre>
3480 * StringUtils.splitPreserveAllTokens(null, *) = null
3481 * StringUtils.splitPreserveAllTokens("", *) = []
3482 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b","c"]
3483 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "","b", "c"]
3484 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
3485 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) =["a", "b", "c"]
3486 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b","c"]
3487 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b","c", ""]
3488 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
3489 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b","c"]
3490 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a","b", "c"]
3491 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b","c", ""]
3492 * </pre>
3493 *
3494 * @param str the String to parse,may be {@code null}
3495 * @param separatorChar thecharacter used as the delimiter,
3496 * {@code null} splits onwhitespace
3497 * @return an array of parsed Strings, {@code null} if null String input
3498 * @since 2.1
3499 */
3500 public static String[] splitPreserveAllTokens(final String str, finalchar separatorChar) {
3501 return splitWorker(str, separatorChar, true);
3502 }
3503
3504 /**
3505 * Performs the logic for the {@code split} and
3506 * {@code splitPreserveAllTokens} methods that do not return a
3507 * maximum array length.
3508 *
3509 * @param str the String to parse,may be {@code null}
3510 * @param separatorChar the separate character
3511 * @param preserveAllTokens if {@code true}, adjacent separators are
3512 * treated as empty token separators; if {@code false}, adjacent
3513 * separators are treated as one separator.
3514 * @return an array of parsed Strings, {@code null} if null String input
3515 */
3516 private static String[] splitWorker(final String str, final charseparatorChar, final boolean preserveAllTokens) {
3517 // Performance tuned for 2.0 (JDK1.4)
3518
3519 if (str == null) {
3520 return null;
3521 }
3522 final int len = str.length();
3523 if (len == 0) {
3524 returnArrayUtils.EMPTY_STRING_ARRAY;
3525 }
3526 final List<String> list = new ArrayList<>();
3527 int i = 0, start = 0;
3528 boolean match = false;
3529 boolean lastMatch = false;
3530 while (i < len) {
3531 if (str.charAt(i) == separatorChar){
3532 if (match ||preserveAllTokens) {
3533 list.add(str.substring(start, i));
3534 match = false;
3535 lastMatch = true;
3536 }
3537 start = ++i;
3538 continue;
3539 }
3540 lastMatch = false;
3541 match = true;
3542 i++;
3543 }
3544 if (match || preserveAllTokens && lastMatch) {
3545 list.add(str.substring(start, i));
3546 }
3547 return list.toArray(new String[list.size()]);
3548 }
3549
3550 /**
3551 * <p>Splits the provided text into an array, separators specified,
3552 * preserving all tokens, including empty tokens created by adjacent
3553 * separators. This is an alternative to using StringTokenizer.</p>
3554 *
3555 * <p>The separator is not included in the returned String array.
3556 * Adjacent separators are treated as separators for empty tokens.
3557 * For more control over the split use the StrTokenizer class.</p>
3558 *
3559 * <p>A {@code null} input String returns {@code null}.
3560 * A {@code null} separatorChars splits on whitespace.</p>
3561 *
3562 * <pre>
3563 * StringUtils.splitPreserveAllTokens(null, *) = null
3564 * StringUtils.splitPreserveAllTokens("", *) = []
3565 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
3566 * StringUtils.splitPreserveAllTokens("abc def", "") = ["abc","def"]
3567 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
3568 * StringUtils.splitPreserveAllTokens("ab:cd:ef",":") = ["ab","cd", "ef"]
3569 * StringUtils.splitPreserveAllTokens("ab:cd:ef:",":") = ["ab","cd", "ef", ""]
3570 * StringUtils.splitPreserveAllTokens("ab:cd:ef::",":") = ["ab", "cd", "ef", "",""]
3571 * StringUtils.splitPreserveAllTokens("ab::cd:ef",":") = ["ab","", cd", "ef"]
3572 * StringUtils.splitPreserveAllTokens(":cd:ef",":") = ["",cd", "ef"]
3573 * StringUtils.splitPreserveAllTokens("::cd:ef",":") = ["","", cd", "ef"]
3574 * StringUtils.splitPreserveAllTokens(":cd:ef:",":") = ["", cd","ef", ""]
3575 * </pre>
3576 *
3577 * @param str the String to parse,may be {@code null}
3578 * @param separatorChars thecharacters used as the delimiters,
3579 * {@code null} splits onwhitespace
3580 * @return an array of parsed Strings, {@code null} if null String input
3581 * @since 2.1
3582 */
3583 public static String[] splitPreserveAllTokens(final String str, finalString separatorChars) {
3584 return splitWorker(str, separatorChars, -1, true);
3585 }
3586
3587 /**
3588 * <p>Splits the provided text into an array with a maximum length,
3589 * separators specified, preserving all tokens, including empty tokens
3590 * created by adjacent separators.</p>
3591 *
3592 * <p>The separator is not included in the returned String array.
3593 * Adjacent separators are treated as separators for empty tokens.
3594 * Adjacent separators are treated as one separator.</p>
3595 *
3596 * <p>A {@code null} input String returns {@code null}.
3597 * A {@code null} separatorChars splits on whitespace.</p>
3598 *
3599 * <p>If more than {@code max} delimited substrings are found, thelast
3600 * returned string includes all characters after the first {@code max -1}
3601 * returned strings (including separator characters).</p>
3602 *
3603 * <pre>
3604 * StringUtils.splitPreserveAllTokens(null, *, *) = null
3605 * StringUtils.splitPreserveAllTokens("", *, *) = []
3606 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd","ef"]
3607 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab","cd", "ef"]
3608 * StringUtils.splitPreserveAllTokens("ab:cd:ef",":", 0) = ["ab","cd", "ef"]
3609 * StringUtils.splitPreserveAllTokens("ab:cd:ef",":", 2) = ["ab","cd:ef"]
3610 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab"," de fg"]
3611 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab","", " de fg"]
3612 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab","", "", "de fg"]
3613 * </pre>
3614 *
3615 * @param str the String to parse,may be {@code null}
3616 * @param separatorChars thecharacters used as the delimiters,
3617 * {@code null} splits onwhitespace
3618 * @param max the maximum numberof elements to include in the
3619 * array. A zero or negative valueimplies no limit
3620 * @return an array of parsed Strings, {@code null} if null String input
3621 * @since 2.1
3622 */
3623 public static String[] splitPreserveAllTokens(final String str, finalString separatorChars, final int max) {
3624 return splitWorker(str, separatorChars, max, true);
3625 }
3626
3627 /**
3628 * Performs the logic for the {@code split} and
3629 * {@code splitPreserveAllTokens} methods that return a maximum array
3630 * length.
3631 *
3632 * @param str the String to parse,may be {@code null}
3633 * @param separatorChars the separate character
3634 * @param max the maximum numberof elements to include in the
3635 * array. A zero or negative valueimplies no limit.
3636 * @param preserveAllTokens if {@code true}, adjacent separators are
3637 * treated as empty token separators; if {@code false}, adjacent
3638 * separators are treated as one separator.
3639 * @return an array of parsed Strings, {@code null} if null String input
3640 */
3641 private static String[] splitWorker(final String str, final StringseparatorChars, final int max, final boolean preserveAllTokens) {
3642 // Performance tuned for 2.0 (JDK1.4)
3643 // Direct code is quicker than StringTokenizer.
3644 // Also, StringTokenizer uses isSpace() not isWhitespace()
3645
3646 if (str == null) {
3647 return null;
3648 }
3649 final int len = str.length();
3650 if (len == 0) {
3651 returnArrayUtils.EMPTY_STRING_ARRAY;
3652 }
3653 final List<String> list = new ArrayList<>();
3654 int sizePlus1 = 1;
3655 int i = 0, start = 0;
3656 boolean match = false;
3657 boolean lastMatch = false;
3658 if (separatorChars == null) {
3659 // Null separator means usewhitespace
3660 while (i < len) {
3661 if (Character.isWhitespace(str.charAt(i))){
3662 if (match ||preserveAllTokens) {
3663 lastMatch = true;
3664 if (sizePlus1++ == max){
3665 i = len;
3666 lastMatch = false;
3667 }
3668 list.add(str.substring(start, i));
3669 match = false;
3670 }
3671 start = ++i;
3672 continue;
3673 }
3674 lastMatch = false;
3675 match = true;
3676 i++;
3677 }
3678 } else if (separatorChars.length() == 1) {
3679 // Optimise 1 character case
3680 final char sep =separatorChars.charAt(0);
3681 while (i < len) {
3682 if (str.charAt(i) == sep) {
3683 if (match ||preserveAllTokens) {
3684 lastMatch = true;
3685 if (sizePlus1++ == max){
3686 i = len;
3687 lastMatch = false;
3688 }
3689 list.add(str.substring(start, i));
3690 match = false;
3691 }
3692 start = ++i;
3693 continue;
3694 }
3695 lastMatch = false;
3696 match = true;
3697 i++;
3698 }
3699 } else {
3700 // standard case
3701 while (i < len) {
3702 if(separatorChars.indexOf(str.charAt(i)) >= 0) {
3703 if (match ||preserveAllTokens) {
3704 lastMatch = true;
3705 if (sizePlus1++ == max){
3706 i = len;
3707 lastMatch = false;
3708 }
3709 list.add(str.substring(start, i));
3710 match = false;
3711 }
3712 start = ++i;
3713 continue;
3714 }
3715 lastMatch = false;
3716 match = true;
3717 i++;
3718 }
3719 }
3720 if (match || preserveAllTokens && lastMatch) {
3721 list.add(str.substring(start, i));
3722 }
3723 return list.toArray(new String[list.size()]);
3724 }
3725
3726 /**
3727 * <p>Splits a String by Character type as returned by
3728 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3729 * characters of the same type are returned as complete tokens.
3730 * <pre>
3731 * StringUtils.splitByCharacterType(null) = null
3732 * StringUtils.splitByCharacterType("") = []
3733 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ","de", " ", "fg"]
3734 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ","fg"]
3735 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":","cd", ":", "ef"]
3736 * StringUtils.splitByCharacterType("number5") = ["number", "5"]
3737 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B","ar"]
3738 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200","B", "ar"]
3739 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
3740 * </pre>
3741 * @param str the String to split, may be {@code null}
3742 * @return an array of parsed Strings, {@code null} if null String input
3743 * @since 2.4
3744 */
3745 public static String[] splitByCharacterType(final String str) {
3746 return splitByCharacterType(str, false);
3747 }
3748
3749 /**
3750 * <p>Splits a String by Character type as returned by
3751 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3752 * characters of the same type are returned as complete tokens, with the
3753 * following exception: the character of type
3754 * {@code Character.UPPERCASE_LETTER}, if any, immediately
3755 * preceding a token of type {@code Character.LOWERCASE_LETTER}
3756 * will belong to the following token rather than to the preceding, ifany,
3757 * {@code Character.UPPERCASE_LETTER} token.
3758 * <pre>
3759 * StringUtils.splitByCharacterTypeCamelCase(null) = null
3760 * StringUtils.splitByCharacterTypeCamelCase("") = []
3761 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ","de", " ", "fg"]
3762 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3763 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":","cd", ":", "ef"]
3764 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
3765 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
3766 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200","Bar"]
3767 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
3768 * </pre>
3769 * @param str the String to split, may be {@code null}
3770 * @return an array of parsed Strings, {@code null} if null String input
3771 * @since 2.4
3772 */
3773 public static String[] splitByCharacterTypeCamelCase(final String str) {
3774 return splitByCharacterType(str, true);
3775 }
3776
3777 /**
3778 * <p>Splits a String by Character type as returned by
3779 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3780 * characters of the same type are returned as complete tokens, with the
3781 * following exception: if {@code camelCase} is {@code true},
3782 * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3783 * immediately preceding a token of type {@codeCharacter.LOWERCASE_LETTER}
3784 * will belong to the following token rather than to the preceding, ifany,
3785 * {@code Character.UPPERCASE_LETTER} token.
3786 * @param str the String to split, may be {@code null}
3787 * @param camelCase whether to use so-called "camel-case" forletter types
3788 * @return an array of parsed Strings, {@code null} if null String input
3789 * @since 2.4
3790 */
3791 private static String[] splitByCharacterType(final String str, finalboolean camelCase) {
3792 if (str == null) {
3793 return null;
3794 }
3795 if (str.isEmpty()) {
3796 returnArrayUtils.EMPTY_STRING_ARRAY;
3797 }
3798 final char[] c = str.toCharArray();
3799 final List<String> list = new ArrayList<>();
3800 int tokenStart = 0;
3801 int currentType = Character.getType(c[tokenStart]);
3802 for (int pos = tokenStart + 1; pos < c.length; pos++) {
3803 final int type =Character.getType(c[pos]);
3804 if (type == currentType) {
3805 continue;
3806 }
3807 if (camelCase && type ==Character.LOWERCASE_LETTER && currentType ==Character.UPPERCASE_LETTER) {
3808 final int newTokenStart = pos -1;
3809 if (newTokenStart !=tokenStart) {
3810 list.add(new String(c,tokenStart, newTokenStart - tokenStart));
3811 tokenStart = newTokenStart;
3812 }
3813 } else {
3814 list.add(new String(c,tokenStart, pos - tokenStart));
3815 tokenStart = pos;
3816 }
3817 currentType = type;
3818 }
3819 list.add(new String(c, tokenStart, c.length - tokenStart));
3820 return list.toArray(newString[list.size()]);
3821 }
3822
3823 // Joining
3824 //-----------------------------------------------------------------------
3825 /**
3826 * <p>Joins the elements of the provided array into a single String
3827 * containing the provided list of elements.</p>
3828 *
3829 * <p>No separator is added to the joined String.
3830 * Null objects or empty strings within the array are represented by
3831 * empty strings.</p>
3832 *
3833 * <pre>
3834 * StringUtils.join(null) = null
3835 * StringUtils.join([]) = ""
3836 * StringUtils.join([null]) = ""
3837 * StringUtils.join(["a", "b", "c"]) ="abc"
3838 * StringUtils.join([null, "", "a"]) = "a"
3839 * </pre>
3840 *
3841 * @param <T> the specific type of values to join together
3842 * @param elements the values tojoin together, may be null
3843 * @return the joined String, {@code null} if null array input
3844 * @since 2.0
3845 * @since 3.0 Changed signature to use varargs
3846 */
3847 @SafeVarargs
3848 public static <T> String join(final T... elements) {
3849 return join(elements, null);
3850 }
3851
3852 /**
3853 * <p>Joins the elements of the provided array into a single String
3854 * containing the provided list of elements.</p>
3855 *
3856 * <p>No delimiter is added before or after the list.
3857 * Null objects or empty strings within the array are represented by
3858 * empty strings.</p>
3859 *
3860 * <pre>
3861 * StringUtils.join(null, *) = null
3862 * StringUtils.join([], *) = ""
3863 * StringUtils.join([null], *) = ""
3864 * StringUtils.join(["a", "b", "c"],';') = "a;b;c"
3865 * StringUtils.join(["a", "b", "c"], null)= "abc"
3866 * StringUtils.join([null, "", "a"], ';') = ";;a"
3867 * </pre>
3868 *
3869 * @param array the array ofvalues to join together, may be null
3870 * @param separator the separatorcharacter to use
3871 * @return the joined String, {@code null} if null array input
3872 * @since 2.0
3873 */
3874 public static String join(final Object[] array, final char separator) {
3875 if (array == null) {
3876 return null;
3877 }
3878 return join(array, separator, 0, array.length);
3879 }
3880
3881 /**
3882 * <p>
3883 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
3884 * </p>
3885 *
3886 * <p>
3887 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
3888 * by empty strings.
3889 * </p>
3890 *
3891 * <pre>
3892 * StringUtils.join(null, *) = null
3893 * StringUtils.join([], *) = ""
3894 * StringUtils.join([null], *) = ""
3895 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3896 * StringUtils.join([1, 2, 3], null) = "123"
3897 * </pre>
3898 *
3899 * @param array
3900 * the array of values tojoin together, may be null
3901 * @param separator
3902 * the separatorcharacter to use
3903 * @return the joined String, {@code null} if null array input
3904 * @since 3.2
3905 */
3906 public static String join(final long[] array, final char separator) {
3907 if (array == null) {
3908 return null;
3909 }
3910 return join(array, separator, 0, array.length);
3911 }
3912
3913 /**
3914 * <p>
3915 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
3916 * </p>
3917 *
3918 * <p>
3919 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
3920 * by empty strings.
3921 * </p>
3922 *
3923 * <pre>
3924 * StringUtils.join(null, *) = null
3925 * StringUtils.join([], *) = ""
3926 * StringUtils.join([null], *) = ""
3927 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3928 * StringUtils.join([1, 2, 3], null) = "123"
3929 * </pre>
3930 *
3931 * @param array
3932 * the array of valuesto join together, may be null
3933 * @param separator
3934 * the separatorcharacter to use
3935 * @return the joined String, {@code null} if null array input
3936 * @since 3.2
3937 */
3938 public static String join(final int[] array, final char separator) {
3939 if (array == null) {
3940 return null;
3941 }
3942 return join(array, separator, 0, array.length);
3943 }
3944
3945 /**
3946 * <p>
3947 * Joins the elements of the provided arrayinto a single String containing the provided list of elements.
3948 * </p>
3949 *
3950 * <p>
3951 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
3952 * by empty strings.
3953 * </p>
3954 *
3955 * <pre>
3956 * StringUtils.join(null, *) = null
3957 * StringUtils.join([], *) = ""
3958 * StringUtils.join([null], *) = ""
3959 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3960 * StringUtils.join([1, 2, 3], null) = "123"
3961 * </pre>
3962 *
3963 * @param array
3964 * the array of values tojoin together, may be null
3965 * @param separator
3966 * the separatorcharacter to use
3967 * @return the joined String, {@code null} if null array input
3968 * @since 3.2
3969 */
3970 public static String join(final short[] array, final char separator) {
3971 if (array == null) {
3972 return null;
3973 }
3974 return join(array, separator, 0, array.length);
3975 }
3976
3977 /**
3978 * <p>
3979 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
3980 * </p>
3981 *
3982 * <p>
3983 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
3984 * by empty strings.
3985 * </p>
3986 *
3987 * <pre>
3988 * StringUtils.join(null, *) = null
3989 * StringUtils.join([], *) = ""
3990 * StringUtils.join([null], *) = ""
3991 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3992 * StringUtils.join([1, 2, 3], null) = "123"
3993 * </pre>
3994 *
3995 * @param array
3996 * the array of valuesto join together, may be null
3997 * @param separator
3998 * the separatorcharacter to use
3999 * @return the joined String, {@code null} if null array input
4000 * @since 3.2
4001 */
4002 public static String join(final byte[] array, final char separator) {
4003 if (array == null) {
4004 return null;
4005 }
4006 return join(array, separator, 0, array.length);
4007 }
4008
4009 /**
4010 * <p>
4011 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4012 * </p>
4013 *
4014 * <p>
4015 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4016 * by empty strings.
4017 * </p>
4018 *
4019 * <pre>
4020 * StringUtils.join(null, *) = null
4021 * StringUtils.join([], *) = ""
4022 * StringUtils.join([null], *) = ""
4023 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4024 * StringUtils.join([1, 2, 3], null) = "123"
4025 * </pre>
4026 *
4027 * @param array
4028 * the array of valuesto join together, may be null
4029 * @param separator
4030 * the separatorcharacter to use
4031 * @return the joined String, {@code null} if null array input
4032 * @since 3.2
4033 */
4034 public static String join(final char[] array, final char separator) {
4035 if (array == null) {
4036 return null;
4037 }
4038 return join(array, separator, 0, array.length);
4039 }
4040
4041 /**
4042 * <p>
4043 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4044 * </p>
4045 *
4046 * <p>
4047 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4048 * by empty strings.
4049 * </p>
4050 *
4051 * <pre>
4052 * StringUtils.join(null, *) = null
4053 * StringUtils.join([], *) = ""
4054 * StringUtils.join([null], *) = ""
4055 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4056 * StringUtils.join([1, 2, 3], null) = "123"
4057 * </pre>
4058 *
4059 * @param array
4060 * the array of valuesto join together, may be null
4061 * @param separator
4062 * the separatorcharacter to use
4063 * @return the joined String, {@code null} if null array input
4064 * @since 3.2
4065 */
4066 public static String join(final float[] array, final char separator) {
4067 if (array == null) {
4068 return null;
4069 }
4070 return join(array, separator, 0, array.length);
4071 }
4072
4073 /**
4074 * <p>
4075 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4076 * </p>
4077 *
4078 * <p>
4079 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4080 * by empty strings.
4081 * </p>
4082 *
4083 * <pre>
4084 * StringUtils.join(null, *) = null
4085 * StringUtils.join([], *) = ""
4086 * StringUtils.join([null], *) = ""
4087 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4088 * StringUtils.join([1, 2, 3], null) = "123"
4089 * </pre>
4090 *
4091 * @param array
4092 * the array of valuesto join together, may be null
4093 * @param separator
4094 * the separatorcharacter to use
4095 * @return the joined String, {@code null} if null array input
4096 * @since 3.2
4097 */
4098 public static String join(final double[] array, final char separator) {
4099 if (array == null) {
4100 return null;
4101 }
4102 return join(array, separator, 0, array.length);
4103 }
4104
4105
4106 /**
4107 * <p>Joins the elements of the provided array into a single String
4108 * containing the provided list of elements.</p>
4109 *
4110 * <p>No delimiter is added before or after the list.
4111 * Null objects or empty strings within the array are represented by
4112 * empty strings.</p>
4113 *
4114 * <pre>
4115 * StringUtils.join(null, *) = null
4116 * StringUtils.join([], *) = ""
4117 * StringUtils.join([null], *) = ""
4118 * StringUtils.join(["a", "b", "c"],';') = "a;b;c"
4119 * StringUtils.join(["a", "b", "c"], null)= "abc"
4120 * StringUtils.join([null, "", "a"], ';') = ";;a"
4121 * </pre>
4122 *
4123 * @param array the array ofvalues to join together, may be null
4124 * @param separator the separatorcharacter to use
4125 * @param startIndex the first index to start joining from. It is
4126 * an error to pass in an end index past the end of the array
4127 * @param endIndex the index to stop joining from (exclusive). It is
4128 * an error to pass in an end index past the end of the array
4129 * @return the joined String, {@code null} if null array input
4130 * @since 2.0
4131 */
4132 public static String join(final Object[] array, final char separator,final int startIndex, final int endIndex) {
4133 if (array == null) {
4134 return null;
4135 }
4136 final int noOfItems = endIndex - startIndex;
4137 if (noOfItems <= 0) {
4138 return EMPTY;
4139 }
4140 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4141 for (int i = startIndex; i < endIndex; i++) {
4142 if (i > startIndex) {
4143 buf.append(separator);
4144 }
4145 if (array[i] != null) {
4146 buf.append(array[i]);
4147 }
4148 }
4149 return buf.toString();
4150 }
4151
4152 /**
4153 * <p>
4154 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4155 * </p>
4156 *
4157 * <p>
4158 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4159 * by empty strings.
4160 * </p>
4161 *
4162 * <pre>
4163 * StringUtils.join(null, *) = null
4164 * StringUtils.join([], *) = ""
4165 * StringUtils.join([null], *) = ""
4166 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4167 * StringUtils.join([1, 2, 3], null) = "123"
4168 * </pre>
4169 *
4170 * @param array
4171 * the array of valuesto join together, may be null
4172 * @param separator
4173 * the separatorcharacter to use
4174 * @param startIndex
4175 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4176 * array
4177 * @param endIndex
4178 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4179 * the array
4180 * @return the joined String, {@code null} if null array input
4181 * @since 3.2
4182 */
4183 public static String join(final long[] array, final char separator,final int startIndex, final int endIndex) {
4184 if (array == null) {
4185 return null;
4186 }
4187 final int noOfItems = endIndex - startIndex;
4188 if (noOfItems <= 0) {
4189 return EMPTY;
4190 }
4191 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4192 for (int i = startIndex; i < endIndex; i++) {
4193 if (i > startIndex) {
4194 buf.append(separator);
4195 }
4196 buf.append(array[i]);
4197 }
4198 return buf.toString();
4199 }
4200
4201 /**
4202 * <p>
4203 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4204 * </p>
4205 *
4206 * <p>
4207 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4208 * by empty strings.
4209 * </p>
4210 *
4211 * <pre>
4212 * StringUtils.join(null, *) = null
4213 * StringUtils.join([], *) = ""
4214 * StringUtils.join([null], *) = ""
4215 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4216 * StringUtils.join([1, 2, 3], null) = "123"
4217 * </pre>
4218 *
4219 * @param array
4220 * the array of valuesto join together, may be null
4221 * @param separator
4222 * the separatorcharacter to use
4223 * @param startIndex
4224 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4225 * array
4226 * @param endIndex
4227 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4228 * the array
4229 * @return the joined String, {@code null} if null array input
4230 * @since 3.2
4231 */
4232 public static String join(final int[] array, final char separator, finalint startIndex, final int endIndex) {
4233 if (array == null) {
4234 return null;
4235 }
4236 final int noOfItems = endIndex - startIndex;
4237 if (noOfItems <= 0) {
4238 return EMPTY;
4239 }
4240 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4241 for (int i = startIndex; i < endIndex; i++) {
4242 if (i > startIndex) {
4243 buf.append(separator);
4244 }
4245 buf.append(array[i]);
4246 }
4247 return buf.toString();
4248 }
4249
4250 /**
4251 * <p>
4252 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4253 * </p>
4254 *
4255 * <p>
4256 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4257 * by empty strings.
4258 * </p>
4259 *
4260 * <pre>
4261 * StringUtils.join(null, *) = null
4262 * StringUtils.join([], *) = ""
4263 * StringUtils.join([null], *) = ""
4264 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4265 * StringUtils.join([1, 2, 3], null) = "123"
4266 * </pre>
4267 *
4268 * @param array
4269 * the array of valuesto join together, may be null
4270 * @param separator
4271 * the separatorcharacter to use
4272 * @param startIndex
4273 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4274 * array
4275 * @param endIndex
4276 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4277 * the array
4278 * @return the joined String, {@code null} if null array input
4279 * @since 3.2
4280 */
4281 public static String join(final byte[] array, final char separator,final int startIndex, final int endIndex) {
4282 if (array == null) {
4283 return null;
4284 }
4285 final int noOfItems = endIndex - startIndex;
4286 if (noOfItems <= 0) {
4287 return EMPTY;
4288 }
4289 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4290 for (int i = startIndex; i < endIndex; i++) {
4291 if (i > startIndex) {
4292 buf.append(separator);
4293 }
4294 buf.append(array[i]);
4295 }
4296 return buf.toString();
4297 }
4298
4299 /**
4300 * <p>
4301 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4302 * </p>
4303 *
4304 * <p>
4305 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4306 * by empty strings.
4307 * </p>
4308 *
4309 * <pre>
4310 * StringUtils.join(null, *) = null
4311 * StringUtils.join([], *) = ""
4312 * StringUtils.join([null], *) = ""
4313 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4314 * StringUtils.join([1, 2, 3], null) = "123"
4315 * </pre>
4316 *
4317 * @param array
4318 * the array of valuesto join together, may be null
4319 * @param separator
4320 * the separatorcharacter to use
4321 * @param startIndex
4322 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4323 * array
4324 * @param endIndex
4325 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4326 * the array
4327 * @return the joined String, {@code null} if null array input
4328 * @since 3.2
4329 */
4330 public static String join(final short[] array, final char separator,final int startIndex, final int endIndex) {
4331 if (array == null) {
4332 return null;
4333 }
4334 final int noOfItems = endIndex - startIndex;
4335 if (noOfItems <= 0) {
4336 return EMPTY;
4337 }
4338 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4339 for (int i = startIndex; i < endIndex; i++) {
4340 if (i > startIndex) {
4341 buf.append(separator);
4342 }
4343 buf.append(array[i]);
4344 }
4345 return buf.toString();
4346 }
4347
4348 /**
4349 * <p>
4350 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4351 * </p>
4352 *
4353 * <p>
4354 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4355 * by empty strings.
4356 * </p>
4357 *
4358 * <pre>
4359 * StringUtils.join(null, *) = null
4360 * StringUtils.join([], *) = ""
4361 * StringUtils.join([null], *) = ""
4362 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4363 * StringUtils.join([1, 2, 3], null) = "123"
4364 * </pre>
4365 *
4366 * @param array
4367 * the array of valuesto join together, may be null
4368 * @param separator
4369 * the separatorcharacter to use
4370 * @param startIndex
4371 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4372 * array
4373 * @param endIndex
4374 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4375 * the array
4376 * @return the joined String, {@code null} if null array input
4377 * @since 3.2
4378 */
4379 public static String join(final char[] array, final char separator,final int startIndex, final int endIndex) {
4380 if (array == null) {
4381 return null;
4382 }
4383 final int noOfItems = endIndex - startIndex;
4384 if (noOfItems <= 0) {
4385 return EMPTY;
4386 }
4387 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4388 for (int i = startIndex; i < endIndex; i++) {
4389 if (i > startIndex) {
4390 buf.append(separator);
4391 }
4392 buf.append(array[i]);
4393 }
4394 return buf.toString();
4395 }
4396
4397 /**
4398 * <p>
4399 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4400 * </p>
4401 *
4402 * <p>
4403 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4404 * by empty strings.
4405 * </p>
4406 *
4407 * <pre>
4408 * StringUtils.join(null, *) = null
4409 * StringUtils.join([], *) = ""
4410 * StringUtils.join([null], *) = ""
4411 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4412 * StringUtils.join([1, 2, 3], null) = "123"
4413 * </pre>
4414 *
4415 * @param array
4416 * the array of valuesto join together, may be null
4417 * @param separator
4418 * the separatorcharacter to use
4419 * @param startIndex
4420 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4421 * array
4422 * @param endIndex
4423 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4424 * the array
4425 * @return the joined String, {@code null} if null array input
4426 * @since 3.2
4427 */
4428 public static String join(final double[] array, final char separator,final int startIndex, final int endIndex) {
4429 if (array == null) {
4430 return null;
4431 }
4432 final int noOfItems = endIndex - startIndex;
4433 if (noOfItems <= 0) {
4434 return EMPTY;
4435 }
4436 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4437 for (int i = startIndex; i < endIndex; i++) {
4438 if (i > startIndex) {
4439 buf.append(separator);
4440 }
4441 buf.append(array[i]);
4442 }
4443 return buf.toString();
4444 }
4445
4446 /**
4447 * <p>
4448 * Joins the elements of the provided array into a single Stringcontaining the provided list of elements.
4449 * </p>
4450 *
4451 * <p>
4452 * No delimiter is added before or after the list. Null objects or emptystrings within the array are represented
4453 * by empty strings.
4454 * </p>
4455 *
4456 * <pre>
4457 * StringUtils.join(null, *) = null
4458 * StringUtils.join([], *) = ""
4459 * StringUtils.join([null], *) = ""
4460 * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4461 * StringUtils.join([1, 2, 3], null) = "123"
4462 * </pre>
4463 *
4464 * @param array
4465 * the array of valuesto join together, may be null
4466 * @param separator
4467 * the separatorcharacter to use
4468 * @param startIndex
4469 * the first index tostart joining from. It is an error to pass in an end index past the end of the
4470 * array
4471 * @param endIndex
4472 * the index to stopjoining from (exclusive). It is an error to pass in an end index past the endof
4473 * the array
4474 * @return the joined String, {@code null} if null array input
4475 * @since 3.2
4476 */
4477 public static String join(final float[] array, final char separator,final int startIndex, final int endIndex) {
4478 if (array == null) {
4479 return null;
4480 }
4481 final int noOfItems = endIndex - startIndex;
4482 if (noOfItems <= 0) {
4483 return EMPTY;
4484 }
4485 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4486 for (int i = startIndex; i < endIndex; i++) {
4487 if (i > startIndex) {
4488 buf.append(separator);
4489 }
4490 buf.append(array[i]);
4491 }
4492 return buf.toString();
4493 }
4494
4495
4496 /**
4497 * <p>Joins the elements of the provided array into a single String
4498 * containing the provided list of elements.</p>
4499 *
4500 * <p>No delimiter is added before or after the list.
4501 * A {@code null} separator is the same as an empty String("").
4502 * Null objects or empty strings within the array are represented by
4503 * empty strings.</p>
4504 *
4505 * <pre>
4506 * StringUtils.join(null, *) = null
4507 * StringUtils.join([], *) = ""
4508 * StringUtils.join([null], *) = ""
4509 * StringUtils.join(["a", "b", "c"],"--") = "a--b--c"
4510 * StringUtils.join(["a", "b", "c"],null) = "abc"
4511 * StringUtils.join(["a", "b", "c"],"") = "abc"
4512 * StringUtils.join([null, "", "a"], ',') = ",,a"
4513 * </pre>
4514 *
4515 * @param array the array ofvalues to join together, may be null
4516 * @param separator the separatorcharacter to use, null treated as ""
4517 * @return the joined String, {@code null} if null array input
4518 */
4519 public static String join(final Object[] array, final String separator){
4520 if (array == null) {
4521 return null;
4522 }
4523 return join(array, separator, 0, array.length);
4524 }
4525
4526 /**
4527 * <p>Joins the elements of the provided array into a single String
4528 * containing the provided list of elements.</p>
4529 *
4530 * <p>No delimiter is added before or after the list.
4531 * A {@code null} separator is the same as an empty String("").
4532 * Null objects or empty strings within the array are represented by
4533 * empty strings.</p>
4534 *
4535 * <pre>
4536 * StringUtils.join(null, *, *, *) = null
4537 * StringUtils.join([], *, *, *) = ""
4538 * StringUtils.join([null], *, *, *) = ""
4539 * StringUtils.join(["a", "b", "c"],"--", 0, 3) ="a--b--c"
4540 * StringUtils.join(["a", "b", "c"],"--", 1, 3) = "b--c"
4541 * StringUtils.join(["a", "b", "c"],"--", 2, 3) = "c"
4542 * StringUtils.join(["a", "b", "c"],"--", 2, 2) = ""
4543 * StringUtils.join(["a", "b", "c"], null,0, 3) = "abc"
4544 * StringUtils.join(["a", "b", "c"],"", 0, 3) = "abc"
4545 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a"
4546 * </pre>
4547 *
4548 * @param array the array ofvalues to join together, may be null
4549 * @param separator the separatorcharacter to use, null treated as ""
4550 * @param startIndex the first index to start joining from.
4551 * @param endIndex the index to stop joining from (exclusive).
4552 * @return the joined String, {@code null} if null array input; or theempty string
4553 * if {@code endIndex - startIndex <= 0}. The number of joined entriesis given by
4554 * {@code endIndex - startIndex}
4555 * @throws ArrayIndexOutOfBoundsException ife<br>
4556 * {@code startIndex < 0} or <br>
4557 * {@code startIndex >= array.length()} or <br>
4558 * {@code endIndex < 0} or <br>
4559 * {@code endIndex > array.length()}
4560 */
4561 public static String join(final Object[] array, String separator, finalint startIndex, final int endIndex) {
4562 if (array == null) {
4563 return null;
4564 }
4565 if (separator == null) {
4566 separator = EMPTY;
4567 }
4568
4569 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
4570 // (Assuming that allStrings are roughly equally long)
4571 final int noOfItems = endIndex - startIndex;
4572 if (noOfItems <= 0) {
4573 return EMPTY;
4574 }
4575
4576 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4577
4578 for (int i = startIndex; i < endIndex; i++) {
4579 if (i > startIndex) {
4580 buf.append(separator);
4581 }
4582 if (array[i] != null) {
4583 buf.append(array[i]);
4584 }
4585 }
4586 return buf.toString();
4587 }
4588
4589 /**
4590 * <p>Joins the elements of the provided {@code Iterator} into
4591 * a single String containing the provided elements.</p>
4592 *
4593 * <p>No delimiter is added before or after the list. Null objectsor empty
4594 * strings within the iteration are represented by emptystrings.</p>
4595 *
4596 * <p>See the examples here: {@link #join(Object[],char)}.</p>
4597 *
4598 * @param iterator the {@codeIterator} of values to join together, may be null
4599 * @param separator the separatorcharacter to use
4600 * @return the joined String, {@code null} if null iterator input
4601 * @since 2.0
4602 */
4603 public static String join(final Iterator<?> iterator, final charseparator) {
4604
4605 // handle null, zero and one elements before building a buffer
4606 if (iterator == null) {
4607 return null;
4608 }
4609 if (!iterator.hasNext()) {
4610 return EMPTY;
4611 }
4612 final Object first = iterator.next();
4613 if (!iterator.hasNext()) {
4614 final String result =Objects.toString(first, "");
4615 return result;
4616 }
4617
4618 // two or more elements
4619 final StringBuilder buf = new StringBuilder(256); // Java default is 16,probably too small
4620 if (first != null) {
4621 buf.append(first);
4622 }
4623
4624 while (iterator.hasNext()) {
4625 buf.append(separator);
4626 final Object obj = iterator.next();
4627 if (obj != null) {
4628 buf.append(obj);
4629 }
4630 }
4631
4632 return buf.toString();
4633 }
4634
4635 /**
4636 * <p>Joins the elements of the provided {@code Iterator} into
4637 * a single String containing the provided elements.</p>
4638 *
4639 * <p>No delimiter is added before or after the list.
4640 * A {@code null} separator is the same as an empty String("").</p>
4641 *
4642 * <p>See the examples here: {@link #join(Object[],String)}.</p>
4643 *
4644 * @param iterator the {@codeIterator} of values to join together, may be null
4645 * @param separator the separatorcharacter to use, null treated as ""
4646 * @return the joined String, {@code null} if null iterator input
4647 */
4648 public static String join(final Iterator<?> iterator, final Stringseparator) {
4649
4650 // handle null, zero and one elements before building a buffer
4651 if (iterator == null) {
4652 return null;
4653 }
4654 if (!iterator.hasNext()) {
4655 return EMPTY;
4656 }
4657 final Object first = iterator.next();
4658 if (!iterator.hasNext()) {
4659 final String result = Objects.toString(first,"");
4660 return result;
4661 }
4662
4663 // two or more elements
4664 final StringBuilder buf = new StringBuilder(256); // Java default is 16,probably too small
4665 if (first != null) {
4666 buf.append(first);
4667 }
4668
4669 while (iterator.hasNext()) {
4670 if (separator != null) {
4671 buf.append(separator);
4672 }
4673 final Object obj = iterator.next();
4674 if (obj != null) {
4675 buf.append(obj);
4676 }
4677 }
4678 return buf.toString();
4679 }
4680
4681 /**
4682 * <p>Joins the elements of the provided {@code Iterable} into
4683 * a single String containing the provided elements.</p>
4684 *
4685 * <p>No delimiter is added before or after the list. Null objectsor empty
4686 * strings within the iteration are represented by emptystrings.</p>
4687 *
4688 * <p>See the examples here: {@link #join(Object[],char)}.</p>
4689 *
4690 * @param iterable the {@codeIterable} providing the values to join together, may be null
4691 * @param separator the separatorcharacter to use
4692 * @return the joined String, {@code null} if null iterator input
4693 * @since 2.3
4694 */
4695 public static String join(final Iterable<?> iterable, final charseparator) {
4696 if (iterable == null) {
4697 return null;
4698 }
4699 return join(iterable.iterator(), separator);
4700 }
4701
4702 /**
4703 * <p>Joins the elements of the provided {@code Iterable} into
4704 * a single String containing the provided elements.</p>
4705 *
4706 * <p>No delimiter is added before or after the list.
4707 * A {@code null} separator is the same as an empty String("").</p>
4708 *
4709 * <p>See the examples here: {@link #join(Object[],String)}.</p>
4710 *
4711 * @param iterable the {@codeIterable} providing the values to join together, may be null
4712 * @param separator the separatorcharacter to use, null treated as ""
4713 * @return the joined String, {@code null} if null iterator input
4714 * @since 2.3
4715 */
4716 public static String join(final Iterable<?> iterable, final Stringseparator) {
4717 if (iterable == null) {
4718 return null;
4719 }
4720 return join(iterable.iterator(), separator);
4721 }
4722
4723 /**
4724 * <p>Joins the elements of the provided varargs into a
4725 * single String containing the provided elements.</p>
4726 *
4727 * <p>No delimiter is added before or after the list.
4728 * {@code null} elements and separator are treated as empty Strings("").</p>
4729 *
4730 * <pre>
4731 * StringUtils.joinWith(",", {"a","b"}) = "a,b"
4732 * StringUtils.joinWith(",", {"a","b",""}) ="a,b,"
4733 * StringUtils.joinWith(",", {"a", null,"b"}) = "a,,b"
4734 * StringUtils.joinWith(null,{"a", "b"}) ="ab"
4735 * </pre>
4736 *
4737 * @param separator the separator character to use, null treated as""
4738 * @param objects the varargs providing the values to join together.{@code null} elements are treated as ""
4739 * @return the joined String.
4740 * @throws java.lang.IllegalArgumentException if a null varargs isprovided
4741 * @since 3.5
4742 */
4743 public static String joinWith(final String separator, final Object...objects) {
4744 if (objects == null) {
4745 throw newIllegalArgumentException("Object varargs must not be null");
4746 }
4747
4748 final String sanitizedSeparator = defaultString(separator,StringUtils.EMPTY);
4749
4750 final StringBuilder result = new StringBuilder();
4751
4752 final Iterator<Object> iterator =Arrays.asList(objects).iterator();
4753 while (iterator.hasNext()) {
4754 final String value =Objects.toString(iterator.next(), "");
4755 result.append(value);
4756
4757 if (iterator.hasNext()) {
4758 result.append(sanitizedSeparator);
4759 }
4760 }
4761
4762 return result.toString();
4763 }
4764
4765 // Delete
4766 //-----------------------------------------------------------------------
4767 /**
4768 * <p>Deletes all whitespaces from a String as defined by
4769 * {@link Character#isWhitespace(char)}.</p>
4770 *
4771 * <pre>
4772 * StringUtils.deleteWhitespace(null) = null
4773 * StringUtils.deleteWhitespace("") = ""
4774 * StringUtils.deleteWhitespace("abc") = "abc"
4775 * StringUtils.deleteWhitespace(" ab c ") = "abc"
4776 * </pre>
4777 *
4778 * @param str the String to deletewhitespace from, may be null
4779 * @return the String without whitespaces, {@code null} if null Stringinput
4780 */
4781 public static String deleteWhitespace(final String str) {
4782 if (isEmpty(str)) {
4783 return str;
4784 }
4785 final int sz = str.length();
4786 final char[] chs = new char[sz];
4787 int count = 0;
4788 for (int i = 0; i < sz; i++) {
4789 if(!Character.isWhitespace(str.charAt(i))) {
4790 chs[count++] = str.charAt(i);
4791 }
4792 }
4793 if (count == sz) {
4794 return str;
4795 }
4796 return new String(chs, 0, count);
4797 }
4798
4799 // Remove
4800 //-----------------------------------------------------------------------
4801 /**
4802 * <p>Removes a substring only if it is at the beginning of a sourcestring,
4803 * otherwise returns the source string.</p>
4804 *
4805 * <p>A {@code null} source string will return {@code null}.
4806 * An empty ("") source string will return the empty string.
4807 * A {@code null} search string will return the source string.</p>
4808 *
4809 * <pre>
4810 * StringUtils.removeStart(null, *) = null
4811 * StringUtils.removeStart("", *) = ""
4812 * StringUtils.removeStart(*, null) = *
4813 * StringUtils.removeStart("www.domain.com","www.") ="domain.com"
4814 * StringUtils.removeStart("domain.com", "www.") = "domain.com"
4815 * StringUtils.removeStart("www.domain.com","domain") = "www.domain.com"
4816 * StringUtils.removeStart("abc", "") = "abc"
4817 * </pre>
4818 *
4819 * @param str the source String tosearch, may be null
4820 * @param remove the String tosearch for and remove, may be null
4821 * @return the substring with the string removed if found,
4822 * {@code null} if null Stringinput
4823 * @since 2.1
4824 */
4825 public static String removeStart(final String str, final String remove){
4826 if (isEmpty(str) || isEmpty(remove)) {
4827 return str;
4828 }
4829 if (str.startsWith(remove)){
4830 returnstr.substring(remove.length());
4831 }
4832 return str;
4833 }
4834
4835 /**
4836 * <p>Case insensitive removal of a substring if it is at thebeginning of a source string,
4837 * otherwise returns the source string.</p>
4838 *
4839 * <p>A {@code null} source string will return {@code null}.
4840 * An empty ("") source string will return the empty string.
4841 * A {@code null} search string will return the source string.</p>
4842 *
4843 * <pre>
4844 * StringUtils.removeStartIgnoreCase(null, *) = null
4845 * StringUtils.removeStartIgnoreCase("", *) = ""
4846 * StringUtils.removeStartIgnoreCase(*, null) = *
4847 * StringUtils.removeStartIgnoreCase("www.domain.com","www.") ="domain.com"
4848 * StringUtils.removeStartIgnoreCase("www.domain.com","WWW.") ="domain.com"
4849 * StringUtils.removeStartIgnoreCase("domain.com","www.") ="domain.com"
4850 * StringUtils.removeStartIgnoreCase("www.domain.com","domain") = "www.domain.com"
4851 * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
4852 * </pre>
4853 *
4854 * @param str the source String tosearch, may be null
4855 * @param remove the String tosearch for (case insensitive) and remove, may be null
4856 * @return the substring with the string removed if found,
4857 * {@code null} if null Stringinput
4858 * @since 2.4
4859 */
4860 public static String removeStartIgnoreCase(final String str, finalString remove) {
4861 if (isEmpty(str) || isEmpty(remove)) {
4862 return str;
4863 }
4864 if (startsWithIgnoreCase(str, remove)) {
4865 returnstr.substring(remove.length());
4866 }
4867 return str;
4868 }
4869
4870 /**
4871 * <p>Removes a substring only if it is at the end of a sourcestring,
4872 * otherwise returns the source string.</p>
4873 *
4874 * <p>A {@code null} source string will return {@code null}.
4875 * An empty ("") source string will return the empty string.
4876 * A {@code null} search string will return the source string.</p>
4877 *
4878 * <pre>
4879 * StringUtils.removeEnd(null, *) = null
4880 * StringUtils.removeEnd("", *) = ""
4881 * StringUtils.removeEnd(*, null) = *
4882 * StringUtils.removeEnd("www.domain.com",".com.") ="www.domain.com"
4883 * StringUtils.removeEnd("www.domain.com",".com") ="www.domain"
4884 * StringUtils.removeEnd("www.domain.com", "domain")= "www.domain.com"
4885 * StringUtils.removeEnd("abc", "") = "abc"
4886 * </pre>
4887 *
4888 * @param str the source String tosearch, may be null
4889 * @param remove the String tosearch for and remove, may be null
4890 * @return the substring with the string removed if found,
4891 * {@code null} if null Stringinput
4892 * @since 2.1
4893 */
4894 public static String removeEnd(final String str, final String remove) {
4895 if (isEmpty(str) || isEmpty(remove)) {
4896 return str;
4897 }
4898 if (str.endsWith(remove)) {
4899 return str.substring(0, str.length()- remove.length());
4900 }
4901 return str;
4902 }
4903
4904 /**
4905 * <p>Case insensitive removal of a substring if it is at the endof a source string,
4906 * otherwise returns the source string.</p>
4907 *
4908 * <p>A {@code null} sourcestring will return {@code null}.
4909 * An empty ("") source string will return the empty string.
4910 * A {@code null} search string will return the source string.</p>
4911 *
4912 * <pre>
4913 * StringUtils.removeEndIgnoreCase(null, *) = null
4914 * StringUtils.removeEndIgnoreCase("", *) = ""
4915 * StringUtils.removeEndIgnoreCase(*, null) = *
4916 * StringUtils.removeEndIgnoreCase("www.domain.com",".com.") = "www.domain.com"
4917 * StringUtils.removeEndIgnoreCase("www.domain.com",".com") ="www.domain"
4918 * StringUtils.removeEndIgnoreCase("www.domain.com","domain") = "www.domain.com"
4919 * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
4920 * StringUtils.removeEndIgnoreCase("www.domain.com",".COM") = "www.domain")
4921 * StringUtils.removeEndIgnoreCase("www.domain.COM",".com") = "www.domain")
4922 * </pre>
4923 *
4924 * @param str the source String tosearch, may be null
4925 * @param remove the String tosearch for (case insensitive) and remove, may be null
4926 * @return the substring with the string removed if found,
4927 * {@code null} if null Stringinput
4928 * @since 2.4
4929 */
4930 public static String removeEndIgnoreCase(final String str, final Stringremove) {
4931 if (isEmpty(str) || isEmpty(remove)) {
4932 return str;
4933 }
4934 if (endsWithIgnoreCase(str, remove)) {
4935 return str.substring(0,str.length() - remove.length());
4936 }
4937 return str;
4938 }
4939
4940 /**
4941 * <p>Removes all occurrences of a substring from within the sourcestring.</p>
4942 *
4943 * <p>A {@code null} source string will return {@code null}.
4944 * An empty ("") source string will return the empty string.
4945 * A {@code null} remove string will return the source string.
4946 * An empty ("") remove string will return the sourcestring.</p>
4947 *
4948 * <pre>
4949 * StringUtils.remove(null, *) = null
4950 * StringUtils.remove("", *) = ""
4951 * StringUtils.remove(*, null) = *
4952 * StringUtils.remove(*, "") = *
4953 * StringUtils.remove("queued", "ue") ="qd"
4954 * StringUtils.remove("queued", "zz") ="queued"
4955 * </pre>
4956 *
4957 * @param str the source String tosearch, may be null
4958 * @param remove the String tosearch for and remove, may be null
4959 * @return the substring with the string removed if found,
4960 * {@code null} if null Stringinput
4961 * @since 2.1
4962 */
4963 public static String remove(final String str, final String remove) {
4964 if (isEmpty(str) || isEmpty(remove)) {
4965 return str;
4966 }
4967 return replace(str, remove, EMPTY, -1);
4968 }
4969
4970 /**
4971 * <p>
4972 * Case insensitive removal of all occurrences of a substring from within
4973 * the source string.
4974 * </p>
4975 *
4976 * <p>
4977 * A {@code null} source string will return {@code null}. An empty("")
4978 * source string will return the empty string. A {@code null} removestring
4979 * will return the source string. An empty ("") remove stringwill return
4980 * the source string.
4981 * </p>
4982 *
4983 * <pre>
4984 * StringUtils.removeIgnoreCase(null, *) = null
4985 * StringUtils.removeIgnoreCase("", *) = ""
4986 * StringUtils.removeIgnoreCase(*, null) = *
4987 * StringUtils.removeIgnoreCase(*, "") = *
4988 * StringUtils.removeIgnoreCase("queued", "ue") ="qd"
4989 * StringUtils.removeIgnoreCase("queued", "zz") ="queued"
4990 * StringUtils.removeIgnoreCase("quEUed", "UE") ="qd"
4991 * StringUtils.removeIgnoreCase("queued", "zZ") ="queued"
4992 * </pre>
4993 *
4994 * @param str
4995 * the source String tosearch, may be null
4996 * @param remove
4997 * the String to searchfor (case insensitive) and remove, may be
4998 * null
4999 * @return the substring with the stringremoved if found, {@code null} if
5000 * null String input
5001 * @since 3.5
5002 */
5003 public static String removeIgnoreCase(final String str, final Stringremove) {
5004 if (isEmpty(str) || isEmpty(remove)) {
5005 return str;
5006 }
5007 return replaceIgnoreCase(str, remove, EMPTY, -1);
5008 }
5009
5010 /**
5011 * <p>Removes all occurrences of a character from within the sourcestring.</p>
5012 *
5013 * <p>A {@code null} source string will return {@code null}.
5014 * An empty ("") source string will return the emptystring.</p>
5015 *
5016 * <pre>
5017 * StringUtils.remove(null, *) = null
5018 * StringUtils.remove("", *) = ""
5019 * StringUtils.remove("queued", 'u') = "qeed"
5020 * StringUtils.remove("queued", 'z') = "queued"
5021 * </pre>
5022 *
5023 * @param str the source String tosearch, may be null
5024 * @param remove the char tosearch for and remove, may be null
5025 * @return the substring with the char removed if found,
5026 * {@code null} if null Stringinput
5027 * @since 2.1
5028 */
5029 public static String remove(final String str, final char remove) {
5030 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5031 return str;
5032 }
5033 final char[] chars = str.toCharArray();
5034 int pos = 0;
5035 for (int i = 0; i < chars.length; i++) {
5036 if (chars[i] != remove) {
5037 chars[pos++] = chars[i];
5038 }
5039 }
5040 return new String(chars, 0, pos);
5041 }
5042
5043 /**
5044 * <p>Removes each substring of the text String that matches thegiven regular expression.</p>
5045 *
5046 * This method is a {@code null} safe equivalent to:
5047 * <ul>
5048 * <li>{@codetext.replaceAll(regex, StringUtils.EMPTY)}</li>
5049 * <li>{@codePattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5050 * </ul>
5051 *
5052 * <p>A {@code null} reference passed to this method is ano-op.</p>
5053 *
5054 * <p>Unlike in the {@link #removePattern(String, String)} method,the {@link Pattern#DOTALL} option
5055 * is NOT automatically added.
5056 * To use the DOTALL option prepend<code>"(?s)"</code> to the regex.
5057 * DOTALL is also know as single-line mode in Perl.</p>
5058 *
5059 * <pre>
5060 * StringUtils.removeAll(null, *) = null
5061 * StringUtils.removeAll("any", null) = "any"
5062 * StringUtils.removeAll("any", "") = "any"
5063 * StringUtils.removeAll("any", ".*") = ""
5064 * StringUtils.removeAll("any", ".+") = ""
5065 * StringUtils.removeAll("abc", ".?") = ""
5066 *StringUtils.removeAll("A<__>\n<__>B","<.*>") ="A\nB"
5067 * StringUtils.removeAll("A<__>\n<__>B","(?s)<.*>") ="AB"
5068 * StringUtils.removeAll("ABCabc123abc","[a-z]") ="ABC123"
5069 * </pre>
5070 *
5071 * @param text text to removefrom, may be null
5072 * @param regex the regularexpression to which this string is to be matched
5073 * @return the text with anyremoves processed,
5074 * {@code null} ifnull String input
5075 *
5076 * @throws java.util.regex.PatternSyntaxException
5077 * if the regularexpression's syntax is invalid
5078 *
5079 * @see #replaceAll(String, String, String)
5080 * @see #removePattern(String, String)
5081 * @see String#replaceAll(String, String)
5082 * @see java.util.regex.Pattern
5083 * @see java.util.regex.Pattern#DOTALL
5084 * @since 3.5
5085 */
5086 public static String removeAll(final String text, final String regex) {
5087 return replaceAll(text, regex, StringUtils.EMPTY);
5088 }
5089
5090 /**
5091 * <p>Removes the first substring of the text string that matchesthe given regular expression.</p>
5092 *
5093 * This method is a {@code null} safe equivalent to:
5094 * <ul>
5095 * <li>{@code text.replaceFirst(regex,StringUtils.EMPTY)}</li>
5096 * <li>{@codePattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5097 * </ul>
5098 *
5099 * <p>A {@code null} reference passed to this method is ano-op.</p>
5100 *
5101 * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5102 * To use the DOTALL option prepend<code>"(?s)"</code> to the regex.
5103 * DOTALL is also know as single-line mode in Perl.</p>
5104 *
5105 * <pre>
5106 * StringUtils.removeFirst(null, *) = null
5107 * StringUtils.removeFirst("any", null) = "any"
5108 * StringUtils.removeFirst("any", "") = "any"
5109 * StringUtils.removeFirst("any", ".*") = ""
5110 * StringUtils.removeFirst("any", ".+") = ""
5111 * StringUtils.removeFirst("abc", ".?") = "bc"
5112 *StringUtils.removeFirst("A<__>\n<__>B","<.*>") ="A\n<__>B"
5113 *StringUtils.removeFirst("A<__>\n<__>B","(?s)<.*>") ="AB"
5114 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123"
5115 * StringUtils.removeFirst("ABCabc123abc","[a-z]+") ="ABC123abc"
5116 * </pre>
5117 *
5118 * @param text text to removefrom, may be null
5119 * @param regex the regularexpression to which this string is to be matched
5120 * @return the text with the firstreplacement processed,
5121 * {@code null} ifnull String input
5122 *
5123 * @throws java.util.regex.PatternSyntaxException
5124 * if the regularexpression's syntax is invalid
5125 *
5126 * @see #replaceFirst(String, String, String)
5127 * @see String#replaceFirst(String, String)
5128 * @see java.util.regex.Pattern
5129 * @see java.util.regex.Pattern#DOTALL
5130 * @since 3.5
5131 */
5132 public static String removeFirst(final String text, final String regex){
5133 return replaceFirst(text, regex, StringUtils.EMPTY);
5134 }
5135
5136 // Replacing
5137 //-----------------------------------------------------------------------
5138 /**
5139 * <p>Replaces a String with another String inside a larger String,once.</p>
5140 *
5141 * <p>A {@code null} reference passed to this method is ano-op.</p>
5142 *
5143 * <pre>
5144 * StringUtils.replaceOnce(null, *, *) = null
5145 * StringUtils.replaceOnce("", *, *) = ""
5146 * StringUtils.replaceOnce("any", null, *) = "any"
5147 * StringUtils.replaceOnce("any", *, null) = "any"
5148 * StringUtils.replaceOnce("any", "", *) = "any"
5149 * StringUtils.replaceOnce("aba", "a", null) = "aba"
5150 * StringUtils.replaceOnce("aba", "a","") = "ba"
5151 *StringUtils.replaceOnce("aba", "a", "z") = "zba"
5152 * </pre>
5153 *
5154 * @see #replace(String text, String searchString, String replacement,int max)
5155 * @param text text to search andreplace in, may be null
5156 * @param searchString the Stringto search for, may be null
5157 * @param replacement the Stringto replace with, may be null
5158 * @return the text with any replacements processed,
5159 * {@code null} if null Stringinput
5160 */
5161 public static String replaceOnce(final String text, final StringsearchString, final String replacement) {
5162 return replace(text, searchString, replacement, 1);
5163 }
5164
5165 /**
5166 * <p>Case insensitively replaces a String with another Stringinside a larger String, once.</p>
5167 *
5168 * <p>A {@code null} reference passed to this method is ano-op.</p>
5169 *
5170 * <pre>
5171 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null
5172 * StringUtils.replaceOnceIgnoreCase("", *, *) = ""
5173 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any"
5174 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any"
5175 * StringUtils.replaceOnceIgnoreCase("any", "",*) = "any"
5176 * StringUtils.replaceOnceIgnoreCase("aba", "a",null) = "aba"
5177 * StringUtils.replaceOnceIgnoreCase("aba", "a","") = "ba"
5178 * StringUtils.replaceOnceIgnoreCase("aba", "a","z") = "zba"
5179 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo","foo", "") = "Foofoo"
5180 * </pre>
5181 *
5182 * @see #replaceIgnoreCase(String text, String searchString, String replacement,int max)
5183 * @param text text to search andreplace in, may be null
5184 * @param searchString the Stringto search for (case insensitive), may be null
5185 * @param replacement the Stringto replace with, may be null
5186 * @return the text with any replacements processed,
5187 * {@code null} if null Stringinput
5188 * @since 3.5
5189 */
5190 public static String replaceOnceIgnoreCase(final String text, finalString searchString, final String replacement) {
5191 return replaceIgnoreCase(text, searchString, replacement, 1);
5192 }
5193
5194 /**
5195 * <p>Replaces each substring of the source String that matches thegiven regular expression with the given
5196 * replacement using the {@link Pattern#DOTALL} option. DOTALL is alsoknow as single-line mode in Perl.</p>
5197 *
5198 * This call is a {@code null} safe equivalent to:
5199 * <ul>
5200 * <li>{@code source.replaceAll("(?s)" + regex,replacement)}</li>
5201 * <li>{@code Pattern.compile(regex,Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
5202 * </ul>
5203 *
5204 * <p>A {@code null} reference passed to this method is ano-op.</p>
5205 *
5206 * <pre>
5207 * StringUtils.replacePattern(null, *, *) = null
5208 * StringUtils.replacePattern("any", null, *) = "any"
5209 * StringUtils.replacePattern("any", *, null) = "any"
5210 * StringUtils.replacePattern("", "","zzz") = "zzz"
5211 * StringUtils.replacePattern("",".*", "zzz") ="zzz"
5212 * StringUtils.replacePattern("", ".+","zzz") = ""
5213 *StringUtils.replacePattern("<__>\n<__>","<.*>", "z") = "z"
5214 * StringUtils.replacePattern("ABCabc123", "[a-z]","_") ="ABC___123"
5215 * StringUtils.replacePattern("ABCabc123","[^A-Z0-9]+", "_") ="ABC_123"
5216 * StringUtils.replacePattern("ABCabc123","[^A-Z0-9]+", "") ="ABC123"
5217 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit"
5218 * </pre>
5219 *
5220 * @param source
5221 * the source string
5222 * @param regex
5223 * the regularexpression to which this string is to be matched
5224 * @param replacement
5225 * the string to besubstituted for each match
5226 * @return The resulting {@code String}
5227 * @see #replaceAll(String, String, String)
5228 * @see String#replaceAll(String, String)
5229 * @see Pattern#DOTALL
5230 * @since 3.2
5231 * @since 3.5 Changed {@code null} reference passed to this method is ano-op.
5232 */
5233 public static String replacePattern(final String source, final Stringregex, final String replacement) {
5234 if (source == null || regex == null || replacement == null) {
5235 return source;
5236 }
5237 return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement);
5238 }
5239
5240 /**
5241 * <p>Removes each substring of the source String that matches thegiven regular expression using the DOTALL option.
5242 * </p>
5243 *
5244 * This call is a {@code null} safe equivalent to:
5245 * <ul>
5246 * <li>{@code source.replaceAll("(?s)" + regex,StringUtils.EMPTY)}</li>
5247 * <li>{@code Pattern.compile(regex,Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5248 * </ul>
5249 *
5250 * <p>A {@code null} reference passed to this method is ano-op.</p>
5251 *
5252 * <pre>
5253 * StringUtils.removePattern(null, *) = null
5254 * StringUtils.removePattern("any", null) = "any"
5255 * StringUtils.removePattern("A<__>\n<__>B","<.*>") ="AB"
5256 * StringUtils.removePattern("ABCabc123","[a-z]") ="ABC123"
5257 * </pre>
5258 *
5259 * @param source
5260 * the source string
5261 * @param regex
5262 * the regular expression to which thisstring is to be matched
5263 * @return The resulting {@code String}
5264 * @see #replacePattern(String, String, String)
5265 * @see String#replaceAll(String, String)
5266 * @see Pattern#DOTALL
5267 * @since 3.2
5268 * @since 3.5 Changed {@code null} reference passed to this method is ano-op.
5269 */
5270 public static String removePattern(final String source, final Stringregex) {
5271 return replacePattern(source, regex, StringUtils.EMPTY);
5272 }
5273
5274 /**
5275 * <p>Replaces each substring of the text String that matches thegiven regular expression
5276 * with the given replacement.</p>
5277 *
5278 * This method is a {@code null} safe equivalent to:
5279 * <ul>
5280 * <li>{@codetext.replaceAll(regex, replacement)}</li>
5281 * <li>{@codePattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5282 * </ul>
5283 *
5284 * <p>A {@code null} reference passed to this method is ano-op.</p>
5285 *
5286 * <p>Unlike in the {@link #replacePattern(String, String, String)}method, the {@link Pattern#DOTALL} option
5287 * is NOT automatically added.
5288 * To use the DOTALL option prepend<code>"(?s)"</code> to the regex.
5289 * DOTALL is also know as single-line mode in Perl.</p>
5290 *
5291 * <pre>
5292 * StringUtils.replaceAll(null, *, *) = null
5293 * StringUtils.replaceAll("any", null, *) = "any"
5294 * StringUtils.replaceAll("any", *, null) = "any"
5295 * StringUtils.replaceAll("", "","zzz") = "zzz"
5296 * StringUtils.replaceAll("", ".*","zzz") = "zzz"
5297 * StringUtils.replaceAll("", ".+","zzz") = ""
5298 * StringUtils.replaceAll("abc", "","ZZ") ="ZZaZZbZZcZZ"
5299 *StringUtils.replaceAll("<__>\n<__>","<.*>", "z") = "z\nz"
5300 * StringUtils.replaceAll("<__>\n<__>","(?s)<.*>", "z") = "z"
5301 * StringUtils.replaceAll("ABCabc123", "[a-z]","_") ="ABC___123"
5302 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+","_") = "ABC_123"
5303 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+","") = "ABC123"
5304 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit"
5305 * </pre>
5306 *
5307 * @param text text to search andreplace in, may be null
5308 * @param regex the regularexpression to which this string is to be matched
5309 * @param replacement the stringto be substituted for each match
5310 * @return the text with anyreplacements processed,
5311 * {@code null} ifnull String input
5312 *
5313 * @throws java.util.regex.PatternSyntaxException
5314 * if the regularexpression's syntax is invalid
5315 *
5316 * @see #replacePattern(String, String, String)
5317 * @see String#replaceAll(String, String)
5318 * @see java.util.regex.Pattern
5319 * @see java.util.regex.Pattern#DOTALL
5320 * @since 3.5
5321 */
5322 public static String replaceAll(final String text, final String regex,final String replacement) {
5323 if (text == null || regex == null|| replacement == null ) {
5324 return text;
5325 }
5326 return text.replaceAll(regex, replacement);
5327 }
5328
5329 /**
5330 * <p>Replaces the first substring of the text string that matchesthe given regular expression
5331 * with the given replacement.</p>
5332 *
5333 * This method is a {@code null} safe equivalent to:
5334 * <ul>
5335 * <li>{@code text.replaceFirst(regex,replacement)}</li>
5336 * <li>{@codePattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5337 * </ul>
5338 *
5339 * <p>A {@code null} reference passed to this method is ano-op.</p>
5340 *
5341 * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5342 * To use the DOTALL option prepend<code>"(?s)"</code> to the regex.
5343 * DOTALL is also know as single-line mode in Perl.</p>
5344 *
5345 * <pre>
5346 * StringUtils.replaceFirst(null, *, *) = null
5347 * StringUtils.replaceFirst("any", null, *) = "any"
5348 * StringUtils.replaceFirst("any", *, null) = "any"
5349 * StringUtils.replaceFirst("", "","zzz") = "zzz"
5350 * StringUtils.replaceFirst("", ".*","zzz") = "zzz"
5351 * StringUtils.replaceFirst("", ".+","zzz") = ""
5352 * StringUtils.replaceFirst("abc", "","ZZ") = "ZZabc"
5353 *StringUtils.replaceFirst("<__>\n<__>","<.*>", "z") ="z\n<__>"
5354 *StringUtils.replaceFirst("<__>\n<__>","(?s)<.*>", "z") = "z"
5355 * StringUtils.replaceFirst("ABCabc123", "[a-z]","_") ="ABC_bc123"
5356 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+","_") = "ABC_123abc"
5357 * StringUtils.replaceFirst("ABCabc123abc","[^A-Z0-9]+", "") ="ABC123abc"
5358 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit"
5359 * </pre>
5360 *
5361 * @param text text to search andreplace in, may be null
5362 * @param regex the regularexpression to which this string is to be matched
5363 * @param replacement the stringto be substituted for the first match
5364 * @return the text with the firstreplacement processed,
5365 * {@code null} ifnull String input
5366 *
5367 * @throws java.util.regex.PatternSyntaxException
5368 * if the regularexpression's syntax is invalid
5369 *
5370 * @see String#replaceFirst(String, String)
5371 * @see java.util.regex.Pattern
5372 * @see java.util.regex.Pattern#DOTALL
5373 * @since 3.5
5374 */
5375 public static String replaceFirst(final String text, final String regex,final String replacement) {
5376 if (text == null || regex == null|| replacement == null ) {
5377 return text;
5378 }
5379 return text.replaceFirst(regex, replacement);
5380 }
5381
5382 /**
5383 * <p>Replaces all occurrences of a String within anotherString.</p>
5384 *
5385 * <p>A {@code null} reference passed to this method is ano-op.</p>
5386 *
5387 * <pre>
5388 * StringUtils.replace(null, *, *) = null
5389 * StringUtils.replace("", *, *) = ""
5390 * StringUtils.replace("any", null, *) = "any"
5391 * StringUtils.replace("any", *, null) = "any"
5392 * StringUtils.replace("any", "", *) = "any"
5393 * StringUtils.replace("aba", "a", null) = "aba"
5394 * StringUtils.replace("aba", "a", "") = "b"
5395 * StringUtils.replace("aba", "a","z") = "zbz"
5396 * </pre>
5397 *
5398 * @see #replace(String text, String searchString, String replacement,int max)
5399 * @param text text to search andreplace in, may be null
5400 * @param searchString the Stringto search for, may be null
5401 * @param replacement the Stringto replace it with, may be null
5402 * @return the text with any replacements processed,
5403 * {@code null} if null Stringinput
5404 */
5405 public static String replace(final String text, final StringsearchString, final String replacement) {
5406 return replace(text, searchString, replacement, -1);
5407 }
5408
5409 /**
5410 * <p>Case insensitively replaces all occurrences of a Stringwithin another String.</p>
5411 *
5412 * <p>A {@code null} reference passed to this method is ano-op.</p>
5413 *
5414 * <pre>
5415 * StringUtils.replaceIgnoreCase(null, *, *) = null
5416 * StringUtils.replaceIgnoreCase("", *, *) = ""
5417 * StringUtils.replaceIgnoreCase("any", null, *) = "any"
5418 * StringUtils.replaceIgnoreCase("any", *, null) = "any"
5419 * StringUtils.replaceIgnoreCase("any", "", *) = "any"
5420 * StringUtils.replaceIgnoreCase("aba", "a",null) = "aba"
5421 * StringUtils.replaceIgnoreCase("abA", "A","") = "b"
5422 * StringUtils.replaceIgnoreCase("aba", "A","z") = "zbz"
5423 * </pre>
5424 *
5425 * @see #replaceIgnoreCase(String text, String searchString, Stringreplacement, int max)
5426 * @param text text to search andreplace in, may be null
5427 * @param searchString the Stringto search for (case insensitive), may be null
5428 * @param replacement the Stringto replace it with, may be null
5429 * @return the text with any replacements processed,
5430 * {@code null} if null Stringinput
5431 * @since 3.5
5432 */
5433 public static String replaceIgnoreCase(final String text, final StringsearchString, final String replacement) {
5434 return replaceIgnoreCase(text, searchString, replacement, -1);
5435 }
5436
5437 /**
5438 * <p>Replaces a String with another String inside a larger String,
5439 * for the first {@code max} values of the search String.</p>
5440 *
5441 * <p>A {@code null} reference passed to this method is ano-op.</p>
5442 *
5443 * <pre>
5444 * StringUtils.replace(null, *, *, *) = null
5445 * StringUtils.replace("", *, *, *) = ""
5446 * StringUtils.replace("any", null, *, *) = "any"
5447 * StringUtils.replace("any", *, null, *) = "any"
5448 * StringUtils.replace("any", "", *, *) = "any"
5449 * StringUtils.replace("any", *, *, 0) = "any"
5450 * StringUtils.replace("abaa", "a", null, -1) ="abaa"
5451 * StringUtils.replace("abaa", "a", "",-1) = "b"
5452 * StringUtils.replace("abaa", "a", "z",0) = "abaa"
5453 * StringUtils.replace("abaa", "a", "z",1) = "zbaa"
5454 * StringUtils.replace("abaa", "a", "z",2) = "zbza"
5455 * StringUtils.replace("abaa", "a", "z",-1) = "zbzz"
5456 * </pre>
5457 *
5458 * @param text text to search andreplace in, may be null
5459 * @param searchString the Stringto search for, may be null
5460 * @param replacement the Stringto replace it with, may be null
5461 * @param max maximum number ofvalues to replace, or {@code -1} if no maximum
5462 * @return the text with any replacements processed,
5463 * {@code null} if null Stringinput
5464 */
5465 public static String replace(final String text, final StringsearchString, final String replacement, final int max) {
5466 return replace(text, searchString, replacement, max, false);
5467 }
5468
5469 /**
5470 * <p>Replaces a String with another String inside a larger String,
5471 * for the first {@code max} values of the search String,
5472 * case sensitively/insensisitively based on {@code ignoreCase}value.</p>
5473 *
5474 * <p>A {@code null} reference passed to this method is ano-op.</p>
5475 *
5476 * <pre>
5477 * StringUtils.replace(null, *, *, *, false) = null
5478 * StringUtils.replace("", *, *, *, false) = ""
5479 * StringUtils.replace("any", null, *, *, false) = "any"
5480 * StringUtils.replace("any", *, null, *, false) = "any"
5481 * StringUtils.replace("any", "", *, *, false) = "any"
5482 * StringUtils.replace("any", *, *, 0, false) = "any"
5483 * StringUtils.replace("abaa", "a", null, -1, false)= "abaa"
5484 * StringUtils.replace("abaa", "a", "", -1,false) = "b"
5485 * StringUtils.replace("abaa", "a", "z", 0,false) = "abaa"
5486 * StringUtils.replace("abaa", "A", "z", 1,false) = "abaa"
5487 * StringUtils.replace("abaa", "A", "z", 1,true) = "zbaa"
5488 * StringUtils.replace("abAa", "a", "z", 2,true) = "zbza"
5489 * StringUtils.replace("abAa", "a", "z",-1, true) = "zbzz"
5490 * </pre>
5491 *
5492 * @param text text to search andreplace in, may be null
5493 * @param searchString the Stringto search for (case insensitive), may be null
5494 * @param replacement the Stringto replace it with, may be null
5495 * @param max maximum number ofvalues to replace, or {@code -1} if no maximum
5496 * @param ignoreCase if true replace is case insensitive, otherwise casesensitive
5497 * @return the text with any replacements processed,
5498 * {@code null} if null Stringinput
5499 */
5500 private static String replace(final String text, String searchString,final String replacement, int max, final boolean ignoreCase) {
5501 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max== 0) {
5502 return text;
5503 }
5504 String searchText = text;
5505 if (ignoreCase) {
5506 searchText = text.toLowerCase();
5507 searchString =searchString.toLowerCase();
5508 }
5509 int start = 0;
5510 int end = searchText.indexOf(searchString, start);
5511 if (end == INDEX_NOT_FOUND) {
5512 return text;
5513 }
5514 final int replLength = searchString.length();
5515 int increase = replacement.length() - replLength;
5516 increase = increase < 0 ? 0 : increase;
5517 increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5518 final StringBuilder buf = new StringBuilder(text.length() + increase);
5519 while (end != INDEX_NOT_FOUND) {
5520 buf.append(text.substring(start,end)).append(replacement);
5521 start = end + replLength;
5522 if (--max == 0) {
5523 break;
5524 }
5525 end =searchText.indexOf(searchString, start);
5526 }
5527 buf.append(text.substring(start));
5528 return buf.toString();
5529 }
5530
5531 /**
5532 * <p>Case insensitively replaces a String with another String insidea larger String,
5533 * for the first {@code max} values of the search String.</p>
5534 *
5535 * <p>A {@code null} reference passed to this method is ano-op.</p>
5536 *
5537 * <pre>
5538 * StringUtils.replaceIgnoreCase(null, *, *, *) = null
5539 * StringUtils.replaceIgnoreCase("", *, *, *) = ""
5540 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any"
5541 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any"
5542 * StringUtils.replaceIgnoreCase("any", "", *,*) = "any"
5543 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any"
5544 * StringUtils.replaceIgnoreCase("abaa", "a", null,-1) = "abaa"
5545 * StringUtils.replaceIgnoreCase("abaa", "a","", -1) = "b"
5546 * StringUtils.replaceIgnoreCase("abaa", "a","z", 0) = "abaa"
5547 * StringUtils.replaceIgnoreCase("abaa", "A","z", 1) = "zbaa"
5548 * StringUtils.replaceIgnoreCase("abAa", "a", "z",2) = "zbza"
5549 * StringUtils.replaceIgnoreCase("abAa", "a","z", -1) = "zbzz"
5550 * </pre>
5551 *
5552 * @param text text to search andreplace in, may be null
5553 * @param searchString the Stringto search for (case insensitive), may be null
5554 * @param replacement the Stringto replace it with, may be null
5555 * @param max maximum number ofvalues to replace, or {@code -1} if no maximum
5556 * @return the text with any replacements processed,
5557 * {@code null} if null Stringinput
5558 * @since 3.5
5559 */
5560 public static String replaceIgnoreCase(final String text, final StringsearchString, final String replacement, final int max) {
5561 return replace(text, searchString, replacement, max, true);
5562 }
5563
5564 /**
5565 * <p>
5566 * Replaces all occurrences of Strings within another String.
5567 * </p>
5568 *
5569 * <p>
5570 * A {@code null} reference passed to this method is a no-op, or if
5571 * any "search string" or "string to replace" isnull, that replace will be
5572 * ignored. This will not repeat. For repeating replaces, call the
5573 * overloaded method.
5574 * </p>
5575 *
5576 * <pre>
5577 * StringUtils.replaceEach(null,*, *) = null
5578 * StringUtils.replaceEach("", *, *) = ""
5579 * StringUtils.replaceEach("aba", null, null) = "aba"
5580 * StringUtils.replaceEach("aba", new String[0], null) ="aba"
5581 * StringUtils.replaceEach("aba", null, new String[0]) ="aba"
5582 * StringUtils.replaceEach("aba", new String[]{"a"},null) = "aba"
5583 * StringUtils.replaceEach("aba", new String[]{"a"},new String[]{""}) ="b"
5584 * StringUtils.replaceEach("aba", new String[]{null}, newString[]{"a"}) ="aba"
5585 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"w", "t"}) = "wcte"
5586 * (example of how it does notrepeat)
5587 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"d", "t"}) = "dcte"
5588 * </pre>
5589 *
5590 * @param text
5591 * text to search andreplace in, no-op if null
5592 * @param searchList
5593 * the Strings to search for, no-op ifnull
5594 * @param replacementList
5595 * the Strings toreplace them with, no-op if null
5596 * @return the text with any replacements processed, {@code null} if
5597 * null String input
5598 * @throws IllegalArgumentException
5599 * if the lengths ofthe arrays are not the same (null is ok,
5600 * and/or size 0)
5601 * @since 2.4
5602 */
5603 public static String replaceEach(final String text, final String[]searchList, final String[] replacementList) {
5604 return replaceEach(text, searchList, replacementList, false, 0);
5605 }
5606
5607 /**
5608 * <p>
5609 * Replaces all occurrences of Strings within another String.
5610 * </p>
5611 *
5612 * <p>
5613 * A {@code null} reference passed to this method is a no-op, or if
5614 * any "search string" or "string to replace" isnull, that replace will be
5615 * ignored.
5616 * </p>
5617 *
5618 * <pre>
5619 * StringUtils.replaceEachRepeatedly(null, *, *) = null
5620 * StringUtils.replaceEachRepeatedly("", *, *) = ""
5621 * StringUtils.replaceEachRepeatedly("aba", null, null) ="aba"
5622 * StringUtils.replaceEachRepeatedly("aba", new String[0], null)= "aba"
5623 * StringUtils.replaceEachRepeatedly("aba", null, new String[0])= "aba"
5624 * StringUtils.replaceEachRepeatedly("aba",new String[]{"a"}, null) = "aba"
5625 * StringUtils.replaceEachRepeatedly("aba", newString[]{"a"}, new String[]{""}) = "b"
5626 * StringUtils.replaceEachRepeatedly("aba", new String[]{null},new String[]{"a"}) = "aba"
5627 * StringUtils.replaceEachRepeatedly("abcde", newString[]{"ab", "d"}, new String[]{"w","t"}) = "wcte"
5628 * (example of how it repeats)
5629 * StringUtils.replaceEachRepeatedly("abcde", newString[]{"ab", "d"}, new String[]{"d", "t"})= "tcte"
5630 * StringUtils.replaceEachRepeatedly("abcde", newString[]{"ab", "d"}, new String[]{"d","ab"}) = IllegalStateException
5631 * </pre>
5632 *
5633 * @param text
5634 * text to search andreplace in, no-op if null
5635 * @param searchList
5636 * the Strings to searchfor, no-op if null
5637 * @param replacementList
5638 * the Strings toreplace them with, no-op if null
5639 * @return the text with any replacements processed, {@code null} if
5640 * null String input
5641 * @throws IllegalStateException
5642 * if the search isrepeating and there is an endless loop due
5643 * to outputs of one being inputs toanother
5644 * @throws IllegalArgumentException
5645 * if the lengths ofthe arrays are not the same (null is ok,
5646 * and/or size 0)
5647 * @since 2.4
5648 */
5649 public static String replaceEachRepeatedly(final String text, finalString[] searchList, final String[] replacementList) {
5650 // timeToLive should be 0 if not used or nothing to replace, else it's
5651 // the length of the replace array
5652 final int timeToLive = searchList == null ? 0 : searchList.length;
5653 return replaceEach(text, searchList, replacementList, true, timeToLive);
5654 }
5655
5656 /**
5657 * <p>
5658 * Replace all occurrences of Strings within another String.
5659 * This is a private recursive helper method for {@link#replaceEachRepeatedly(String, String[], String[])} and
5660 * {@link #replaceEach(String, String[], String[])}
5661 * </p>
5662 *
5663 * <p>
5664 * A {@code null} reference passed to this method is a no-op, or if
5665 * any "search string" or "string to replace" isnull, that replace will be
5666 * ignored.
5667 * </p>
5668 *
5669 * <pre>
5670 * StringUtils.replaceEach(null,*, *, *, *) = null
5671 * StringUtils.replaceEach("", *, *, *, *) = ""
5672 * StringUtils.replaceEach("aba", null, null, *, *) ="aba"
5673 * StringUtils.replaceEach("aba", new String[0], null, *, *) ="aba"
5674 * StringUtils.replaceEach("aba", null, new String[0], *, *) ="aba"
5675 * StringUtils.replaceEach("aba", new String[]{"a"},null, *, *) = "aba"
5676 * StringUtils.replaceEach("aba", new String[]{"a"},new String[]{""}, *, >=0) = "b"
5677 * StringUtils.replaceEach("aba", new String[]{null}, newString[]{"a"}, *, >=0) = "aba"
5678 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"w", "t"}, *, >=0) ="wcte"
5679 * (example of how it repeats)
5680 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"d", "t"}, false, >=0) ="dcte"
5681 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"d", "t"}, true, >=2) ="tcte"
5682 * StringUtils.replaceEach("abcde", new String[]{"ab","d"}, new String[]{"d", "ab"}, *, *) =IllegalStateException
5683 * </pre>
5684 *
5685 * @param text
5686 * text to search andreplace in, no-op if null
5687 * @param searchList
5688 * the Strings to searchfor, no-op if null
5689 * @param replacementList
5690 * the Strings toreplace them with, no-op if null
5691 * @param repeat if true, then replace repeatedly
5692 * until there are no morepossible replacements or timeToLive < 0
5693 * @param timeToLive
5694 * if less than 0 thenthere is a circular reference and endless
5695 * loop
5696 * @return the text with any replacements processed, {@code null} if
5697 * null String input
5698 * @throws IllegalStateException
5699 * if the search isrepeating and there is an endless loop due
5700 * to outputs of onebeing inputs to another
5701 * @throws IllegalArgumentException
5702 * if the lengths ofthe arrays are not the same (null is ok,
5703 * and/or size 0)
5704 * @since 2.4
5705 */
5706 private static String replaceEach(
5707 final String text, final String[]searchList, final String[] replacementList, final boolean repeat, final inttimeToLive) {
5708
5709 // mchyzer Performance note: This creates very few new objects (onemajor goal)
5710 // let me know if there are performance requests, we can create aharness to measure
5711
5712 if (text == null || text.isEmpty() || searchList == null ||
5713 searchList.length == 0 ||replacementList == null || replacementList.length == 0) {
5714 return text;
5715 }
5716
5717 // if recursing, this shouldn't be less than 0
5718 if (timeToLive < 0) {
5719 throw newIllegalStateException("Aborting to protect against StackOverflowError -" +
5720 "outputof one loop is the input of another");
5721 }
5722
5723 final int searchLength = searchList.length;
5724 final int replacementLength = replacementList.length;
5725
5726 // make sure lengths are ok, these need to be equal
5727 if (searchLength != replacementLength) {
5728 throw newIllegalArgumentException("Search and Replace array lengths don't match:"
5729 + searchLength
5730 + " vs "
5731 + replacementLength);
5732 }
5733
5734 // keep track of which still have matches
5735 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5736
5737 // index on index that the match was found
5738 int textIndex = -1;
5739 int replaceIndex = -1;
5740 int tempIndex = -1;
5741
5742 // index of replace array that will replace the search string found
5743 // NOTE: logic duplicated below START
5744 for (int i = 0; i < searchLength; i++) {
5745 if (noMoreMatchesForReplIndex[i] ||searchList[i] == null ||
5746 searchList[i].isEmpty() ||replacementList[i] == null) {
5747 continue;
5748 }
5749 tempIndex =text.indexOf(searchList[i]);
5750
5751 // see if we need to keep searchingfor this
5752 if (tempIndex == -1) {
5753 noMoreMatchesForReplIndex[i] =true;
5754 } else {
5755 if (textIndex == -1 ||tempIndex < textIndex) {
5756 textIndex = tempIndex;
5757 replaceIndex = i;
5758 }
5759 }
5760 }
5761 // NOTE: logic mostly below END
5762
5763 // no search strings found, we are done
5764 if (textIndex == -1) {
5765 return text;
5766 }
5767
5768 int start = 0;
5769
5770 // get a good guess on the size of the result buffer so it doesn't haveto double if it goes over a bit
5771 int increase = 0;
5772
5773 // count the replacement text elements that are larger than theircorresponding text being replaced
5774 for (int i = 0; i < searchList.length; i++) {
5775 if (searchList[i] == null ||replacementList[i] == null) {
5776 continue;
5777 }
5778 final int greater =replacementList[i].length() - searchList[i].length();
5779 if (greater > 0) {
5780 increase += 3 * greater; //assume 3 matches
5781 }
5782 }
5783 // have upper-bound at 20% increase, then let Java take over
5784 increase = Math.min(increase, text.length() / 5);
5785
5786 final StringBuilder buf = new StringBuilder(text.length() + increase);
5787
5788 while (textIndex != -1) {
5789
5790 for (int i = start; i <textIndex; i++) {
5791 buf.append(text.charAt(i));
5792 }
5793 buf.append(replacementList[replaceIndex]);
5794
5795 start = textIndex +searchList[replaceIndex].length();
5796
5797 textIndex = -1;
5798 replaceIndex = -1;
5799 tempIndex = -1;
5800 // find the next earliest match
5801 // NOTE: logic mostly duplicatedabove START
5802 for (int i = 0; i <searchLength; i++) {
5803 if(noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5804 searchList[i].isEmpty()|| replacementList[i] == null) {
5805 continue;
5806 }
5807 tempIndex =text.indexOf(searchList[i], start);
5808
5809 // see if we need to keep searchingfor this
5810 if (tempIndex == -1) {
5811 noMoreMatchesForReplIndex[i] = true;
5812 } else {
5813 if (textIndex == -1 ||tempIndex < textIndex) {
5814 textIndex = tempIndex;
5815 replaceIndex = i;
5816 }
5817 }
5818 }
5819 // NOTE: logic duplicated above END
5820
5821 }
5822 final int textLength = text.length();
5823 for (int i = start; i < textLength; i++) {
5824 buf.append(text.charAt(i));
5825 }
5826 final String result = buf.toString();
5827 if (!repeat) {
5828 return result;
5829 }
5830
5831 return replaceEach(result, searchList, replacementList, repeat,timeToLive - 1);
5832 }
5833
5834 // Replace, character based
5835 //-----------------------------------------------------------------------
5836 /**
5837 * <p>Replaces all occurrences of a character in a String withanother.
5838 * This is a null-safe version of {@link String#replace(char,char)}.</p>
5839 *
5840 * <p>A {@code null} string input returns {@code null}.
5841 * An empty ("") string input returns an emptystring.</p>
5842 *
5843 * <pre>
5844 * StringUtils.replaceChars(null, *, *) = null
5845 * StringUtils.replaceChars("", *, *) = ""
5846 * StringUtils.replaceChars("abcba", 'b', 'y') ="aycya"
5847 * StringUtils.replaceChars("abcba", 'z', 'y') ="abcba"
5848 * </pre>
5849 *
5850 * @param str String to replacecharacters in, may be null
5851 * @param searchChar the characterto search for, may be null
5852 * @param replaceChar thecharacter to replace, may be null
5853 * @return modified String, {@code null} if null string input
5854 * @since 2.0
5855 */
5856 public static String replaceChars(final String str, final charsearchChar, final char replaceChar) {
5857 if (str == null) {
5858 return null;
5859 }
5860 return str.replace(searchChar, replaceChar);
5861 }
5862
5863 /**
5864 * <p>Replaces multiple characters in a String in one go.
5865 * This method can also be used to delete characters.</p>
5866 *
5867 * <p>For example:<br>
5868 * <code>replaceChars("hello","ho", "jy") = jelly</code>.</p>
5869 *
5870 * <p>A {@code null} string input returns {@code null}.
5871 * An empty ("") string input returns an empty string.
5872 * A null or empty set of search characters returns the inputstring.</p>
5873 *
5874 * <p>The length of the search characters should normally equal thelength
5875 * of the replace characters.
5876 * If the search characters is longer, then the extra search characters
5877 * are deleted.
5878 * If the search characters is shorter, then the extra replace characters
5879 * are ignored.</p>
5880 *
5881 * <pre>
5882 * StringUtils.replaceChars(null, *, *) = null
5883 * StringUtils.replaceChars("", *, *) = ""
5884 * StringUtils.replaceChars("abc", null, *) = "abc"
5885 * StringUtils.replaceChars("abc", "", *) = "abc"
5886 * StringUtils.replaceChars("abc", "b", null) = "ac"
5887 * StringUtils.replaceChars("abc", "b","") = "ac"
5888 * StringUtils.replaceChars("abcba", "bc","yz") = "ayzya"
5889 * StringUtils.replaceChars("abcba", "bc","y") = "ayya"
5890 * StringUtils.replaceChars("abcba", "bc","yzx") = "ayzya"
5891 * </pre>
5892 *
5893 * @param str String to replacecharacters in, may be null
5894 * @param searchChars a set ofcharacters to search for, may be null
5895 * @param replaceChars a set ofcharacters to replace, may be null
5896 * @return modified String, {@code null} if null string input
5897 * @since 2.0
5898 */
5899 public static String replaceChars(final String str, final StringsearchChars, String replaceChars) {
5900 if (isEmpty(str) || isEmpty(searchChars)) {
5901 return str;
5902 }
5903 if (replaceChars == null) {
5904 replaceChars = EMPTY;
5905 }
5906 boolean modified = false;
5907 final int replaceCharsLength = replaceChars.length();
5908 final int strLength = str.length();
5909 final StringBuilder buf = new StringBuilder(strLength);
5910 for (int i = 0; i < strLength; i++) {
5911 final char ch = str.charAt(i);
5912 final int index =searchChars.indexOf(ch);
5913 if (index >= 0) {
5914 modified = true;
5915 if (index <replaceCharsLength) {
5916 buf.append(replaceChars.charAt(index));
5917 }
5918 } else {
5919 buf.append(ch);
5920 }
5921 }
5922 if (modified) {
5923 return buf.toString();
5924 }
5925 return str;
5926 }
5927
5928 // Overlay
5929 //-----------------------------------------------------------------------
5930 /**
5931 * <p>Overlays part of a String with another String.</p>
5932 *
5933 * <p>A {@code null} string input returns {@code null}.
5934 * A negative index is treated as zero.
5935 * An index greater than the string length is treated as the stringlength.
5936 * The start index is always thesmaller of the two indices.</p>
5937 *
5938 * <pre>
5939 * StringUtils.overlay(null, *, *, *) = null
5940 * StringUtils.overlay("", "abc", 0, 0) = "abc"
5941 * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
5942 * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
5943 * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
5944 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
5945 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
5946 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
5947 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
5948 * StringUtils.overlay("abcdef", "zzzz", -2, -3) ="zzzzabcdef"
5949 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
5950 * </pre>
5951 *
5952 * @param str the String to dooverlaying in, may be null
5953 * @param overlay the String tooverlay, may be null
5954 * @param start the position to start overlaying at
5955 * @param end the position to stopoverlaying before
5956 * @return overlayed String, {@code null} if null String input
5957 * @since 2.0
5958 */
5959 public static String overlay(final String str, String overlay, intstart, int end) {
5960 if (str == null) {
5961 return null;
5962 }
5963 if (overlay == null) {
5964 overlay = EMPTY;
5965 }
5966 final int len = str.length();
5967 if (start < 0) {
5968 start = 0;
5969 }
5970 if (start > len) {
5971 start = len;
5972 }
5973 if (end < 0) {
5974 end = 0;
5975 }
5976 if (end > len) {
5977 end = len;
5978 }
5979 if (start > end) {
5980 final int temp = start;
5981 start = end;
5982 end = temp;
5983 }
5984 return new StringBuilder(len + start - end + overlay.length() + 1)
5985 .append(str.substring(0, start))
5986 .append(overlay)
5987 .append(str.substring(end))
5988 .toString();
5989 }
5990
5991 // Chomping
5992 //-----------------------------------------------------------------------
5993 /**
5994 * <p>Removes one newline from end of a String if it's there,
5995 * otherwise leave it alone. Anewline is "{@code \n}",
5996 * "{@code \r}", or "{@code\r\n}".</p>
5997 *
5998 * <p>NOTE: This method changed in 2.0.
5999 * It now more closely matches Perl chomp.</p>
6000 *
6001 * <pre>
6002 * StringUtils.chomp(null) = null
6003 * StringUtils.chomp("") = ""
6004 * StringUtils.chomp("abc \r") = "abc "
6005 * StringUtils.chomp("abc\n") = "abc"
6006 * StringUtils.chomp("abc\r\n") = "abc"
6007 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
6008 * StringUtils.chomp("abc\n\r") = "abc\n"
6009 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
6010 * StringUtils.chomp("\r") = ""
6011 * StringUtils.chomp("\n") = ""
6012 * StringUtils.chomp("\r\n") = ""
6013 * </pre>
6014 *
6015 * @param str the String to chompa newline from, may be null
6016 * @return String without newline, {@code null} if null String input
6017 */
6018 public static String chomp(final String str) {
6019 if (isEmpty(str)) {
6020 return str;
6021 }
6022
6023 if (str.length() == 1) {
6024 final char ch = str.charAt(0);
6025 if (ch == CharUtils.CR || ch ==CharUtils.LF) {
6026 return EMPTY;
6027 }
6028 return str;
6029 }
6030
6031 int lastIdx = str.length() - 1;
6032 final char last = str.charAt(lastIdx);
6033
6034 if (last == CharUtils.LF) {
6035 if (str.charAt(lastIdx - 1) ==CharUtils.CR) {
6036 lastIdx--;
6037 }
6038 } else if (last != CharUtils.CR) {
6039 lastIdx++;
6040 }
6041 return str.substring(0, lastIdx);
6042 }
6043
6044 /**
6045 * <p>Removes {@code separator} from the end of
6046 * {@code str} if it's there, otherwise leave it alone.</p>
6047 *
6048 * <p>NOTE: This method changed in version 2.0.
6049 * It now more closely matches Perl chomp.
6050 * For the previous behavior, use {@link #substringBeforeLast(String,String)}.
6051 * This method uses {@link String#endsWith(String)}.</p>
6052 *
6053 * <pre>
6054 * StringUtils.chomp(null, *) = null
6055 * StringUtils.chomp("", *) = ""
6056 * StringUtils.chomp("foobar", "bar") ="foo"
6057 * StringUtils.chomp("foobar", "baz") ="foobar"
6058 * StringUtils.chomp("foo", "foo") = ""
6059 * StringUtils.chomp("foo ", "foo") = "foo "
6060 * StringUtils.chomp(" foo", "foo") = " "
6061 * StringUtils.chomp("foo", "foooo") = "foo"
6062 * StringUtils.chomp("foo", "") = "foo"
6063 * StringUtils.chomp("foo", null) = "foo"
6064 * </pre>
6065 *
6066 * @param str the String to chompfrom, may be null
6067 * @param separator separatorString, may be null
6068 * @return String without trailing separator, {@code null} if null Stringinput
6069 * @deprecated This feature will be removed in Lang 4.0, use {@linkStringUtils#removeEnd(String, String)} instead
6070 */
6071 @Deprecated
6072 public static String chomp(final String str, final String separator) {
6073 return removeEnd(str,separator);
6074 }
6075
6076 // Chopping
6077 //-----------------------------------------------------------------------
6078 /**
6079 * <p>Remove the last character from a String.</p>
6080 *
6081 * <p>If the String ends in {@code \r\n}, then remove both
6082 * of them.</p>
6083 *
6084 * <pre>
6085 * StringUtils.chop(null) = null
6086 * StringUtils.chop("") = ""
6087 * StringUtils.chop("abc \r") = "abc "
6088 * StringUtils.chop("abc\n") = "abc"
6089 * StringUtils.chop("abc\r\n") = "abc"
6090 * StringUtils.chop("abc") = "ab"
6091 * StringUtils.chop("abc\nabc") = "abc\nab"
6092 * StringUtils.chop("a") = ""
6093 * StringUtils.chop("\r") = ""
6094 *StringUtils.chop("\n") = ""
6095 * StringUtils.chop("\r\n") = ""
6096 * </pre>
6097 *
6098 * @param str the String to choplast character from, may be null
6099 * @return String without last character, {@code null} if null Stringinput
6100 */
6101 public static String chop(final String str) {
6102 if (str == null) {
6103 return null;
6104 }
6105 final int strLen = str.length();
6106 if (strLen < 2) {
6107 return EMPTY;
6108 }
6109 final int lastIdx = strLen - 1;
6110 final String ret = str.substring(0, lastIdx);
6111 final char last = str.charAt(lastIdx);
6112 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) ==CharUtils.CR) {
6113 return ret.substring(0, lastIdx -1);
6114 }
6115 return ret;
6116 }
6117
6118 // Conversion
6119 //-----------------------------------------------------------------------
6120
6121 // Padding
6122 //-----------------------------------------------------------------------
6123 /**
6124 * <p>Repeat a String {@code repeat} times to form a
6125 * new String.</p>
6126 *
6127 * <pre>
6128 * StringUtils.repeat(null, 2) = null
6129 * StringUtils.repeat("", 0) = ""
6130 * StringUtils.repeat("", 2) = ""
6131 * StringUtils.repeat("a", 3) = "aaa"
6132 * StringUtils.repeat("ab", 2) = "abab"
6133 * StringUtils.repeat("a", -2) = ""
6134 * </pre>
6135 *
6136 * @param str the String torepeat, may be null
6137 * @param repeat number of timesto repeat str, negative treated as zero
6138 * @return a new String consisting of the original String repeated,
6139 * {@code null} if null Stringinput
6140 */
6141 public static String repeat(final String str, final int repeat) {
6142 // Performance tuned for 2.0 (JDK1.4)
6143
6144 if (str == null) {
6145 return null;
6146 }
6147 if (repeat <= 0) {
6148 return EMPTY;
6149 }
6150 final int inputLength = str.length();
6151 if (repeat == 1 || inputLength == 0) {
6152 return str;
6153 }
6154 if (inputLength == 1 && repeat <= PAD_LIMIT) {
6155 return repeat(str.charAt(0),repeat);
6156 }
6157
6158 final int outputLength = inputLength * repeat;
6159 switch (inputLength) {
6160 case 1 :
6161 return repeat(str.charAt(0),repeat);
6162 case 2 :
6163 final char ch0 = str.charAt(0);
6164 final char ch1 = str.charAt(1);
6165 final char[] output2 = newchar[outputLength];
6166 for (int i = repeat * 2 - 2; i>= 0; i--, i--) {
6167 output2[i] = ch0;
6168 output2[i + 1] = ch1;
6169 }
6170 return new String(output2);
6171 default :
6172 final StringBuilder buf= new StringBuilder(outputLength);
6173 for (int i = 0; i < repeat;i++) {
6174 buf.append(str);
6175 }
6176 return buf.toString();
6177 }
6178 }
6179
6180 /**
6181 * <p>Repeat a String {@code repeat} times to form a
6182 * new String, with a String separator injected each time. </p>
6183 *
6184 * <pre>
6185 * StringUtils.repeat(null, null, 2) = null
6186 * StringUtils.repeat(null, "x", 2) = null
6187 * StringUtils.repeat("", null, 0) = ""
6188 * StringUtils.repeat("", "", 2) = ""
6189 * StringUtils.repeat("", "x", 3) = "xxx"
6190 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
6191 * </pre>
6192 *
6193 * @param str the String torepeat, may be null
6194 * @param separator the String toinject, may be null
6195 * @param repeat number oftimes to repeat str, negative treated as zero
6196 * @return a new String consisting of the original String repeated,
6197 * {@code null} if null Stringinput
6198 * @since 2.5
6199 */
6200 public static String repeat(final String str, final String separator,final int repeat) {
6201 if(str == null || separator == null) {
6202 return repeat(str, repeat);
6203 }
6204 // given that repeat(String, int) is quite optimized, better to rely onit than try and splice this into it
6205 final String result = repeat(str + separator, repeat);
6206 return removeEnd(result, separator);
6207 }
6208
6209 /**
6210 * <p>Returns padding using the specified delimiter repeated
6211 * to a given length.</p>
6212 *
6213 * <pre>
6214 * StringUtils.repeat('e', 0) =""
6215 * StringUtils.repeat('e', 3) ="eee"
6216 * StringUtils.repeat('e', -2) = ""
6217 * </pre>
6218 *
6219 * <p>Note: this method doesn't not support padding with
6220 * <ahref="http://www.unicode.org/glossary/#supplementary_character">UnicodeSupplementary Characters</a>
6221 * as they require a pair of {@code char}s to be represented.
6222 * If you are needing to support full I18N of your applications
6223 * consider using {@link #repeat(String, int)} instead.
6224 * </p>
6225 *
6226 * @param ch character to repeat
6227 * @param repeat number of timesto repeat char, negative treated as zero
6228 * @return String with repeated character
6229 * @see #repeat(String, int)
6230 */
6231 public static String repeat(final char ch, final int repeat) {
6232 if (repeat <= 0) {
6233 return EMPTY;
6234 }
6235 final char[] buf = new char[repeat];
6236 for (int i = repeat - 1; i >= 0; i--) {
6237 buf[i] = ch;
6238 }
6239 return new String(buf);
6240 }
6241
6242 /**
6243 * <p>Right pad a String with spaces (' ').</p>
6244 *
6245 * <p>The String is padded to the size of {@code size}.</p>
6246 *
6247 * <pre>
6248 * StringUtils.rightPad(null, *) = null
6249 * StringUtils.rightPad("", 3) = " "
6250 * StringUtils.rightPad("bat", 3) = "bat"
6251 * StringUtils.rightPad("bat", 5) = "bat "
6252 * StringUtils.rightPad("bat", 1) = "bat"
6253 * StringUtils.rightPad("bat", -1) = "bat"
6254 * </pre>
6255 *
6256 * @param str the String to padout, may be null
6257 * @param size the size to pad to
6258 * @return right padded String or original String if no padding isnecessary,
6259 * {@code null} if null Stringinput
6260 */
6261 public static String rightPad(final String str, final int size) {
6262 return rightPad(str, size, ' ');
6263 }
6264
6265 /**
6266 * <p>Right pad a String with a specified character.</p>
6267 *
6268 * <p>The String is padded to the size of {@code size}.</p>
6269 *
6270 * <pre>
6271 * StringUtils.rightPad(null, *, *) = null
6272 * StringUtils.rightPad("", 3, 'z') = "zzz"
6273 * StringUtils.rightPad("bat", 3, 'z') = "bat"
6274 * StringUtils.rightPad("bat", 5, 'z') = "batzz"
6275 * StringUtils.rightPad("bat", 1, 'z') = "bat"
6276 * StringUtils.rightPad("bat", -1, 'z') = "bat"
6277 * </pre>
6278 *
6279 * @param str the String to padout, may be null
6280 * @param size the size to pad to
6281 * @param padChar the character topad with
6282 * @return right padded String or original String if no padding isnecessary,
6283 * {@code null} if null Stringinput
6284 * @since 2.0
6285 */
6286 public static String rightPad(final String str, final int size, finalchar padChar) {
6287 if (str == null) {
6288 return null;
6289 }
6290 final int pads = size - str.length();
6291 if (pads <= 0) {
6292 return str; // returns originalString when possible
6293 }
6294 if (pads > PAD_LIMIT) {
6295 return rightPad(str, size,String.valueOf(padChar));
6296 }
6297 return str.concat(repeat(padChar, pads));
6298 }
6299
6300 /**
6301 * <p>Right pad a String with a specified String.</p>
6302 *
6303 * <p>The String is padded to the size of {@code size}.</p>
6304 *
6305 * <pre>
6306 * StringUtils.rightPad(null, *, *) = null
6307 * StringUtils.rightPad("", 3, "z") = "zzz"
6308 * StringUtils.rightPad("bat", 3, "yz") = "bat"
6309 * StringUtils.rightPad("bat", 5, "yz") = "batyz"
6310 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
6311 * StringUtils.rightPad("bat", 1, "yz") = "bat"
6312 * StringUtils.rightPad("bat", -1, "yz") ="bat"
6313 * StringUtils.rightPad("bat", 5, null) = "bat "
6314 * StringUtils.rightPad("bat", 5, "") = "bat "
6315 * </pre>
6316 *
6317 * @param str the String to padout, may be null
6318 * @param size the size to pad to
6319 * @param padStr the String to padwith, null or empty treated as single space
6320 * @return right padded String or original String if no padding isnecessary,
6321 * {@code null} if null Stringinput
6322 */
6323 public static String rightPad(final String str, final int size, StringpadStr) {
6324 if (str == null) {
6325 return null;
6326 }
6327 if (isEmpty(padStr)) {
6328 padStr = SPACE;
6329 }
6330 final int padLen = padStr.length();
6331 final int strLen = str.length();
6332 final int pads = size - strLen;
6333 if (pads <= 0) {
6334 return str; // returns originalString when possible
6335 }
6336 if (padLen == 1 && pads <= PAD_LIMIT) {
6337 return rightPad(str, size,padStr.charAt(0));
6338 }
6339
6340 if (pads == padLen) {
6341 return str.concat(padStr);
6342 } else if (pads < padLen) {
6343 returnstr.concat(padStr.substring(0, pads));
6344 } else {
6345 final char[] padding = newchar[pads];
6346 final char[] padChars =padStr.toCharArray();
6347 for (int i = 0; i < pads; i++) {
6348 padding[i] = padChars[i% padLen];
6349 }
6350 return str.concat(newString(padding));
6351 }
6352 }
6353
6354 /**
6355 * <p>Left pad a String with spaces (' ').</p>
6356 *
6357 * <p>The String is padded to the size of {@code size}.</p>
6358 *
6359 * <pre>
6360 * StringUtils.leftPad(null, *) =null
6361 * StringUtils.leftPad("", 3) = " "
6362 * StringUtils.leftPad("bat", 3) = "bat"
6363 * StringUtils.leftPad("bat", 5) = " bat"
6364 * StringUtils.leftPad("bat", 1) = "bat"
6365 * StringUtils.leftPad("bat", -1) = "bat"
6366 * </pre>
6367 *
6368 * @param str the String to padout, may be null
6369 * @param size the size to pad to
6370 * @return left padded String or original String if no padding isnecessary,
6371 * {@code null} if null Stringinput
6372 */
6373 public static String leftPad(final String str, final int size) {
6374 return leftPad(str, size, ' ');
6375 }
6376
6377 /**
6378 * <p>Left pad a String with a specified character.</p>
6379 *
6380 * <p>Pad to a size of {@code size}.</p>
6381 *
6382 * <pre>
6383 * StringUtils.leftPad(null, *, *) = null
6384 * StringUtils.leftPad("", 3, 'z') = "zzz"
6385 * StringUtils.leftPad("bat", 3, 'z') = "bat"
6386 * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
6387 * StringUtils.leftPad("bat", 1, 'z') = "bat"
6388 * StringUtils.leftPad("bat", -1, 'z') = "bat"
6389 * </pre>
6390 *
6391 * @param str the String to padout, may be null
6392 * @param size the size to pad to
6393 * @param padChar the character topad with
6394 * @return left padded String or original String if no padding isnecessary,
6395 * {@code null} if null Stringinput
6396 * @since 2.0
6397 */
6398 public static String leftPad(final String str, final int size, finalchar padChar) {
6399 if (str == null) {
6400 return null;
6401 }
6402 final int pads = size - str.length();
6403 if (pads <= 0) {
6404 return str; // returns originalString when possible
6405 }
6406 if (pads > PAD_LIMIT) {
6407 return leftPad(str, size,String.valueOf(padChar));
6408 }
6409 return repeat(padChar, pads).concat(str);
6410 }
6411
6412 /**
6413 * <p>Left pad a String with a specified String.</p>
6414 *
6415 * <p>Pad to a size of{@code size}.</p>
6416 *
6417 * <pre>
6418 * StringUtils.leftPad(null, *, *) = null
6419 * StringUtils.leftPad("", 3, "z") = "zzz"
6420 * StringUtils.leftPad("bat", 3, "yz") = "bat"
6421 * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
6422 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
6423 * StringUtils.leftPad("bat", 1, "yz") = "bat"
6424 * StringUtils.leftPad("bat", -1, "yz") ="bat"
6425 * StringUtils.leftPad("bat", 5, null) = " bat"
6426 * StringUtils.leftPad("bat", 5, "") = " bat"
6427 * </pre>
6428 *
6429 * @param str the String to padout, may be null
6430 * @param size the size to pad to
6431 * @param padStr the String to padwith, null or empty treated as single space
6432 * @return left padded String or original String if no padding isnecessary,
6433 * {@code null} if null Stringinput
6434 */
6435 public static String leftPad(final String str, final int size, StringpadStr) {
6436 if (str == null) {
6437 return null;
6438 }
6439 if (isEmpty(padStr)) {
6440 padStr = SPACE;
6441 }
6442 final int padLen = padStr.length();
6443 final int strLen = str.length();
6444 final int pads = size - strLen;
6445 if (pads <= 0) {
6446 return str; // returns originalString when possible
6447 }
6448 if (padLen == 1 && pads <= PAD_LIMIT) {
6449 return leftPad(str, size,padStr.charAt(0));
6450 }
6451
6452 if (pads == padLen) {
6453 return padStr.concat(str);
6454 } else if (pads < padLen) {
6455 return padStr.substring(0,pads).concat(str);
6456 } else {
6457 final char[] padding = newchar[pads];
6458 final char[] padChars =padStr.toCharArray();
6459 for (int i = 0; i < pads; i++) {
6460 padding[i] = padChars[i %padLen];
6461 }
6462 return newString(padding).concat(str);
6463 }
6464 }
6465
6466 /**
6467 * Gets a CharSequence length or {@code 0} if the CharSequence is
6468 * {@code null}.
6469 *
6470 * @param cs
6471 * a CharSequence or{@code null}
6472 * @return CharSequence length or {@code 0} if the CharSequence is
6473 * {@code null}.
6474 * @since 2.4
6475 * @since 3.0 Changed signature from length(String) tolength(CharSequence)
6476 */
6477 public static int length(final CharSequence cs) {
6478 return cs == null ? 0 : cs.length();
6479 }
6480
6481 // Centering
6482 //-----------------------------------------------------------------------
6483 /**
6484 * <p>Centers a String in a larger String of size {@code size}
6485 * using the space character (' ').</p>
6486 *
6487 * <p>If the size is less than the String length, the String isreturned.
6488 * A {@code null} String returns {@code null}.
6489 * A negative size is treated as zero.</p>
6490 *
6491 * <p>Equivalent to {@code center(str, size, "")}.</p>
6492 *
6493 * <pre>
6494 * StringUtils.center(null, *) =null
6495 * StringUtils.center("", 4) = " "
6496 * StringUtils.center("ab", -1) = "ab"
6497 * StringUtils.center("ab", 4) = " ab "
6498 * StringUtils.center("abcd", 2) = "abcd"
6499 * StringUtils.center("a", 4) = " a "
6500 * </pre>
6501 *
6502 * @param str the String tocenter, may be null
6503 * @param size the int size of newString, negative treated as zero
6504 * @return centered String, {@code null} if null String input
6505 */
6506 public static String center(final String str, final int size) {
6507 return center(str, size, ' ');
6508 }
6509
6510 /**
6511 * <p>Centers a String in a larger String of size {@code size}.
6512 * Uses a supplied character asthe value to pad the String with.</p>
6513 *
6514 * <p>If the size is less than the String length, the String isreturned.
6515 * A {@code null} String returns {@code null}.
6516 * A negative size is treated as zero.</p>
6517 *
6518 * <pre>
6519 * StringUtils.center(null, *, *) = null
6520 * StringUtils.center("", 4, ' ') = " "
6521 * StringUtils.center("ab", -1, ' ') = "ab"
6522 * StringUtils.center("ab", 4, ' ') = " ab "
6523 * StringUtils.center("abcd", 2, ' ') = "abcd"
6524 * StringUtils.center("a", 4, ' ') = " a "
6525 * StringUtils.center("a", 4, 'y') = "yayy"
6526 * </pre>
6527 *
6528 * @param str the String tocenter, may be null
6529 * @param size the int size of newString, negative treated as zero
6530 * @param padChar the character topad the new String with
6531 * @return centered String, {@code null} if null String input
6532 * @since 2.0
6533 */
6534 public static String center(String str, final int size, final charpadChar) {
6535 if (str == null || size <= 0) {
6536 return str;
6537 }
6538 final int strLen = str.length();
6539 final int pads = size - strLen;
6540 if (pads <= 0) {
6541 return str;
6542 }
6543 str = leftPad(str, strLen + pads / 2, padChar);
6544 str = rightPad(str, size, padChar);
6545 return str;
6546 }
6547
6548 /**
6549 * <p>Centers a String in a larger String of size {@code size}.
6550 * Uses a supplied String as the value to pad the String with.</p>
6551 *
6552 * <p>If the size is less than the String length, the String isreturned.
6553 * A {@code null} String returns {@code null}.
6554 * A negative size is treated as zero.</p>
6555 *
6556 * <pre>
6557 * StringUtils.center(null, *, *) = null
6558 * StringUtils.center("", 4, " ") = " "
6559 * StringUtils.center("ab", -1, " ") = "ab"
6560 * StringUtils.center("ab", 4, " ") = " ab "
6561 * StringUtils.center("abcd", 2, " ") ="abcd"
6562 * StringUtils.center("a", 4, " ") = " a "
6563 * StringUtils.center("a", 4, "yz") = "yayz"
6564 * StringUtils.center("abc", 7, null) = " abc "
6565 * StringUtils.center("abc", 7, "") = " abc "
6566 * </pre>
6567 *
6568 * @param str the String tocenter, may be null
6569 * @param size the int size of newString, negative treated as zero
6570 * @param padStr the String to padthe new String with, must not be null or empty
6571 * @return centered String, {@code null} if null String input
6572 * @throws IllegalArgumentException if padStr is {@code null} or empty
6573 */
6574 public static String center(String str, final int size, String padStr) {
6575 if (str == null || size <= 0) {
6576 return str;
6577 }
6578 if (isEmpty(padStr)) {
6579 padStr = SPACE;
6580 }
6581 final int strLen = str.length();
6582 final int pads = size - strLen;
6583 if (pads <= 0) {
6584 return str;
6585 }
6586 str = leftPad(str, strLen + pads / 2, padStr);
6587 str = rightPad(str, size, padStr);
6588 return str;
6589 }
6590
6591 // Case conversion
6592 //-----------------------------------------------------------------------
6593 /**
6594 * <p>Converts a String to upper case as per {@linkString#toUpperCase()}.</p>
6595 *
6596 * <p>A {@code null} input String returns {@code null}.</p>
6597 *
6598 * <pre>
6599 * StringUtils.upperCase(null) =null
6600 * StringUtils.upperCase("") = ""
6601 * StringUtils.upperCase("aBc") = "ABC"
6602 * </pre>
6603 *
6604 * <p><strong>Note:</strong> As described in thedocumentation for {@link String#toUpperCase()},
6605 * the result of this method is affected by the current locale.
6606 * For platform-independent case transformations, the method {@link#lowerCase(String, Locale)}
6607 * should be used with a specific locale (e.g. {@linkLocale#ENGLISH}).</p>
6608 *
6609 * @param str the String to uppercase, may be null
6610 * @return the upper cased String, {@code null} if null String input
6611 */
6612 public static String upperCase(final String str) {
6613 if (str == null) {
6614 return null;
6615 }
6616 return str.toUpperCase();
6617 }
6618
6619 /**
6620 * <p>Converts a String to upper case as per {@linkString#toUpperCase(Locale)}.</p>
6621 *
6622 * <p>A {@code null} input String returns {@code null}.</p>
6623 *
6624 * <pre>
6625 * StringUtils.upperCase(null, Locale.ENGLISH) = null
6626 * StringUtils.upperCase("", Locale.ENGLISH) = ""
6627 * StringUtils.upperCase("aBc", Locale.ENGLISH) ="ABC"
6628 * </pre>
6629 *
6630 * @param str the String to uppercase, may be null
6631 * @param locale the locale thatdefines the case transformation rules, must not be null
6632 * @return the upper cased String, {@code null} if null String input
6633 * @since 2.5
6634 */
6635 public static StringupperCase(final String str, final Locale locale) {
6636 if (str == null) {
6637 return null;
6638 }
6639 return str.toUpperCase(locale);
6640 }
6641
6642 /**
6643 * <p>Converts a String to lower case as per {@linkString#toLowerCase()}.</p>
6644 *
6645 * <p>A {@code null} input String returns {@code null}.</p>
6646 *
6647 * <pre>
6648 * StringUtils.lowerCase(null) =null
6649 * StringUtils.lowerCase("") = ""
6650 * StringUtils.lowerCase("aBc") = "abc"
6651 * </pre>
6652 *
6653 * <p><strong>Note:</strong> As described in thedocumentation for {@link String#toLowerCase()},
6654 * the result of this method is affected by the current locale.
6655 * For platform-independent case transformations, the method {@link#lowerCase(String, Locale)}
6656 * should be used with a specific locale (e.g. {@linkLocale#ENGLISH}).</p>
6657 *
6658 * @param str the String to lower case,may be null
6659 * @return the lower cased String, {@code null} if null String input
6660 */
6661 public static String lowerCase(final String str) {
6662 if (str == null) {
6663 return null;
6664 }
6665 return str.toLowerCase();
6666 }
6667
6668 /**
6669 * <p>Converts a String to lower case as per {@linkString#toLowerCase(Locale)}.</p>
6670 *
6671 * <p>A {@code null} input String returns {@code null}.</p>
6672 *
6673 * <pre>
6674 * StringUtils.lowerCase(null, Locale.ENGLISH) = null
6675 * StringUtils.lowerCase("", Locale.ENGLISH) = ""
6676 * StringUtils.lowerCase("aBc", Locale.ENGLISH) ="abc"
6677 * </pre>
6678 *
6679 * @param str the String to lowercase, may be null
6680 * @param locale the locale thatdefines the case transformation rules, must not be null
6681 * @return the lower cased String, {@code null} if null String input
6682 * @since 2.5
6683 */
6684 public static String lowerCase(final String str, final Locale locale) {
6685 if (str == null) {
6686 return null;
6687 }
6688 return str.toLowerCase(locale);
6689 }
6690
6691 /**
6692 * <p>Capitalizes a String changing the first character to titlecase as
6693 * per {@link Character#toTitleCase(int)}. No other characters arechanged.</p>
6694 *
6695 * <p>For a word based algorithm, see {@linkorg.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6696 * A {@code null} input String returns {@code null}.</p>
6697 *
6698 * <pre>
6699 * StringUtils.capitalize(null) =null
6700 * StringUtils.capitalize("") = ""
6701 * StringUtils.capitalize("cat") = "Cat"
6702 * StringUtils.capitalize("cAt") = "CAt"
6703 * StringUtils.capitalize("'cat'") = "'cat'"
6704 * </pre>
6705 *
6706 * @param str the String to capitalize, may be null
6707 * @return the capitalized String, {@code null} if null String input
6708 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6709 * @see #uncapitalize(String)
6710 * @since 2.0
6711 */
6712 public static String capitalize(final String str) {
6713 int strLen;
6714 if (str == null || (strLen = str.length()) == 0) {
6715 return str;
6716 }
6717
6718 final int firstCodepoint = str.codePointAt(0);
6719 final int newCodePoint = Character.toTitleCase(firstCodepoint);
6720 if (firstCodepoint == newCodePoint) {
6721 // already capitalized
6722 return str;
6723 }
6724
6725 final int newCodePoints[] = new int[strLen]; // cannot be longer thanthe char array
6726 int outOffset = 0;
6727 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6728 for (int inOffset = Character.charCount(firstCodepoint); inOffset <strLen; ) {
6729 final int codepoint =str.codePointAt(inOffset);
6730 newCodePoints[outOffset++] =codepoint; // copy the remaining ones
6731 inOffset +=Character.charCount(codepoint);
6732 }
6733 return new String(newCodePoints, 0, outOffset);
6734 }
6735
6736 /**
6737 * <p>Uncapitalizes a String, changing the first character to lowercase as
6738 * per {@link Character#toLowerCase(int)}. No other characters arechanged.</p>
6739 *
6740 * <p>For a word based algorithm, see {@linkorg.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6741 * A {@code null} input String returns {@code null}.</p>
6742 *
6743 * <pre>
6744 * StringUtils.uncapitalize(null) = null
6745 * StringUtils.uncapitalize("") = ""
6746 * StringUtils.uncapitalize("cat") = "cat"
6747 * StringUtils.uncapitalize("Cat") = "cat"
6748 * StringUtils.uncapitalize("CAT") = "cAT"
6749 * </pre>
6750 *
6751 * @param str the String to uncapitalize, may be null
6752 * @return the uncapitalized String, {@code null} if null String input
6753 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6754 * @see #capitalize(String)
6755 * @since 2.0
6756 */
6757 public static String uncapitalize(final String str) {
6758 int strLen;
6759 if (str == null || (strLen = str.length()) == 0) {
6760 return str;
6761 }
6762
6763 final int firstCodepoint = str.codePointAt(0);
6764 final int newCodePoint = Character.toLowerCase(firstCodepoint);
6765 if (firstCodepoint == newCodePoint) {
6766 // already capitalized
6767 return str;
6768 }
6769
6770 final int newCodePoints[] = new int[strLen]; // cannot be longer thanthe char array
6771 int outOffset = 0;
6772 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6773 for (int inOffset = Character.charCount(firstCodepoint); inOffset <strLen; ) {
6774 final int codepoint =str.codePointAt(inOffset);
6775 newCodePoints[outOffset++]= codepoint; // copy the remaining ones
6776 inOffset +=Character.charCount(codepoint);
6777 }
6778 return new String(newCodePoints, 0, outOffset);
6779 }
6780
6781 /**
6782 * <p>Swaps the case of a String changing upper and title case to
6783 * lower case, and lower case to upper case.</p>
6784 *
6785 * <ul>
6786 * <li>Upper case characterconverts to Lower case</li>
6787 * <li>Title case characterconverts to Lower case</li>
6788 * <li>Lower case characterconverts to Upper case</li>
6789 * </ul>
6790 *
6791 * <p>For a word based algorithm, see {@linkorg.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6792 * A {@code null} input String returns {@code null}.</p>
6793 *
6794 * <pre>
6795 * StringUtils.swapCase(null) = null
6796 * StringUtils.swapCase("") = ""
6797 * StringUtils.swapCase("The dog has a BONE") = "tHE DOGHAS A bone"
6798 * </pre>
6799 *
6800 * <p>NOTE: This method changed in Lang version 2.0.
6801 * It no longer performs a word based algorithm.
6802 * If you only use ASCII, you will notice no change.
6803 * That functionality is available inorg.apache.commons.lang3.text.WordUtils.</p>
6804 *
6805 * @param str the String to swapcase, may be null
6806 * @return the changed String, {@code null} if null String input
6807 */
6808 public static String swapCase(final String str) {
6809 if (StringUtils.isEmpty(str)) {
6810 return str;
6811 }
6812
6813 final int strLen = str.length();
6814 final int newCodePoints[] = new int[strLen]; // cannot be longer thanthe char array
6815 int outOffset = 0;
6816 for (int i = 0; i < strLen; ) {
6817 final int oldCodepoint =str.codePointAt(i);
6818 final int newCodePoint;
6819 if(Character.isUpperCase(oldCodepoint)) {
6820 newCodePoint =Character.toLowerCase(oldCodepoint);
6821 } else if(Character.isTitleCase(oldCodepoint)) {
6822 newCodePoint = Character.toLowerCase(oldCodepoint);
6823 } else if(Character.isLowerCase(oldCodepoint)) {
6824 newCodePoint =Character.toUpperCase(oldCodepoint);
6825 } else {
6826 newCodePoint = oldCodepoint;
6827 }
6828 newCodePoints[outOffset++] =newCodePoint;
6829 i +=Character.charCount(newCodePoint);
6830 }
6831 return new String(newCodePoints, 0, outOffset);
6832 }
6833
6834 // Count matches
6835 //-----------------------------------------------------------------------
6836 /**
6837 * <p>Counts how many times the substring appears in the largerstring.</p>
6838 *
6839 * <p>A {@code null} or empty ("") String input returns{@code 0}.</p>
6840 *
6841 * <pre>
6842 * StringUtils.countMatches(null, *) = 0
6843 * StringUtils.countMatches("", *) = 0
6844 * StringUtils.countMatches("abba", null) = 0
6845 * StringUtils.countMatches("abba", "") = 0
6846 * StringUtils.countMatches("abba", "a") = 2
6847 * StringUtils.countMatches("abba", "ab") = 1
6848 * StringUtils.countMatches("abba", "xxx") = 0
6849 * </pre>
6850 *
6851 * @param str the CharSequence tocheck, may be null
6852 * @param sub the substring tocount, may be null
6853 * @return the number of occurrences, 0 if either CharSequence is {@codenull}
6854 * @since 3.0 Changed signature from countMatches(String, String) tocountMatches(CharSequence, CharSequence)
6855 */
6856 public static int countMatches(final CharSequence str, finalCharSequence sub) {
6857 if (isEmpty(str) || isEmpty(sub)) {
6858 return 0;
6859 }
6860 int count = 0;
6861 int idx = 0;
6862 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) !=INDEX_NOT_FOUND) {
6863 count++;
6864 idx += sub.length();
6865 }
6866 return count;
6867 }
6868
6869 /**
6870 * <p>Counts how many times the char appears in the givenstring.</p>
6871 *
6872 * <p>A {@code null} or empty ("") String input returns{@code 0}.</p>
6873 *
6874 * <pre>
6875 * StringUtils.countMatches(null, *) = 0
6876 * StringUtils.countMatches("", *) = 0
6877 * StringUtils.countMatches("abba", 0) = 0
6878 * StringUtils.countMatches("abba", 'a') = 2
6879 * StringUtils.countMatches("abba", 'b') = 2
6880 * StringUtils.countMatches("abba", 'x') = 0
6881 * </pre>
6882 *
6883 * @param str the CharSequence tocheck, may be null
6884 * @param ch the char to count
6885 * @return the number of occurrences, 0 if the CharSequence is {@codenull}
6886 * @since 3.4
6887 */
6888 public static int countMatches(final CharSequence str, final char ch) {
6889 if (isEmpty(str)) {
6890 return 0;
6891 }
6892 int count = 0;
6893 // We could also call str.toCharArray() for faster look ups but that wouldgenerate more garbage.
6894 for (int i = 0; i < str.length(); i++) {
6895 if (ch == str.charAt(i)) {
6896 count++;
6897 }
6898 }
6899 return count;
6900 }
6901
6902 // Character Tests
6903 //-----------------------------------------------------------------------
6904 /**
6905 * <p>Checks if the CharSequence contains only Unicodeletters.</p>
6906 *
6907 * <p>{@code null} will return {@code false}.
6908 * An empty CharSequence (length()=0) will return {@codefalse}.</p>
6909 *
6910 * <pre>
6911 * StringUtils.isAlpha(null) =false
6912 * StringUtils.isAlpha("") = false
6913 * StringUtils.isAlpha(" ") = false
6914 * StringUtils.isAlpha("abc") = true
6915 * StringUtils.isAlpha("ab2c") = false
6916 * StringUtils.isAlpha("ab-c") = false
6917 * </pre>
6918 *
6919 * @param cs the CharSequence tocheck, may be null
6920 * @return {@code true} if only contains letters, and is non-null
6921 * @since 3.0 Changed signature from isAlpha(String) toisAlpha(CharSequence)
6922 * @since 3.0 Changed "" to return false and not true
6923 */
6924 public static boolean isAlpha(final CharSequence cs) {
6925 if (isEmpty(cs)) {
6926 return false;
6927 }
6928 final int sz = cs.length();
6929 for (int i = 0; i < sz; i++) {
6930 if(Character.isLetter(cs.charAt(i)) == false) {
6931 return false;
6932 }
6933 }
6934 return true;
6935 }
6936
6937 /**
6938 * <p>Checks if the CharSequence contains only Unicode letters and
6939 * space (' ').</p>
6940 *
6941 * <p>{@code null} will return {@code false}
6942 * An empty CharSequence (length()=0) will return {@code true}.</p>
6943 *
6944 * <pre>
6945 * StringUtils.isAlphaSpace(null) = false
6946 * StringUtils.isAlphaSpace("") = true
6947 * StringUtils.isAlphaSpace(" ") = true
6948 * StringUtils.isAlphaSpace("abc") = true
6949 * StringUtils.isAlphaSpace("ab c") = true
6950 * StringUtils.isAlphaSpace("ab2c") = false
6951 * StringUtils.isAlphaSpace("ab-c") = false
6952 * </pre>
6953 *
6954 * @param cs the CharSequence tocheck, may be null
6955 * @return {@code true} if only contains letters and space,
6956 * and is non-null
6957 * @since 3.0 Changed signature from isAlphaSpace(String) toisAlphaSpace(CharSequence)
6958 */
6959 public static boolean isAlphaSpace(final CharSequence cs) {
6960 if (cs == null) {
6961 return false;
6962 }
6963 final int sz = cs.length();
6964 for (int i = 0; i < sz; i++) {
6965 if (Character.isLetter(cs.charAt(i)) == false&& cs.charAt(i) != ' ') {
6966 return false;
6967 }
6968 }
6969 return true;
6970 }
6971
6972 /**
6973 * <p>Checks if the CharSequence contains only Unicode letters ordigits.</p>
6974 *
6975 * <p>{@code null} will return {@code false}.
6976 * An empty CharSequence (length()=0) will return {@codefalse}.</p>
6977 *
6978 * <pre>
6979 * StringUtils.isAlphanumeric(null) = false
6980 * StringUtils.isAlphanumeric("") = false
6981 * StringUtils.isAlphanumeric(" ") = false
6982 * StringUtils.isAlphanumeric("abc") = true
6983 * StringUtils.isAlphanumeric("ab c") = false
6984 * StringUtils.isAlphanumeric("ab2c") = true
6985 * StringUtils.isAlphanumeric("ab-c") = false
6986 * </pre>
6987 *
6988 * @param cs the CharSequence tocheck, may be null
6989 * @return {@code true} if only contains letters or digits,
6990 * and is non-null
6991 * @since 3.0 Changed signature from isAlphanumeric(String) toisAlphanumeric(CharSequence)
6992 * @since 3.0 Changed "" to return false and not true
6993 */
6994 public static boolean isAlphanumeric(final CharSequence cs) {
6995 if (isEmpty(cs)) {
6996 return false;
6997 }
6998 final int sz = cs.length();
6999 for (int i = 0; i < sz; i++) {
7000 if(Character.isLetterOrDigit(cs.charAt(i)) == false) {
7001 return false;
7002 }
7003 }
7004 return true;
7005 }
7006
7007 /**
7008 * <p>Checks if the CharSequence contains only Unicode letters,digits
7009 * or space ({@code ' '}).</p>
7010 *
7011 * <p>{@code null} will return {@code false}.
7012 * An empty CharSequence (length()=0) will return {@code true}.</p>
7013 *
7014 * <pre>
7015 * StringUtils.isAlphanumericSpace(null) = false
7016 * StringUtils.isAlphanumericSpace("") = true
7017 * StringUtils.isAlphanumericSpace(" ") = true
7018 * StringUtils.isAlphanumericSpace("abc") = true
7019 * StringUtils.isAlphanumericSpace("ab c") = true
7020 * StringUtils.isAlphanumericSpace("ab2c") = true
7021 *StringUtils.isAlphanumericSpace("ab-c") = false
7022 * </pre>
7023 *
7024 * @param cs the CharSequence tocheck, may be null
7025 * @return {@code true} if only contains letters, digits or space,
7026 * and is non-null
7027 * @since 3.0 Changed signature from isAlphanumericSpace(String) toisAlphanumericSpace(CharSequence)
7028 */
7029 public static boolean isAlphanumericSpace(final CharSequence cs) {
7030 if (cs == null) {
7031 return false;
7032 }
7033 final int sz = cs.length();
7034 for (int i = 0; i < sz; i++) {
7035 if(Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != '') {
7036 return false;
7037 }
7038 }
7039 return true;
7040 }
7041
7042 /**
7043 * <p>Checks if the CharSequence contains only ASCII printablecharacters.</p>
7044 *
7045 * <p>{@code null} will return {@code false}.
7046 * An empty CharSequence (length()=0) will return {@code true}.</p>
7047 *
7048 * <pre>
7049 * StringUtils.isAsciiPrintable(null) = false
7050 * StringUtils.isAsciiPrintable("") = true
7051 * StringUtils.isAsciiPrintable(" ") = true
7052 * StringUtils.isAsciiPrintable("Ceki") = true
7053 * StringUtils.isAsciiPrintable("ab2c") = true
7054 * StringUtils.isAsciiPrintable("!ab-c~") = true
7055 * StringUtils.isAsciiPrintable("\u0020") = true
7056 * StringUtils.isAsciiPrintable("\u0021") = true
7057 * StringUtils.isAsciiPrintable("\u007e") = true
7058 * StringUtils.isAsciiPrintable("\u007f") = false
7059 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
7060 * </pre>
7061 *
7062 * @param cs the CharSequence to check, may be null
7063 * @return {@code true} if every character is in the range
7064 * 32 thru 126
7065 * @since 2.1
7066 * @since 3.0 Changed signature from isAsciiPrintable(String) toisAsciiPrintable(CharSequence)
7067 */
7068 public static boolean isAsciiPrintable(final CharSequence cs) {
7069 if (cs == null) {
7070 return false;
7071 }
7072 final int sz = cs.length();
7073 for (int i = 0; i < sz; i++) {
7074 if(CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
7075 return false;
7076 }
7077 }
7078 return true;
7079 }
7080
7081 /**
7082 * <p>Checks if the CharSequence contains only Unicode digits.
7083 * A decimal point is not a Unicode digit and returns false.</p>
7084 *
7085 * <p>{@code null} will return {@code false}.
7086 * An empty CharSequence (length()=0) will return {@codefalse}.</p>
7087 *
7088 * <p>Note that the method does not allow for a leading sign,either positive or negative.
7089 * Also, if a String passes the numeric test, it may still generate aNumberFormatException
7090 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the valueis outside the range
7091 * for int or long respectively.</p>
7092 *
7093 * <pre>
7094 * StringUtils.isNumeric(null) =false
7095 * StringUtils.isNumeric("") = false
7096 * StringUtils.isNumeric(" ") = false
7097 * StringUtils.isNumeric("123") = true
7098 * StringUtils.isNumeric("\u0967\u0968\u0969") = true
7099 * StringUtils.isNumeric("12 3") = false
7100 * StringUtils.isNumeric("ab2c") = false
7101 * StringUtils.isNumeric("12-3") = false
7102 * StringUtils.isNumeric("12.3") = false
7103 * StringUtils.isNumeric("-123") = false
7104 * StringUtils.isNumeric("+123") = false
7105 * </pre>
7106 *
7107 * @param cs the CharSequence tocheck, may be null
7108 * @return {@code true} if only contains digits, and is non-null
7109 * @since 3.0 Changed signature from isNumeric(String) toisNumeric(CharSequence)
7110 * @since 3.0 Changed "" to return false and not true
7111 */
7112 public static boolean isNumeric(final CharSequence cs) {
7113 if (isEmpty(cs)) {
7114 return false;
7115 }
7116 final int sz = cs.length();
7117 for (int i = 0; i < sz; i++) {
7118 if(!Character.isDigit(cs.charAt(i))) {
7119 return false;
7120 }
7121 }
7122 return true;
7123 }
7124
7125 /**
7126 * <p>Checks if the CharSequence contains only Unicode digits orspace
7127 * ({@code ' '}).
7128 * A decimal point is not a Unicode digit and returns false.</p>
7129 *
7130 * <p>{@code null} will return {@code false}.
7131 * An empty CharSequence (length()=0) will return {@code true}.</p>
7132 *
7133 * <pre>
7134 * StringUtils.isNumericSpace(null) = false
7135 * StringUtils.isNumericSpace("") = true
7136 * StringUtils.isNumericSpace(" ") = true
7137 * StringUtils.isNumericSpace("123") = true
7138 * StringUtils.isNumericSpace("12 3") = true
7139 * StringUtils.isNumeric("\u0967\u0968\u0969") = true
7140 * StringUtils.isNumeric("\u0967\u0968 \u0969") = true
7141 * StringUtils.isNumericSpace("ab2c") = false
7142 * StringUtils.isNumericSpace("12-3") = false
7143 * StringUtils.isNumericSpace("12.3") = false
7144 * </pre>
7145 *
7146 * @param cs the CharSequence tocheck, may be null
7147 * @return {@code true} if only contains digits or space,
7148 * and is non-null
7149 * @since 3.0 Changed signature from isNumericSpace(String) toisNumericSpace(CharSequence)
7150 */
7151 public static boolean isNumericSpace(final CharSequence cs) {
7152 if (cs == null) {
7153 return false;
7154 }
7155 final int sz = cs.length();
7156 for (int i = 0; i < sz; i++) {
7157 if (Character.isDigit(cs.charAt(i))== false && cs.charAt(i) != ' ') {
7158 return false;
7159 }
7160 }
7161 return true;
7162 }
7163
7164 /**
7165 * <p>Checks if a String {@code str} contains Unicode digits,
7166 * if yes then concatenate all the digits in {@code str} and return it asa String.</p>
7167 *
7168 * <p>An empty ("") String will be returned if no digitsfound in {@code str}.</p>
7169 *
7170 * <pre>
7171 * StringUtils.getDigits(null) =null
7172 * StringUtils.getDigits("") = ""
7173 * StringUtils.getDigits("abc") = ""
7174 * StringUtils.getDigits("1000$") = "1000"
7175 * StringUtils.getDigits("1123~45") = "12345"
7176 * StringUtils.getDigits("(541) 754-3010") ="5417543010"
7177 * StringUtils.getDigits("\u0967\u0968\u0969") ="\u0967\u0968\u0969"
7178 * </pre>
7179 *
7180 * @param str the String to extract digits from, may be null
7181 * @return String with only digits,
7182 * or an empty("") String if no digits found,
7183 * or {@code null} Stringif {@code str} is null
7184 * @since 3.6
7185 */
7186 public static String getDigits(final Stringstr) {
7187 if (isEmpty(str)) {
7188 return str;
7189 }
7190 final int sz = str.length();
7191 final StringBuilder strDigits = new StringBuilder(sz);
7192 for (int i = 0; i < sz; i++) {
7193 final char tempChar =str.charAt(i);
7194 if (Character.isDigit(tempChar)) {
7195 strDigits.append(tempChar);
7196 }
7197 }
7198 return strDigits.toString();
7199 }
7200
7201 /**
7202 * <p>Checks if the CharSequence contains onlywhitespace.</p>
7203 *
7204 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
7205 *
7206 * <p>{@code null} will return {@code false}.
7207 * An empty CharSequence (length()=0) will return {@code true}.</p>
7208 *
7209 * <pre>
7210 * StringUtils.isWhitespace(null) = false
7211 * StringUtils.isWhitespace("") = true
7212 * StringUtils.isWhitespace(" ") = true
7213 *StringUtils.isWhitespace("abc") = false
7214 * StringUtils.isWhitespace("ab2c") = false
7215 * StringUtils.isWhitespace("ab-c") = false
7216 * </pre>
7217 *
7218 * @param cs the CharSequence tocheck, may be null
7219 * @return {@code true} if only contains whitespace, and is non-null
7220 * @since 2.0
7221 * @since 3.0 Changed signature from isWhitespace(String) toisWhitespace(CharSequence)
7222 */
7223 public static boolean isWhitespace(final CharSequence cs) {
7224 if (cs == null) {
7225 return false;
7226 }
7227 final int sz = cs.length();
7228 for (int i = 0; i < sz; i++) {
7229 if(Character.isWhitespace(cs.charAt(i)) == false) {
7230 return false;
7231 }
7232 }
7233 return true;
7234 }
7235
7236 /**
7237 * <p>Checks if the CharSequence contains only lowercasecharacters.</p>
7238 *
7239 * <p>{@code null} will return {@code false}.
7240 * An empty CharSequence(length()=0) will return {@code false}.</p>
7241 *
7242 * <pre>
7243 * StringUtils.isAllLowerCase(null) = false
7244 * StringUtils.isAllLowerCase("") = false
7245 * StringUtils.isAllLowerCase(" ") = false
7246 * StringUtils.isAllLowerCase("abc") = true
7247 * StringUtils.isAllLowerCase("abC") = false
7248 * StringUtils.isAllLowerCase("ab c") = false
7249 * StringUtils.isAllLowerCase("ab1c") = false
7250 * StringUtils.isAllLowerCase("ab/c") = false
7251 * </pre>
7252 *
7253 * @param cs the CharSequence tocheck, may be null
7254 * @return {@code true} if only contains lowercase characters, and isnon-null
7255 * @since 2.5
7256 * @since 3.0 Changed signature from isAllLowerCase(String) toisAllLowerCase(CharSequence)
7257 */
7258 public static boolean isAllLowerCase(final CharSequence cs) {
7259 if (cs == null || isEmpty(cs)) {
7260 return false;
7261 }
7262 final int sz = cs.length();
7263 for (int i = 0; i < sz; i++) {
7264 if(Character.isLowerCase(cs.charAt(i)) == false) {
7265 return false;
7266 }
7267 }
7268 return true;
7269 }
7270
7271 /**
7272 * <p>Checks if the CharSequence contains only uppercasecharacters.</p>
7273 *
7274 * <p>{@code null} will return {@code false}.
7275 * An empty String (length()=0) will return {@code false}.</p>
7276 *
7277 * <pre>
7278 * StringUtils.isAllUpperCase(null) = false
7279 * StringUtils.isAllUpperCase("") = false
7280 * StringUtils.isAllUpperCase(" ") = false
7281 * StringUtils.isAllUpperCase("ABC") = true
7282 * StringUtils.isAllUpperCase("aBC") = false
7283 * StringUtils.isAllUpperCase("A C") = false
7284 * StringUtils.isAllUpperCase("A1C") = false
7285 * StringUtils.isAllUpperCase("A/C") = false
7286 * </pre>
7287 *
7288 * @param cs the CharSequence to check, may be null
7289 * @return {@code true} if only contains uppercase characters, and isnon-null
7290 * @since 2.5
7291 * @since 3.0 Changed signature from isAllUpperCase(String) toisAllUpperCase(CharSequence)
7292 */
7293 public static boolean isAllUpperCase(final CharSequence cs) {
7294 if (cs == null || isEmpty(cs)) {
7295 return false;
7296 }
7297 final int sz = cs.length();
7298 for (int i = 0; i < sz; i++) {
7299 if(Character.isUpperCase(cs.charAt(i)) == false) {
7300 return false;
7301 }
7302 }
7303 return true;
7304 }
7305
7306 /**
7307 * <p>Checks if the CharSequence contains mixed casing of bothuppercase and lowercase characters.</p>
7308 *
7309 * <p>{@code null} will return {@code false}. An empty CharSequence({@code length()=0}) will return
7310 * {@code false}.</p>
7311 *
7312 * <pre>
7313 * StringUtils.isMixedCase(null) = false
7314 * StringUtils.isMixedCase("") = false
7315 * StringUtils.isMixedCase("ABC") = false
7316 * StringUtils.isMixedCase("abc") = false
7317 * StringUtils.isMixedCase("aBc") = true
7318 * StringUtils.isMixedCase("A c") = true
7319 * StringUtils.isMixedCase("A1c") = true
7320 * StringUtils.isMixedCase("a/C") = true
7321 * StringUtils.isMixedCase("aC\t") = true
7322 * </pre>
7323 *
7324 * @param cs the CharSequence to check, may be null
7325 * @return {@code true} if the CharSequence contains both uppercase andlowercase characters
7326 * @since 3.5
7327 */
7328 public static boolean isMixedCase(final CharSequence cs) {
7329 if (isEmpty(cs) || cs.length() == 1) {
7330 return false;
7331 }
7332 boolean containsUppercase = false;
7333 boolean containsLowercase = false;
7334 final int sz = cs.length();
7335 for (int i = 0; i < sz; i++) {
7336 if (containsUppercase &&containsLowercase) {
7337 return true;
7338 } else if(Character.isUpperCase(cs.charAt(i))) {
7339 containsUppercase = true;
7340 } else if(Character.isLowerCase(cs.charAt(i))) {
7341 containsLowercase = true;
7342 }
7343 }
7344 return containsUppercase && containsLowercase;
7345 }
7346
7347 // Defaults
7348 //-----------------------------------------------------------------------
7349 /**
7350 * <p>Returns either the passed in String,
7351 * or if the String is {@code null}, an empty String("").</p>
7352 *
7353 * <pre>
7354 * StringUtils.defaultString(null) = ""
7355 * StringUtils.defaultString("") = ""
7356 * StringUtils.defaultString("bat") = "bat"
7357 * </pre>
7358 *
7359 * @see ObjectUtils#toString(Object)
7360 * @see String#valueOf(Object)
7361 * @param str the String to check,may be null
7362 * @return the passed in String, or the empty String if it
7363 * was {@code null}
7364 */
7365 public static String defaultString(final String str) {
7366 return str == null ? EMPTY : str;
7367 }
7368
7369 /**
7370 * <p>Returns either the passed in String, or if the String is
7371 * {@code null}, the value of {@code defaultStr}.</p>
7372 *
7373 * <pre>
7374 * StringUtils.defaultString(null, "NULL") = "NULL"
7375 * StringUtils.defaultString("", "NULL") = ""
7376 * StringUtils.defaultString("bat", "NULL") ="bat"
7377 * </pre>
7378 *
7379 * @see ObjectUtils#toString(Object,String)
7380 * @see String#valueOf(Object)
7381 * @param str the String to check,may be null
7382 * @param defaultStr the defaultString to return
7383 * if the input is {@code null},may be null
7384 * @return the passed in String, or the default if it was {@code null}
7385 */
7386 public static String defaultString(final String str, final StringdefaultStr) {
7387 return str == null ? defaultStr : str;
7388 }
7389
7390 /**
7391 * <p>Returns either the passed in CharSequence, or if theCharSequence is
7392 * whitespace, empty("") or {@code null}, the value of {@code defaultStr}.</p>
7393 *
7394 * <p>Whitespace is defined by {@linkCharacter#isWhitespace(char)}.</p>
7395 *
7396 * <pre>
7397 * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
7398 * StringUtils.defaultIfBlank("", "NULL") = "NULL"
7399 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
7400 * StringUtils.defaultIfBlank("bat", "NULL") ="bat"
7401 * StringUtils.defaultIfBlank("", null) = null
7402 * </pre>
7403 * @param <T> the specific kind of CharSequence
7404 * @param str the CharSequence to check, may be null
7405 * @param defaultStr the defaultCharSequence to return
7406 * if the input is whitespace,empty ("") or {@code null}, may be null
7407 * @return the passed in CharSequence, or the default
7408 * @see StringUtils#defaultString(String, String)
7409 */
7410 public static <T extends CharSequence> T defaultIfBlank(final Tstr, final T defaultStr) {
7411 return isBlank(str) ? defaultStr : str;
7412 }
7413
7414 /**
7415 * <p>Returns either the passed in CharSequence, or if theCharSequence is
7416 * empty or {@code null}, the value of {@code defaultStr}.</p>
7417 *
7418 * <pre>
7419 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
7420 * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
7421 * StringUtils.defaultIfEmpty(" ", "NULL") = " "
7422 * StringUtils.defaultIfEmpty("bat", "NULL") ="bat"
7423 * StringUtils.defaultIfEmpty("", null) = null
7424 * </pre>
7425 * @param <T> the specific kind of CharSequence
7426 * @param str the CharSequence tocheck, may be null
7427 * @param defaultStr the defaultCharSequence to return
7428 * if the input is empty("") or {@code null}, may be null
7429 * @return the passed in CharSequence, or the default
7430 * @see StringUtils#defaultString(String, String)
7431 */
7432 public static <T extends CharSequence> T defaultIfEmpty(final Tstr, final T defaultStr) {
7433 return isEmpty(str) ? defaultStr : str;
7434 }
7435
7436 // Rotating (circular shift)
7437 //-----------------------------------------------------------------------
7438 /**
7439 * <p>Rotate (circular shift) a String of {@code shift}characters.</p>
7440 * <ul>
7441 * <li>If {@code shift >0}, right circular shift (ex : ABCDEF => FABCDE)</li>
7442 * <li>If {@code shift <0}, left circular shift (ex : ABCDEF => BCDEFA)</li>
7443 * </ul>
7444 *
7445 * <pre>
7446 * StringUtils.rotate(null, *) = null
7447 * StringUtils.rotate("", *) = ""
7448 * StringUtils.rotate("abcdefg", 0) = "abcdefg"
7449 * StringUtils.rotate("abcdefg", 2) = "fgabcde"
7450 * StringUtils.rotate("abcdefg", -2) = "cdefgab"
7451 * StringUtils.rotate("abcdefg", 7) = "abcdefg"
7452 * StringUtils.rotate("abcdefg", -7) = "abcdefg"
7453 * StringUtils.rotate("abcdefg", 9) = "fgabcde"
7454 *StringUtils.rotate("abcdefg", -9) = "cdefgab"
7455 * </pre>
7456 *
7457 * @param str the String torotate, may be null
7458 * @param shift number of time toshift (positive : right shift, negative : left shift)
7459 * @return the rotated String,
7460 * or the original Stringif {@code shift == 0},
7461 * or {@code null} if nullString input
7462 * @since 3.5
7463 */
7464 public static String rotate(final String str, final int shift) {
7465 if (str == null) {
7466 return null;
7467 }
7468
7469 final int strLen = str.length();
7470 if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7471 return str;
7472 }
7473
7474 final StringBuilder builder = new StringBuilder(strLen);
7475 final int offset = - (shift % strLen);
7476 builder.append(substring(str, offset));
7477 builder.append(substring(str, 0, offset));
7478 return builder.toString();
7479 }
7480
7481 // Reversing
7482 //-----------------------------------------------------------------------
7483 /**
7484 * <p>Reverses a String as per {@linkStringBuilder#reverse()}.</p>
7485 *
7486 * <p>A {@code null} String returns {@code null}.</p>
7487 *
7488 * <pre>
7489 * StringUtils.reverse(null) =null
7490 * StringUtils.reverse("") = ""
7491 * StringUtils.reverse("bat") ="tab"
7492 * </pre>
7493 *
7494 * @param str the String toreverse, may be null
7495 * @return the reversed String, {@code null} if null String input
7496 */
7497 public static String reverse(final String str) {
7498 if (str == null) {
7499 return null;
7500 }
7501 return new StringBuilder(str).reverse().toString();
7502 }
7503
7504 /**
7505 * <p>Reverses a String that is delimited by a specificcharacter.</p>
7506 *
7507 * <p>The Strings between the delimiters are not reversed.
7508 * Thus java.lang.String becomes String.lang.java (if the delimiter
7509 * is {@code '.'}).</p>
7510 *
7511 * <pre>
7512 * StringUtils.reverseDelimited(null, *) = null
7513 * StringUtils.reverseDelimited("", *) = ""
7514 * StringUtils.reverseDelimited("a.b.c", 'x') ="a.b.c"
7515 * StringUtils.reverseDelimited("a.b.c", ".") ="c.b.a"
7516 * </pre>
7517 *
7518 * @param str the String toreverse, may be null
7519 * @param separatorChar theseparator character to use
7520 * @return the reversed String, {@code null} if null String input
7521 * @since 2.0
7522 */
7523 public static String reverseDelimited(final String str, final charseparatorChar) {
7524 if (str == null) {
7525 return null;
7526 }
7527 // could implement manually, but simple way is to reuse other,
7528 // probably slower, methods.
7529 final String[] strs = split(str, separatorChar);
7530 ArrayUtils.reverse(strs);
7531 return join(strs, separatorChar);
7532 }
7533
7534 // Abbreviating
7535 //-----------------------------------------------------------------------
7536 /**
7537 * <p>Abbreviates a String using ellipses. This will turn
7538 * "Now is the time for all good men" into "Now is thetime for..."</p>
7539 *
7540 * <p>Specifically:</p>
7541 * <ul>
7542 * <li>If the number ofcharacters in {@code str} is less than or equal to
7543 * {@code maxWidth}, return{@code str}.</li>
7544 * <li>Else abbreviate itto {@code (substring(str, 0, max-3) + "...")}.</li>
7545 * <li>If {@code maxWidth}is less than {@code 4}, throw an
7546 * {@codeIllegalArgumentException}.</li>
7547 * <li>In no case will itreturn a String of length greater than
7548 * {@codemaxWidth}.</li>
7549 * </ul>
7550 *
7551 * <pre>
7552 * StringUtils.abbreviate(null, *) = null
7553 * StringUtils.abbreviate("", 4) = ""
7554 * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7555 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7556 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7557 * StringUtils.abbreviate("abcdefg", 4) = "a..."
7558 * StringUtils.abbreviate("abcdefg", 3) =IllegalArgumentException
7559 * </pre>
7560 *
7561 * @param str the String to check,may be null
7562 * @param maxWidth maximum lengthof result String, must be at least 4
7563 * @return abbreviated String, {@code null} if null String input
7564 * @throws IllegalArgumentException if the width is too small
7565 * @since 2.0
7566 */
7567 public static String abbreviate(final String str, final int maxWidth) {
7568 final String defaultAbbrevMarker = "...";
7569 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
7570 }
7571
7572 /**
7573 * <p>Abbreviates a Stringusing ellipses. This will turn
7574 * "Now is the time for all good men" into "...is the timefor..."</p>
7575 *
7576 * <p>Works like {@code abbreviate(String, int)}, but allows you tospecify
7577 * a "left edge" offset. Note that this left edge is not necessarily going to
7578 * be the leftmost character in the result, or the first characterfollowing the
7579 * ellipses, but it will appear somewhere in the result.
7580 *
7581 * <p>In no case will itreturn a String of length greater than
7582 * {@code maxWidth}.</p>
7583 *
7584 * <pre>
7585 * StringUtils.abbreviate(null, *, *) = null
7586 * StringUtils.abbreviate("", 0, 4) = ""
7587 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) ="abcdefg..."
7588 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
7589 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
7590 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
7591 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
7592 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
7593 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
7594 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) ="...ijklmno"
7595 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) ="...ijklmno"
7596 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
7597 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
7598 * </pre>
7599 *
7600 * @param str the String to check,may be null
7601 * @param offset left edge ofsource String
7602 * @param maxWidth maximum lengthof result String, must be at least 4
7603 * @return abbreviated String, {@code null} if null String input
7604 * @throws IllegalArgumentException if the width is too small
7605 * @since 2.0
7606 */
7607 public static String abbreviate(final String str, final int offset,final int maxWidth) {
7608 final String defaultAbbrevMarker = "...";
7609 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
7610 }
7611
7612 /**
7613 * <p>Abbreviates a String using another given String asreplacement marker. This will turn
7614 * "Now is the time for all good men" into "Now is thetime for..." if "..." was defined
7615 * as the replacement marker.</p>
7616 *
7617 * <p>Specifically:</p>
7618 * <ul>
7619 * <li>If the number ofcharacters in {@code str} is less than or equal to
7620 * {@code maxWidth}, return{@code str}.</li>
7621 * <li>Else abbreviate itto {@code (substring(str, 0, max-abbrevMarker.length) +abbrevMarker)}.</li>
7622 * <li>If {@code maxWidth}is less than {@code abbrevMarker.length + 1}, throw an
7623 * {@codeIllegalArgumentException}.</li>
7624 * <li>In no case will itreturn a String of length greater than
7625 * {@codemaxWidth}.</li>
7626 * </ul>
7627 *
7628 * <pre>
7629 * StringUtils.abbreviate(null, "...", *) = null
7630 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg"
7631 * StringUtils.abbreviate("", "...", 4) = ""
7632 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd."
7633 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg"
7634 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg"
7635 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.."
7636 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.."
7637 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException
7638 * StringUtils.abbreviate("abcdefg", "...", 3) =IllegalArgumentException
7639 * </pre>
7640 *
7641 * @param str the String to check,may be null
7642 * @param abbrevMarker the Stringused as replacement marker
7643 * @param maxWidth maximum lengthof result String, must be at least {@code abbrevMarker.length + 1}
7644 * @return abbreviated String, {@code null} if null String input
7645 * @throws IllegalArgumentException if the width is too small
7646 * @since 3.6
7647 */
7648 public static String abbreviate(final String str, final StringabbrevMarker, final int maxWidth) {
7649 return abbreviate(str, abbrevMarker, 0, maxWidth);
7650 }
7651
7652 /**
7653 * <p>Abbreviates a String using a given replacement marker. Thiswill turn
7654 * "Now is the time for all good men" into "...is the timefor..." if "..." was defined
7655 * as the replacement marker.</p>
7656 *
7657 * <p>Works like {@code abbreviate(String, String, int)}, butallows you to specify
7658 * a "left edge" offset. Note that this left edge is not necessarily going to
7659 * be the leftmost character in the result, or the first characterfollowing the
7660 * replacement marker, but it will appear somewhere in the result.
7661 *
7662 * <p>In no case will it return a String of length greater than{@code maxWidth}.</p>
7663 *
7664 * <pre>
7665 * StringUtils.abbreviate(null, null, *, *) = null
7666 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno"
7667 * StringUtils.abbreviate("", "...", 0, 4) = ""
7668 * StringUtils.abbreviate("abcdefghijklmno", "---",-1, 10) = "abcdefg---"
7669 * StringUtils.abbreviate("abcdefghijklmno", ",", 0,10) = "abcdefghi,"
7670 * StringUtils.abbreviate("abcdefghijklmno", ",", 1,10) = "abcdefghi,"
7671 * StringUtils.abbreviate("abcdefghijklmno", ",", 2,10) = "abcdefghi,"
7672 * StringUtils.abbreviate("abcdefghijklmno", "::", 4,10) = "::efghij::"
7673 * StringUtils.abbreviate("abcdefghijklmno", "...",6, 10) = "...ghij..."
7674 * StringUtils.abbreviate("abcdefghijklmno", "*", 9,10) = "*ghijklmno"
7675 * StringUtils.abbreviate("abcdefghijklmno", "'", 10,10) = "'ghijklmno"
7676 * StringUtils.abbreviate("abcdefghijklmno", "!", 12,10) = "!ghijklmno"
7677 * StringUtils.abbreviate("abcdefghij", "abra", 0,4) = IllegalArgumentException
7678 * StringUtils.abbreviate("abcdefghij", "...", 5,6) = IllegalArgumentException
7679 * </pre>
7680 *
7681 * @param str the String to check,may be null
7682 * @param abbrevMarker the Stringused as replacement marker
7683 * @param offset left edge ofsource String
7684 * @param maxWidth maximum lengthof result String, must be at least 4
7685 * @return abbreviated String, {@code null} if null String input
7686 * @throws IllegalArgumentException if the width is too small
7687 * @since 3.6
7688 */
7689 public static String abbreviate(final String str, final StringabbrevMarker, int offset, final int maxWidth) {
7690 if (isEmpty(str) ||isEmpty(abbrevMarker)) {
7691 return str;
7692 }
7693
7694 final int abbrevMarkerLength = abbrevMarker.length();
7695 final int minAbbrevWidth = abbrevMarkerLength + 1;
7696 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength+ 1;
7697
7698 if (maxWidth < minAbbrevWidth) {
7699 throw newIllegalArgumentException(String.format("Minimum abbreviation width is%d", minAbbrevWidth));
7700 }
7701 if (str.length() <= maxWidth) {
7702 return str;
7703 }
7704 if (offset > str.length()) {
7705 offset = str.length();
7706 }
7707 if (str.length() - offset < maxWidth - abbrevMarkerLength) {
7708 offset = str.length() - (maxWidth -abbrevMarkerLength);
7709 }
7710 if (offset <= abbrevMarkerLength+1) {
7711 return str.substring(0, maxWidth -abbrevMarkerLength) + abbrevMarker;
7712 }
7713 if (maxWidth < minAbbrevWidthOffset) {
7714 throw newIllegalArgumentException(String.format("Minimum abbreviation width withoffset is %d", minAbbrevWidthOffset));
7715 }
7716 if (offset + maxWidth - abbrevMarkerLength < str.length()) {
7717 return abbrevMarker +abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
7718 }
7719 return abbrevMarker + str.substring(str.length() - (maxWidth -abbrevMarkerLength));
7720 }
7721
7722 /**
7723 * <p>Abbreviates a String to the length passed, replacing themiddle characters with the supplied
7724 * replacement String.</p>
7725 *
7726 * <p>This abbreviation only occurs if the following criteria ismet:</p>
7727 * <ul>
7728 * <li>Neither the String forabbreviation nor the replacement String are null or empty </li>
7729 * <li>The length to truncate to is less than the length of thesupplied String</li>
7730 * <li>The length to truncate to is greater than 0</li>
7731 * <li>The abbreviated String will have enough room for the lengthsupplied replacement String
7732 * and the first and last characters of the supplied String forabbreviation</li>
7733 * </ul>
7734 * <p>Otherwise, the returned String will be the same as thesupplied String for abbreviation.
7735 * </p>
7736 *
7737 * <pre>
7738 * StringUtils.abbreviateMiddle(null, null, 0) = null
7739 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
7740 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
7741 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
7742 * StringUtils.abbreviateMiddle("abcdef", ".",4) = "ab.f"
7743 * </pre>
7744 *
7745 * @param str the String toabbreviate, may be null
7746 * @param middle the String to replace the middle characters with, may benull
7747 * @param length the length to abbreviate {@code str} to.
7748 * @return the abbreviated String if the above criteria is met, or theoriginal String supplied for abbreviation.
7749 * @since 2.5
7750 */
7751 public static String abbreviateMiddle(final String str, final Stringmiddle, final int length) {
7752 if (isEmpty(str) || isEmpty(middle)) {
7753 return str;
7754 }
7755
7756 if (length >= str.length() || length < middle.length()+2) {
7757 return str;
7758 }
7759
7760 final int targetSting = length-middle.length();
7761 final int startOffset = targetSting/2+targetSting%2;
7762 final int endOffset = str.length()-targetSting/2;
7763
7764 final StringBuilder builder = new StringBuilder(length);
7765 builder.append(str.substring(0,startOffset));
7766 builder.append(middle);
7767 builder.append(str.substring(endOffset));
7768
7769 return builder.toString();
7770 }
7771
7772 // Difference
7773 //-----------------------------------------------------------------------
7774 /**
7775 * <p>Compares two Strings, and returns the portion where theydiffer.
7776 * More precisely, return the remainder of the second String,
7777 * starting from where it's different from the first. This means that
7778 * the difference between "abc" and "ab" is the emptyString and not "c". </p>
7779 *
7780 * <p>For example,
7781 * {@code difference("i am a machine", "i am arobot") -> "robot"}.</p>
7782 *
7783 * <pre>
7784 * StringUtils.difference(null, null) = null
7785 * StringUtils.difference("", "") = ""
7786 * StringUtils.difference("", "abc") ="abc"
7787 * StringUtils.difference("abc", "") = ""
7788 * StringUtils.difference("abc", "abc") =""
7789 * StringUtils.difference("abc", "ab") = ""
7790 * StringUtils.difference("ab", "abxyz") ="xyz"
7791 * StringUtils.difference("abcde", "abxyz") ="xyz"
7792 * StringUtils.difference("abcde", "xyz") ="xyz"
7793 * </pre>
7794 *
7795 * @param str1 the first String,may be null
7796 * @param str2 the second String,may be null
7797 * @return the portion of str2 where it differs from str1; returns the
7798 * empty String if they are equal
7799 * @see #indexOfDifference(CharSequence,CharSequence)
7800 * @since 2.0
7801 */
7802 public static String difference(final String str1, final String str2) {
7803 if (str1 == null) {
7804 return str2;
7805 }
7806 if (str2 == null) {
7807 return str1;
7808 }
7809 final int at = indexOfDifference(str1, str2);
7810 if (at == INDEX_NOT_FOUND) {
7811 return EMPTY;
7812 }
7813 return str2.substring(at);
7814 }
7815
7816 /**
7817 * <p>Compares two CharSequences, and returns the index at whichthe
7818 * CharSequences begin to differ.</p>
7819 *
7820 * <p>For example,
7821 * {@code indexOfDifference("i am a machine", "i am arobot") -> 7}</p>
7822 *
7823 * <pre>
7824 * StringUtils.indexOfDifference(null, null) = -1
7825 * StringUtils.indexOfDifference("", "") = -1
7826 * StringUtils.indexOfDifference("", "abc") = 0
7827 * StringUtils.indexOfDifference("abc", "") = 0
7828 * StringUtils.indexOfDifference("abc", "abc") = -1
7829 * StringUtils.indexOfDifference("ab", "abxyz") = 2
7830 * StringUtils.indexOfDifference("abcde", "abxyz") =2
7831 * StringUtils.indexOfDifference("abcde", "xyz") = 0
7832 * </pre>
7833 *
7834 * @param cs1 the firstCharSequence, may be null
7835 * @param cs2 the secondCharSequence, may be null
7836 * @return the index where cs1 and cs2 begin to differ; -1 if they areequal
7837 * @since 2.0
7838 * @since 3.0 Changed signature from indexOfDifference(String, String) to
7839 * indexOfDifference(CharSequence, CharSequence)
7840 */
7841 public static int indexOfDifference(final CharSequence cs1, finalCharSequence cs2) {
7842 if (cs1 == cs2) {
7843 return INDEX_NOT_FOUND;
7844 }
7845 if (cs1 == null || cs2 == null) {
7846 return 0;
7847 }
7848 int i;
7849 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
7850 if (cs1.charAt(i) != cs2.charAt(i)){
7851 break;
7852 }
7853 }
7854 if (i < cs2.length() || i < cs1.length()) {
7855 return i;
7856 }
7857 return INDEX_NOT_FOUND;
7858 }
7859
7860 /**
7861 * <p>Compares all CharSequences in an array and returns the indexat which the
7862 * CharSequences begin to differ.</p>
7863 *
7864 * <p>For example,
7865 * <code>indexOfDifference(new String[] {"i am amachine", "i am a robot"}) -> 7</code></p>
7866 *
7867 * <pre>
7868 * StringUtils.indexOfDifference(null) = -1
7869 * StringUtils.indexOfDifference(new String[] {}) = -1
7870 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
7871 * StringUtils.indexOfDifference(new String[] {null, null}) = -1
7872 * StringUtils.indexOfDifference(new String[] {"",""}) = -1
7873 * StringUtils.indexOfDifference(new String[] {"", null}) = 0
7874 * StringUtils.indexOfDifference(new String[] {"abc", null,null}) = 0
7875 * StringUtils.indexOfDifference(new String[] {null, null,"abc"}) = 0
7876 * StringUtils.indexOfDifference(new String[] {"","abc"}) = 0
7877 * StringUtils.indexOfDifference(new String[] {"abc",""}) = 0
7878 * StringUtils.indexOfDifference(new String[] {"abc","abc"}) = -1
7879 * StringUtils.indexOfDifference(new String[] {"abc","a"}) = 1
7880 * StringUtils.indexOfDifference(new String[] {"ab","abxyz"}) = 2
7881 * StringUtils.indexOfDifference(new String[] {"abcde","abxyz"}) = 2
7882 * StringUtils.indexOfDifference(new String[] {"abcde","xyz"}) = 0
7883 * StringUtils.indexOfDifference(new String[] {"xyz","abcde"}) = 0
7884 * StringUtils.indexOfDifference(new String[] {"i am amachine", "i am a robot"}) = 7
7885 * </pre>
7886 *
7887 * @param css array ofCharSequences, entries may be null
7888 * @return the index where the strings begin to differ; -1 if they areall equal
7889 * @since 2.4
7890 * @since 3.0 Changed signature from indexOfDifference(String...) toindexOfDifference(CharSequence...)
7891 */
7892 public static int indexOfDifference(final CharSequence... css) {
7893 if (css == null || css.length <= 1) {
7894 return INDEX_NOT_FOUND;
7895 }
7896 boolean anyStringNull = false;
7897 boolean allStringsNull = true;
7898 final int arrayLen = css.length;
7899 int shortestStrLen = Integer.MAX_VALUE;
7900 int longestStrLen = 0;
7901
7902 // find the min and max string lengths; this avoids checking to make
7903 // sure we are not exceeding the length of the string each time through
7904 // the bottom loop.
7905 for (CharSequence cs : css) {
7906 if (cs == null) {
7907 anyStringNull = true;
7908 shortestStrLen = 0;
7909 } else {
7910 allStringsNull = false;
7911 shortestStrLen =Math.min(cs.length(), shortestStrLen);
7912 longestStrLen =Math.max(cs.length(), longestStrLen);
7913 }
7914 }
7915
7916 // handle lists containing all nulls or all empty strings
7917 if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
7918 return INDEX_NOT_FOUND;
7919 }
7920
7921 // handle lists containing some nulls or some empty strings
7922 if (shortestStrLen == 0) {
7923 return 0;
7924 }
7925
7926 // find the position with the first difference across all strings
7927 int firstDiff = -1;
7928 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
7929 final char comparisonChar =css[0].charAt(stringPos);
7930 for (int arrayPos = 1; arrayPos< arrayLen; arrayPos++) {
7931 if(css[arrayPos].charAt(stringPos) != comparisonChar) {
7932 firstDiff = stringPos;
7933 break;
7934 }
7935 }
7936 if (firstDiff != -1) {
7937 break;
7938 }
7939 }
7940
7941 if (firstDiff == -1 && shortestStrLen != longestStrLen) {
7942 // we compared all of thecharacters up to the length of the
7943 // shortest string and didn't finda match, but the string lengths
7944 // vary, so return the length ofthe shortest string.
7945 return shortestStrLen;
7946 }
7947 return firstDiff;
7948 }
7949
7950 /**
7951 * <p>Compares all Strings in an array and returns the initialsequence of
7952 * characters that is common to all of them.</p>
7953 *
7954 * <p>For example,
7955 * <code>getCommonPrefix(new String[] {"i am a machine","i am a robot"}) -> "i am a "</code></p>
7956 *
7957 * <pre>
7958 * StringUtils.getCommonPrefix(null) = ""
7959 * StringUtils.getCommonPrefix(new String[] {}) = ""
7960 * StringUtils.getCommonPrefix(new String[] {"abc"}) ="abc"
7961 * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
7962 * StringUtils.getCommonPrefix(new String[] {"", ""})= ""
7963 * StringUtils.getCommonPrefix(new String[] {"", null}) =""
7964 * StringUtils.getCommonPrefix(new String[] {"abc", null,null}) = ""
7965 * StringUtils.getCommonPrefix(new String[] {null, null,"abc"}) = ""
7966 * StringUtils.getCommonPrefix(new String[] {"","abc"}) = ""
7967 * StringUtils.getCommonPrefix(new String[] {"abc",""}) = ""
7968 * StringUtils.getCommonPrefix(new String[] {"abc","abc"}) = "abc"
7969 * StringUtils.getCommonPrefix(new String[] {"abc","a"}) = "a"
7970 * StringUtils.getCommonPrefix(new String[] {"ab","abxyz"}) = "ab"
7971 * StringUtils.getCommonPrefix(new String[] {"abcde","abxyz"}) = "ab"
7972 * StringUtils.getCommonPrefix(new String[] {"abcde","xyz"}) = ""
7973 * StringUtils.getCommonPrefix(new String[] {"xyz","abcde"}) = ""
7974 * StringUtils.getCommonPrefix(new String[] {"i am a machine","i am a robot"}) = "i am a "
7975 * </pre>
7976 *
7977 * @param strs array of Stringobjects, entries may be null
7978 * @return the initial sequence of characters that are common to all Strings
7979 * in the array; empty String if the array is null, the elements are allnull
7980 * or if there is no common prefix.
7981 * @since 2.4
7982 */
7983 public static String getCommonPrefix(final String... strs) {
7984 if (strs == null || strs.length == 0) {
7985 return EMPTY;
7986 }
7987 final int smallestIndexOfDiff = indexOfDifference(strs);
7988 if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
7989 // all strings were identical
7990 if (strs[0] == null) {
7991 return EMPTY;
7992 }
7993 return strs[0];
7994 } else if (smallestIndexOfDiff == 0) {
7995 // there were no common initialcharacters
7996 return EMPTY;
7997 } else {
7998 // we found a common initialcharacter sequence
7999 return strs[0].substring(0,smallestIndexOfDiff);
8000 }
8001 }
8002
8003 // Misc
8004 //-----------------------------------------------------------------------
8005 /**
8006 * <p>Find the Levenshtein distance between two Strings.</p>
8007 *
8008 * <p>This is the number of changes needed to change one Stringinto
8009 * another, where each change is a single character modification(deletion,
8010 * insertion or substitution).</p>
8011 *
8012 * <p>The implementation uses a single-dimensional array of lengths.length() + 1. See
8013 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
8014 *http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a>for details.</p>
8015 *
8016 * <pre>
8017 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
8018 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
8019 * StringUtils.getLevenshteinDistance("","") = 0
8020 * StringUtils.getLevenshteinDistance("","a") = 1
8021 * StringUtils.getLevenshteinDistance("aaapppp","") = 7
8022 * StringUtils.getLevenshteinDistance("frog","fog") = 1
8023 * StringUtils.getLevenshteinDistance("fly","ant") = 3
8024 * StringUtils.getLevenshteinDistance("elephant","hippo") = 7
8025 * StringUtils.getLevenshteinDistance("hippo","elephant") = 7
8026 * StringUtils.getLevenshteinDistance("hippo","zzzzzzzz") = 8
8027 * StringUtils.getLevenshteinDistance("hello","hallo") = 1
8028 * </pre>
8029 *
8030 * @param s the first String, mustnot be null
8031 * @param t the second String,must not be null
8032 * @return result distance
8033 * @throws IllegalArgumentException if either String input {@code null}
8034 * @since 3.0 Changed signature from getLevenshteinDistance(String,String) to
8035 * getLevenshteinDistance(CharSequence, CharSequence)
8036 * @deprecated as of 3.6, use commons-text
8037 * <ahref="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8038 * LevenshteinDistance</a> instead
8039 */
8040 @Deprecated
8041 public static int getLevenshteinDistance(CharSequence s, CharSequence t){
8042 if (s == null || t == null) {
8043 throw newIllegalArgumentException("Strings must not be null");
8044 }
8045
8046 int n = s.length();
8047 int m = t.length();
8048
8049 if (n == 0) {
8050 return m;
8051 } else if (m == 0) {
8052 return n;
8053 }
8054
8055 if (n > m) {
8056 // swap the input strings to consumeless memory
8057 final CharSequence tmp = s;
8058 s = t;
8059 t = tmp;
8060 n = m;
8061 m = t.length();
8062 }
8063
8064 final int p[] = new int[n + 1];
8065 // indexes into strings s and t
8066 int i; // iterates through s
8067 int j; // iterates through t
8068 int upper_left;
8069 int upper;
8070
8071 char t_j; // jth character of t
8072 int cost;
8073
8074 for (i = 0; i <= n; i++) {
8075 p[i] = i;
8076 }
8077
8078 for (j = 1; j <= m; j++) {
8079 upper_left = p[0];
8080 t_j = t.charAt(j - 1);
8081 p[0] = j;
8082
8083 for (i = 1; i <= n; i++) {
8084 upper = p[i];
8085 cost = s.charAt(i - 1) == t_j ?0 : 1;
8086 // minimum of cell to theleft+1, to the top+1, diagonally left and up +cost
8087 p[i] = Math.min(Math.min(p[i -1] + 1, p[i] + 1), upper_left + cost);
8088 upper_left = upper;
8089 }
8090 }
8091
8092 return p[n];
8093 }
8094
8095 /**
8096 * <p>Find the Levenshtein distance between two Strings if it'sless than or equal to a given
8097 * threshold.</p>
8098 *
8099 * <p>This is the number of changes needed to change one Stringinto
8100 * another, where each change is a single character modification(deletion,
8101 * insertion or substitution).</p>
8102 *
8103 * <p>This implementation follows from Algorithms on Strings, Treesand Sequences by Dan Gusfield
8104 * and Chas Emerick's implementation of the Levenshtein distancealgorithm from
8105 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
8106 *
8107 * <pre>
8108 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
8109 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
8110 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
8111 * StringUtils.getLevenshteinDistance("","", 0) = 0
8112 * StringUtils.getLevenshteinDistance("aaapppp", "",8) = 7
8113 * StringUtils.getLevenshteinDistance("aaapppp", "",7) = 7
8114 * StringUtils.getLevenshteinDistance("aaapppp", "",6)) = -1
8115 * StringUtils.getLevenshteinDistance("elephant","hippo", 7) = 7
8116 * StringUtils.getLevenshteinDistance("elephant","hippo", 6) = -1
8117 * StringUtils.getLevenshteinDistance("hippo","elephant", 7) = 7
8118 * StringUtils.getLevenshteinDistance("hippo","elephant", 6) = -1
8119 * </pre>
8120 *
8121 * @param s the first String, must not be null
8122 * @param t the second String,must not be null
8123 * @param threshold the target threshold, must not be negative
8124 * @return result distance, or {@code -1} if the distance would be greaterthan the threshold
8125 * @throws IllegalArgumentException if either String input {@code null}or negative threshold
8126 * @deprecated as of 3.6, use commons-text
8127 * <ahref="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8128 * LevenshteinDistance</a> instead
8129 */
8130 @Deprecated
8131 public static int getLevenshteinDistance(CharSequence s, CharSequence t,final int threshold) {
8132 if (s == null || t == null) {
8133 throw newIllegalArgumentException("Strings must not be null");
8134 }
8135 if (threshold < 0) {
8136 throw newIllegalArgumentException("Threshold must not be negative");
8137 }
8138
8139 /*
8140 This implementation only computes the distance if it's less than orequal to the
8141 threshold value, returning -1 if it's greater. The advantage is performance: unbounded
8142 distance is O(nm), but a bound of k allows us to reduce it to O(km) timeby only
8143 computing a diagonal stripe of width 2k + 1 of the cost table.
8144 It is also possible to use this to compute the unbounded Levenshteindistance by starting
8145 the threshold at 1 and doubling each time until the distance is found;this is O(dm), where
8146 d is the distance.
8147
8148 One subtlety comes from needing to ignore entries on the border of ourstripe
8149 eg.
8150 p[] = |#|#|#|*
8151 d[] = *|#|#|#|
8152 We must ignore the entry to the left of the leftmost member
8153 We must ignore the entry above the rightmost member
8154
8155 Another subtlety comes from our stripe running off the matrix if thestrings aren't
8156 of the same size. Since string sis always swapped to be the shorter of the two,
8157 the stripe will always run off to the upper right instead of the lowerleft of the matrix.
8158
8159 As a concrete example, suppose s is of length 5, t is of length 7, andour threshold is 1.
8160 In this case we're going to walk a stripe of length 3. The matrix would look like so:
8161
8162 1 2 3 4 5
8163 1 |#|#| | | |
8164 2 |#|#|#| | |
8165 3 | |#|#|#| |
8166 4 | | |#|#|#|
8167 5 | | | |#|#|
8168 6 | | | | |#|
8169 7 | | | | | |
8170
8171 Note how the stripe leads off the table as there is no possible way toturn a string of length 5
8172 into one of length 7 in edit distance of 1.
8173
8174 Additionally, this implementation decreases memory usage by using two
8175 single-dimensional arrays and swapping them back and forth instead ofallocating
8176 an entire n by m matrix. Thisrequires a few minor changes, such as immediately returning
8177 when it's detected that the stripe has run off the matrix and initiallyfilling the arrays with
8178 large values so that entries we don't compute are ignored.
8179
8180 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for somediscussion.
8181 */
8182
8183 int n = s.length(); // length of s
8184 int m = t.length(); // length of t
8185
8186 // if one string is empty, the edit distance is necessarily the lengthof the other
8187 if (n == 0) {
8188 return m <= threshold ? m : -1;
8189 } else if (m == 0) {
8190 return n <= threshold ? n : -1;
8191 } else if (Math.abs(n - m) > threshold) {
8192 // no need to calculate thedistance if the length difference is greater than the threshold
8193 return -1;
8194 }
8195
8196 if (n > m) {
8197 // swap the two strings to consumeless memory
8198 final CharSequence tmp = s;
8199 s = t;
8200 t = tmp;
8201 n = m;
8202 m = t.length();
8203 }
8204
8205 int p[] = new int[n + 1]; // 'previous' cost array, horizontally
8206 int d[] = new int[n + 1]; // cost array, horizontally
8207 int _d[]; // placeholder to assist in swapping p and d
8208
8209 // fill in starting table values
8210 final int boundary = Math.min(n, threshold) + 1;
8211 for (int i = 0; i < boundary; i++) {
8212 p[i] = i;
8213 }
8214 // these fills ensure that the value above the rightmost entry of our
8215 // stripe will be ignored in following loop iterations
8216 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
8217 Arrays.fill(d, Integer.MAX_VALUE);
8218
8219 // iterates through t
8220 for (int j = 1; j <= m; j++) {
8221 final char t_j = t.charAt(j - 1);// jth character of t
8222 d[0] = j;
8223
8224 // compute stripe indices,constrain to array size
8225 final int min = Math.max(1, j -threshold);
8226 final int max = j >Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
8227
8228 // the stripe may lead off of thetable if s and t are of different sizes
8229 if (min > max) {
8230 return -1;
8231 }
8232
8233 // ignore entry left of leftmost
8234 if (min > 1) {
8235 d[min - 1] = Integer.MAX_VALUE;
8236 }
8237
8238 // iterates through [min, max] in s
8239 for (int i = min; i <= max; i++){
8240 if (s.charAt(i - 1) == t_j) {
8241 // diagonally left and up
8242 d[i] = p[i - 1];
8243 } else {
8244 // 1 + minimum of cell tothe left, to the top, diagonally left and up
8245 d[i] = 1 + Math.min(Math.min(d[i- 1], p[i]), p[i - 1]);
8246 }
8247 }
8248
8249 // copy current distance counts to'previous row' distance counts
8250 _d = p;
8251 p = d;
8252 d = _d;
8253 }
8254
8255 // if p[n] is greater than the threshold, there's no guarantee on itbeing the correct
8256 // distance
8257 if (p[n] <= threshold) {
8258 return p[n];
8259 }
8260 return -1;
8261 }
8262
8263 /**
8264 * <p>Find the Jaro Winkler Distance which indicates the similarityscore between two Strings.</p>
8265 *
8266 * <p>The Jaro measure is the weighted sum of percentage of matchedcharacters from each file and transposed characters.
8267 * Winkler increased this measure for matching initialcharacters.</p>
8268 *
8269 * <p>This implementation is based on the Jaro Winkler similarityalgorithm
8270 * from <ahref="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
8271 *
8272 * <pre>
8273 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException
8274 * StringUtils.getJaroWinklerDistance("","") = 0.0
8275 * StringUtils.getJaroWinklerDistance("","a") = 0.0
8276 * StringUtils.getJaroWinklerDistance("aaapppp","") = 0.0
8277 * StringUtils.getJaroWinklerDistance("frog","fog") = 0.93
8278 * StringUtils.getJaroWinklerDistance("fly","ant") = 0.0
8279 * StringUtils.getJaroWinklerDistance("elephant","hippo") = 0.44
8280 * StringUtils.getJaroWinklerDistance("hippo","elephant") = 0.44
8281 * StringUtils.getJaroWinklerDistance("hippo","zzzzzzzz") = 0.0
8282 * StringUtils.getJaroWinklerDistance("hello","hallo") = 0.88
8283 * StringUtils.getJaroWinklerDistance("ABC Corporation","ABC Corp") = 0.93
8284 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc","D & H Enterprises, Inc.") = 0.95
8285 * StringUtils.getJaroWinklerDistance("My Gym Children's FitnessCenter", "My Gym. Childrens Fitness") = 0.92
8286 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA","PENNCISYLVNIA") = 0.88
8287 * </pre>
8288 *
8289 * @param first the first String, must not be null
8290 * @param second the second String, must not be null
8291 * @return result distance
8292 * @throws IllegalArgumentException if either String input {@code null}
8293 * @since 3.3
8294 * @deprecated as of 3.6, use commons-text
8295 * <ahref="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
8296 * JaroWinklerDistance</a> instead
8297 */
8298 @Deprecated
8299 public static double getJaroWinklerDistance(final CharSequence first,final CharSequence second) {
8300 final double DEFAULT_SCALING_FACTOR = 0.1;
8301
8302 if (first == null || second == null) {
8303 throw newIllegalArgumentException("Strings must not be null");
8304 }
8305
8306 final int[] mtp = matches(first, second);
8307 final double m = mtp[0];
8308 if (m == 0) {
8309 return 0D;
8310 }
8311 final double j = ((m / first.length() + m / second.length() + (m -mtp[1]) / m)) / 3;
8312 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR,1D / mtp[3]) * mtp[2] * (1D - j);
8313 return Math.round(jw * 100.0D) / 100.0D;
8314 }
8315
8316 private static int[] matches(final CharSequence first, finalCharSequence second) {
8317 CharSequence max, min;
8318 if (first.length() > second.length()) {
8319 max = first;
8320 min = second;
8321 } else {
8322 max = second;
8323 min = first;
8324 }
8325 final int range = Math.max(max.length() / 2 - 1, 0);
8326 final int[] matchIndexes = new int[min.length()];
8327 Arrays.fill(matchIndexes, -1);
8328 final boolean[] matchFlags = new boolean[max.length()];
8329 int matches = 0;
8330 for (int mi = 0; mi < min.length(); mi++) {
8331 final char c1 = min.charAt(mi);
8332 for (int xi = Math.max(mi - range,0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
8333 if (!matchFlags[xi] &&c1 == max.charAt(xi)) {
8334 matchIndexes[mi] = xi;
8335 matchFlags[xi] = true;
8336 matches++;
8337 break;
8338 }
8339 }
8340 }
8341 final char[] ms1 = new char[matches];
8342 final char[] ms2 = new char[matches];
8343 for (int i = 0, si = 0; i < min.length(); i++) {
8344 if (matchIndexes[i] != -1) {
8345 ms1[si] = min.charAt(i);
8346 si++;
8347 }
8348 }
8349 for (int i = 0, si = 0; i < max.length(); i++) {
8350 if (matchFlags[i]) {
8351 ms2[si] = max.charAt(i);
8352 si++;
8353 }
8354 }
8355 int transpositions = 0;
8356 for (int mi = 0; mi < ms1.length; mi++) {
8357 if (ms1[mi] != ms2[mi]) {
8358 transpositions++;
8359 }
8360 }
8361 int prefix = 0;
8362 for (int mi = 0; mi < min.length(); mi++) {
8363 if (first.charAt(mi) ==second.charAt(mi)) {
8364 prefix++;
8365 } else {
8366 break;
8367 }
8368 }
8369 return new int[] { matches, transpositions / 2, prefix, max.length() };
8370 }
8371
8372 /**
8373 * <p>Find the Fuzzy Distance which indicates the similarity scorebetween two Strings.</p>
8374 *
8375 * <p>This string matching algorithm is similar to the algorithmsof editors such as Sublime Text,
8376 * TextMate, Atom and others. One point is given for every matchedcharacter. Subsequent
8377 * matches yield two bonus points. A higher score indicates a highersimilarity.</p>
8378 *
8379 * <pre>
8380 * StringUtils.getFuzzyDistance(null, null, null) =IllegalArgumentException
8381 * StringUtils.getFuzzyDistance("", "",Locale.ENGLISH) = 0
8382 * StringUtils.getFuzzyDistance("Workshop", "b",Locale.ENGLISH) = 0
8383 * StringUtils.getFuzzyDistance("Room", "o",Locale.ENGLISH) =1
8384 * StringUtils.getFuzzyDistance("Workshop", "w",Locale.ENGLISH) = 1
8385 * StringUtils.getFuzzyDistance("Workshop", "ws",Locale.ENGLISH) = 2
8386 * StringUtils.getFuzzyDistance("Workshop", "wo",Locale.ENGLISH) = 4
8387 * StringUtils.getFuzzyDistance("Apache Software Foundation","asf", Locale.ENGLISH) = 3
8388 * </pre>
8389 *
8390 * @param term a full term that should be matched against, must not benull
8391 * @param query the query that will be matched against a term, must notbe null
8392 * @param locale This string matching logic is case insensitive. A localeis necessary to normalize
8393 * both Strings to lower case.
8394 * @return result score
8395 * @throws IllegalArgumentException if either String input {@code null}or Locale input {@code null}
8396 * @since 3.4
8397 * @deprecated as of 3.6, use commons-text
8398 * <ahref="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
8399 * FuzzyScore</a> instead
8400 */
8401 @Deprecated
8402 public static int getFuzzyDistance(final CharSequence term, finalCharSequence query, final Locale locale) {
8403 if (term == null || query == null) {
8404 throw newIllegalArgumentException("Strings must not be null");
8405 } else if (locale == null) {
8406 throw newIllegalArgumentException("Locale must not be null");
8407 }
8408
8409 // fuzzy logic is case insensitive. We normalize the Strings to lower
8410 // case right from the start. Turning characters to lower case
8411 // via Character.toLowerCase(char) is unfortunately insufficient
8412 // as it does not accept a locale.
8413 final String termLowerCase = term.toString().toLowerCase(locale);
8414 final String queryLowerCase = query.toString().toLowerCase(locale);
8415
8416 // the resulting score
8417 int score = 0;
8418
8419 // the position in the term which will be scanned next for potential
8420 // query character matches
8421 int termIndex = 0;
8422
8423 // index of the previously matched character in the term
8424 int previousMatchingCharacterIndex = Integer.MIN_VALUE;
8425
8426 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++){
8427 final char queryChar =queryLowerCase.charAt(queryIndex);
8428
8429 boolean termCharacterMatchFound =false;
8430 for (; termIndex <termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
8431 final char termChar =termLowerCase.charAt(termIndex);
8432
8433 if (queryChar == termChar) {
8434 // simple character matchesresult in one point
8435 score++;
8436
8437 // subsequent character matches furtherimprove
8438 // the score.
8439 if(previousMatchingCharacterIndex + 1 == termIndex) {
8440 score += 2;
8441 }
8442
8443 previousMatchingCharacterIndex = termIndex;
8444
8445 // we can leave the nestedloop. Every character in the
8446 // query can match at mostone character in the term.
8447 termCharacterMatchFound =true;
8448 }
8449 }
8450 }
8451
8452 return score;
8453 }
8454
8455 // startsWith
8456 //-----------------------------------------------------------------------
8457
8458 /**
8459 * <p>Check if a CharSequence starts with a specifiedprefix.</p>
8460 *
8461 * <p>{@code null}s are handled without exceptions. Two {@codenull}
8462 * references are considered to be equal. The comparison is case sensitive.</p>
8463 *
8464 * <pre>
8465 * StringUtils.startsWith(null, null) = true
8466 * StringUtils.startsWith(null, "abc") = false
8467 * StringUtils.startsWith("abcdef", null) = false
8468 * StringUtils.startsWith("abcdef", "abc") = true
8469 * StringUtils.startsWith("ABCDEF", "abc") = false
8470 * </pre>
8471 *
8472 * @see java.lang.String#startsWith(String)
8473 * @param str the CharSequence tocheck, may be null
8474 * @param prefix the prefix to find, may be null
8475 * @return {@code true} if the CharSequence starts with the prefix, casesensitive, or
8476 * both {@code null}
8477 * @since 2.4
8478 * @since 3.0 Changed signature from startsWith(String, String) tostartsWith(CharSequence, CharSequence)
8479 */
8480 public static boolean startsWith(final CharSequence str, finalCharSequence prefix) {
8481 return startsWith(str, prefix, false);
8482 }
8483
8484 /**
8485 * <p>Case insensitive check if a CharSequence starts with aspecified prefix.</p>
8486 *
8487 * <p>{@code null}s are handled without exceptions. Two {@codenull}
8488 * references are considered to be equal. The comparison is case insensitive.</p>
8489 *
8490 * <pre>
8491 * StringUtils.startsWithIgnoreCase(null, null) = true
8492 * StringUtils.startsWithIgnoreCase(null, "abc") = false
8493 * StringUtils.startsWithIgnoreCase("abcdef", null) = false
8494 * StringUtils.startsWithIgnoreCase("abcdef", "abc")= true
8495 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc")= true
8496 * </pre>
8497 *
8498 * @see java.lang.String#startsWith(String)
8499 * @param str the CharSequence to check,may be null
8500 * @param prefix the prefix to find, may be null
8501 * @return {@code true} if the CharSequence starts with the prefix, caseinsensitive, or
8502 * both {@code null}
8503 * @since 2.4
8504 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String)to startsWithIgnoreCase(CharSequence, CharSequence)
8505 */
8506 public static boolean startsWithIgnoreCase(final CharSequence str, finalCharSequence prefix) {
8507 return startsWith(str, prefix, true);
8508 }
8509
8510 /**
8511 * <p>Check if a CharSequence starts with a specified prefix(optionally case insensitive).</p>
8512 *
8513 * @see java.lang.String#startsWith(String)
8514 * @param str the CharSequence tocheck, may be null
8515 * @param prefix the prefix to find, may be null
8516 * @param ignoreCase indicates whether the compare should ignore case
8517 * (case insensitive) or not.
8518 * @return {@code true} if the CharSequence starts with the prefix or
8519 * both {@code null}
8520 */
8521 private static boolean startsWith(final CharSequence str, finalCharSequence prefix, final boolean ignoreCase) {
8522 if (str == null || prefix == null) {
8523 return str == null &&prefix == null;
8524 }
8525 if (prefix.length() > str.length()) {
8526 return false;
8527 }
8528 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0,prefix.length());
8529 }
8530
8531 /**
8532 * <p>Check if a CharSequence starts with any of the providedcase-sensitive prefixes.</p>
8533 *
8534 * <pre>
8535 * StringUtils.startsWithAny(null, null) = false
8536 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
8537 * StringUtils.startsWithAny("abcxyz", null) = false
8538 * StringUtils.startsWithAny("abcxyz", new String[]{""}) = true
8539 * StringUtils.startsWithAny("abcxyz", new String[]{"abc"}) = true
8540 * StringUtils.startsWithAny("abcxyz", new String[] {null,"xyz", "abc"}) = true
8541 * StringUtils.startsWithAny("abcxyz", null, "xyz","ABCX") = false
8542 * StringUtils.startsWithAny("ABCXYZ", null, "xyz","abc") = false
8543 * </pre>
8544 *
8545 * @param sequence the CharSequence to check, may be null
8546 * @param searchStrings the case-sensitive CharSequence prefixes, may beempty or contain {@code null}
8547 * @see StringUtils#startsWith(CharSequence, CharSequence)
8548 * @return {@code true} if the input {@code sequence} is {@code null} ANDno {@code searchStrings} are provided, or
8549 * the input {@code sequence}begins with any of the provided case-sensitive {@code searchStrings}.
8550 * @since 2.5
8551 * @since 3.0 Changed signature from startsWithAny(String, String[]) tostartsWithAny(CharSequence, CharSequence...)
8552 */
8553 public static boolean startsWithAny(final CharSequence sequence, finalCharSequence... searchStrings) {
8554 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8555 return false;
8556 }
8557 for (final CharSequence searchString : searchStrings) {
8558 if (startsWith(sequence,searchString)) {
8559 return true;
8560 }
8561 }
8562 return false;
8563 }
8564
8565 // endsWith
8566 //-----------------------------------------------------------------------
8567
8568 /**
8569 * <p>Check if a CharSequence ends with a specifiedsuffix.</p>
8570 *
8571 * <p>{@code null}s are handled without exceptions. Two {@codenull}
8572 * references are considered to be equal. The comparison is casesensitive.</p>
8573 *
8574 * <pre>
8575 * StringUtils.endsWith(null, null) = true
8576 * StringUtils.endsWith(null, "def") = false
8577 * StringUtils.endsWith("abcdef", null) = false
8578 * StringUtils.endsWith("abcdef", "def") = true
8579 * StringUtils.endsWith("ABCDEF", "def") = false
8580 * StringUtils.endsWith("ABCDEF", "cde") = false
8581 * StringUtils.endsWith("ABCDEF", "") = true
8582 * </pre>
8583 *
8584 * @see java.lang.String#endsWith(String)
8585 * @param str the CharSequence tocheck, may be null
8586 * @param suffix the suffix to find, may be null
8587 * @return {@code true} if the CharSequence ends with the suffix, casesensitive, or
8588 * both {@code null}
8589 * @since 2.4
8590 * @since 3.0 Changed signature from endsWith(String, String) toendsWith(CharSequence, CharSequence)
8591 */
8592 public static boolean endsWith(final CharSequence str, finalCharSequence suffix) {
8593 return endsWith(str, suffix, false);
8594 }
8595
8596 /**
8597 * <p>Case insensitive check if a CharSequence ends with aspecified suffix.</p>
8598 *
8599 * <p>{@code null}s are handled without exceptions. Two {@codenull}
8600 * references are considered to be equal. The comparison is caseinsensitive.</p>
8601 *
8602 * <pre>
8603 * StringUtils.endsWithIgnoreCase(null, null) = true
8604 * StringUtils.endsWithIgnoreCase(null, "def") = false
8605 * StringUtils.endsWithIgnoreCase("abcdef", null) = false
8606 * StringUtils.endsWithIgnoreCase("abcdef", "def") =true
8607 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") =true
8608 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") =false
8609 * </pre>
8610 *
8611 * @see java.lang.String#endsWith(String)
8612 * @param str the CharSequence tocheck, may be null
8613 * @param suffix the suffix to find, may be null
8614 * @return {@code true} if the CharSequence ends with the suffix, caseinsensitive, or
8615 * both {@code null}
8616 * @since 2.4
8617 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String)to endsWithIgnoreCase(CharSequence, CharSequence)
8618 */
8619 public static boolean endsWithIgnoreCase(final CharSequence str, finalCharSequence suffix) {
8620 return endsWith(str, suffix, true);
8621 }
8622
8623 /**
8624 * <p>Check if a CharSequence ends with a specified suffix(optionally case insensitive).</p>
8625 *
8626 * @see java.lang.String#endsWith(String)
8627 * @param str the CharSequence tocheck, may be null
8628 * @param suffix the suffix to find, may be null
8629 * @param ignoreCase indicates whether the compare should ignore case
8630 * (case insensitive) or not.
8631 * @return {@code true} if the CharSequence starts with the prefix or
8632 * both {@code null}
8633 */
8634 private static boolean endsWith(final CharSequence str, finalCharSequence suffix, final boolean ignoreCase) {
8635 if (str == null || suffix == null) {
8636 return str == null &&suffix == null;
8637 }
8638 if (suffix.length() > str.length()) {
8639 return false;
8640 }
8641 final int strOffset = str.length() - suffix.length();
8642 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset,suffix, 0, suffix.length());
8643 }
8644
8645 /**
8646 * <p>
8647 * Similar to <a
8648 *href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8649 * -space</a>
8650 * </p>
8651 * <p>
8652 * The function returns the argument string with whitespace normalized byusing
8653 * <code>{@link #trim(String)}</code> to remove leading andtrailing whitespace
8654 * and then replacing sequences of whitespace characters by a singlespace.
8655 * </p>
8656 * In XML Whitespace characters are the same as those allowed by the<a
8657 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a>production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8658 * <p>
8659 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8660 *
8661 * <p>For reference:</p>
8662 * <ul>
8663 * <li>\x0B = vertical tab</li>
8664 * <li>\f = #xC = form feed</li>
8665 * <li>#x20 = space</li>
8666 * <li>#x9 = \t</li>
8667 * <li>#xA = \n</li>
8668 * <li>#xD = \r</li>
8669 * </ul>
8670 *
8671 * <p>
8672 * The difference is that Java's whitespace includes vertical tab andform feed, which this functional will also
8673 * normalize. Additionally <code>{@link #trim(String)}</code>removes control characters (char <= 32) from both
8674 * ends of this String.
8675 * </p>
8676 *
8677 * @see Pattern
8678 * @see #trim(String)
8679 * @see <a
8680 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8681 * @param str the source String to normalize whitespaces from, may benull
8682 * @return the modified string with whitespace normalized, {@code null}if null String input
8683 *
8684 * @since 3.0
8685 */
8686 public static String normalizeSpace(final String str) {
8687 // LANG-1020: Improved performance significantly by normalizing manuallyinstead of using regex
8688 // Seehttps://github.com/librucha/commons-lang-normalizespaces-benchmark forperformance test
8689 if (isEmpty(str)) {
8690 return str;
8691 }
8692 final int size = str.length();
8693 final char[] newChars = new char[size];
8694 int count = 0;
8695 int whitespacesCount = 0;
8696 boolean startWhitespaces = true;
8697 for (int i = 0; i < size; i++) {
8698 final char actualChar =str.charAt(i);
8699 final boolean isWhitespace =Character.isWhitespace(actualChar);
8700 if (!isWhitespace) {
8701 startWhitespaces = false;
8702 newChars[count++] = (actualChar== 160 ? 32 : actualChar);
8703 whitespacesCount = 0;
8704 } else {
8705 if (whitespacesCount == 0&& !startWhitespaces) {
8706 newChars[count++] =SPACE.charAt(0);
8707 }
8708 whitespacesCount++;
8709 }
8710 }
8711 if (startWhitespaces) {
8712 return EMPTY;
8713 }
8714 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 :0)).trim();
8715 }
8716
8717 /**
8718 * <p>Check if a CharSequence ends with any of the providedcase-sensitive suffixes.</p>
8719 *
8720 * <pre>
8721 * StringUtils.endsWithAny(null, null) = false
8722 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
8723 * StringUtils.endsWithAny("abcxyz", null) = false
8724 * StringUtils.endsWithAny("abcxyz", new String[]{""}) = true
8725 * StringUtils.endsWithAny("abcxyz", new String[]{"xyz"}) = true
8726 * StringUtils.endsWithAny("abcxyz", new String[] {null,"xyz", "abc"}) = true
8727 * StringUtils.endsWithAny("abcXYZ", "def","XYZ") = true
8728 * StringUtils.endsWithAny("abcXYZ", "def","xyz") = false
8729 * </pre>
8730 *
8731 * @param sequence theCharSequence to check, may be null
8732 * @param searchStrings the case-sensitive CharSequences to find, may beempty or contain {@code null}
8733 * @see StringUtils#endsWith(CharSequence, CharSequence)
8734 * @return {@code true} if the input {@code sequence} is {@code null} ANDno {@code searchStrings} are provided, or
8735 * the input {@code sequence}ends in any of the provided case-sensitive {@code searchStrings}.
8736 * @since 3.0
8737 */
8738 public static boolean endsWithAny(final CharSequence sequence, finalCharSequence... searchStrings) {
8739 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8740 return false;
8741 }
8742 for (final CharSequence searchString : searchStrings) {
8743 if (endsWith(sequence,searchString)) {
8744 return true;
8745 }
8746 }
8747 return false;
8748 }
8749
8750 /**
8751 * Appends the suffix to the end of the string if the string does not
8752 * already end with the suffix.
8753 *
8754 * @param str The string.
8755 * @param suffix The suffix to append to the end of the string.
8756 * @param ignoreCase Indicates whether the compare should ignore case.
8757 * @param suffixes Additional suffixes that are valid terminators(optional).
8758 *
8759 * @return A new String if suffix was appended, the same stringotherwise.
8760 */
8761 private static String appendIfMissing(final String str, finalCharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes){
8762 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)){
8763 return str;
8764 }
8765 if (suffixes != null && suffixes.length > 0) {
8766 for (final CharSequence s :suffixes) {
8767 if (endsWith(str, s,ignoreCase)) {
8768 return str;
8769 }
8770 }
8771 }
8772 return str + suffix.toString();
8773 }
8774
8775 /**
8776 * Appends the suffix to the end of the string if the string does not
8777 * already end with any of the suffixes.
8778 *
8779 * <pre>
8780 * StringUtils.appendIfMissing(null, null) = null
8781 * StringUtils.appendIfMissing("abc", null) = "abc"
8782 * StringUtils.appendIfMissing("", "xyz") ="xyz"
8783 * StringUtils.appendIfMissing("abc", "xyz") ="abcxyz"
8784 * StringUtils.appendIfMissing("abcxyz", "xyz") ="abcxyz"
8785 * StringUtils.appendIfMissing("abcXYZ", "xyz") ="abcXYZxyz"
8786 * </pre>
8787 * <p>With additional suffixes,</p>
8788 * <pre>
8789 * StringUtils.appendIfMissing(null, null, null) = null
8790 * StringUtils.appendIfMissing("abc", null, null) ="abc"
8791 * StringUtils.appendIfMissing("", "xyz", null) ="xyz"
8792 * StringUtils.appendIfMissing("abc", "xyz", newCharSequence[]{null}) = "abcxyz"
8793 * StringUtils.appendIfMissing("abc", "xyz","") = "abc"
8794 * StringUtils.appendIfMissing("abc", "xyz","mno") = "abcxyz"
8795 * StringUtils.appendIfMissing("abcxyz", "xyz","mno") = "abcxyz"
8796 * StringUtils.appendIfMissing("abcmno", "xyz","mno") = "abcmno"
8797 * StringUtils.appendIfMissing("abcXYZ", "xyz","mno") = "abcXYZxyz"
8798 * StringUtils.appendIfMissing("abcMNO", "xyz","mno") = "abcMNOxyz"
8799 * </pre>
8800 *
8801 * @param str The string.
8802 * @param suffix The suffix to append to the end of the string.
8803 * @param suffixes Additional suffixes that are valid terminators.
8804 *
8805 * @return A new String if suffix was appended, the same stringotherwise.
8806 *
8807 * @since 3.2
8808 */
8809 public static String appendIfMissing(final String str, finalCharSequence suffix, final CharSequence... suffixes) {
8810 return appendIfMissing(str, suffix, false, suffixes);
8811 }
8812
8813 /**
8814 * Appends the suffix to the end of the string if the string does not
8815 * already end, case insensitive, with any of the suffixes.
8816 *
8817 * <pre>
8818 * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8819 * StringUtils.appendIfMissingIgnoreCase("abc", null) ="abc"
8820 * StringUtils.appendIfMissingIgnoreCase("", "xyz") ="xyz"
8821 * StringUtils.appendIfMissingIgnoreCase("abc","xyz") = "abcxyz"
8822 * StringUtils.appendIfMissingIgnoreCase("abcxyz","xyz") = "abcxyz"
8823 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz")= "abcXYZ"
8824 * </pre>
8825 * <p>With additional suffixes,</p>
8826 * <pre>
8827 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8828 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) ="abc"
8829 * StringUtils.appendIfMissingIgnoreCase("", "xyz",null) = "xyz"
8830 * StringUtils.appendIfMissingIgnoreCase("abc","xyz", new CharSequence[]{null}) = "abcxyz"
8831 * StringUtils.appendIfMissingIgnoreCase("abc","xyz", "") = "abc"
8832 * StringUtils.appendIfMissingIgnoreCase("abc","xyz", "mno") = "axyz"
8833 * StringUtils.appendIfMissingIgnoreCase("abcxyz","xyz", "mno") = "abcxyz"
8834 * StringUtils.appendIfMissingIgnoreCase("abcmno","xyz", "mno") = "abcmno"
8835 * StringUtils.appendIfMissingIgnoreCase("abcXYZ","xyz", "mno") = "abcXYZ"
8836 * StringUtils.appendIfMissingIgnoreCase("abcMNO","xyz", "mno") = "abcMNO"
8837 * </pre>
8838 *
8839 * @param str The string.
8840 * @param suffix The suffix to append to the end of the string.
8841 * @param suffixes Additional suffixes that are valid terminators.
8842 *
8843 * @return A new String if suffix was appended, the same stringotherwise.
8844 *
8845 * @since 3.2
8846 */
8847 public static String appendIfMissingIgnoreCase(final String str, finalCharSequence suffix, final CharSequence... suffixes) {
8848 return appendIfMissing(str, suffix, true, suffixes);
8849 }
8850
8851 /**
8852 * Prepends the prefix to the start of the string if the string does not
8853 * already start with any of the prefixes.
8854 *
8855 * @param str The string.
8856 * @param prefix The prefix to prepend to the start of the string.
8857 * @param ignoreCase Indicates whether the compare should ignore case.
8858 * @param prefixes Additional prefixes that are valid (optional).
8859 *
8860 * @return A new String if prefix was prepended, the same stringotherwise.
8861 */
8862 private static String prependIfMissing(final String str, finalCharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes){
8863 if (str == null || isEmpty(prefix) || startsWith(str, prefix,ignoreCase)) {
8864 return str;
8865 }
8866 if (prefixes != null && prefixes.length > 0) {
8867 for (final CharSequence p :prefixes) {
8868 if (startsWith(str, p,ignoreCase)) {
8869 return str;
8870 }
8871 }
8872 }
8873 return prefix.toString() + str;
8874 }
8875
8876 /**
8877 * Prepends the prefix to the start of the string if the string does not
8878 * already start with any of the prefixes.
8879 *
8880 * <pre>
8881 * StringUtils.prependIfMissing(null, null) = null
8882 * StringUtils.prependIfMissing("abc", null) = "abc"
8883 * StringUtils.prependIfMissing("", "xyz") ="xyz"
8884 * StringUtils.prependIfMissing("abc", "xyz") ="xyzabc"
8885 * StringUtils.prependIfMissing("xyzabc", "xyz") ="xyzabc"
8886 * StringUtils.prependIfMissing("XYZabc", "xyz") ="xyzXYZabc"
8887 * </pre>
8888 * <p>With additional prefixes,</p>
8889 * <pre>
8890 * StringUtils.prependIfMissing(null, null, null) = null
8891 * StringUtils.prependIfMissing("abc", null, null) ="abc"
8892 * StringUtils.prependIfMissing("", "xyz", null) ="xyz"
8893 * StringUtils.prependIfMissing("abc", "xyz", newCharSequence[]{null}) = "xyzabc"
8894 *StringUtils.prependIfMissing("abc", "xyz", "") ="abc"
8895 * StringUtils.prependIfMissing("abc", "xyz","mno") = "xyzabc"
8896 * StringUtils.prependIfMissing("xyzabc", "xyz","mno") = "xyzabc"
8897 * StringUtils.prependIfMissing("mnoabc", "xyz","mno") = "mnoabc"
8898 * StringUtils.prependIfMissing("XYZabc", "xyz","mno") = "xyzXYZabc"
8899 * StringUtils.prependIfMissing("MNOabc", "xyz","mno") = "xyzMNOabc"
8900 * </pre>
8901 *
8902 * @param str The string.
8903 * @param prefix The prefix to prepend to the start of the string.
8904 * @param prefixes Additional prefixes that are valid.
8905 *
8906 * @return A new String if prefix was prepended, the same string otherwise.
8907 *
8908 * @since 3.2
8909 */
8910 public static String prependIfMissing(final String str, finalCharSequence prefix, final CharSequence... prefixes) {
8911 return prependIfMissing(str, prefix, false, prefixes);
8912 }
8913
8914 /**
8915 * Prepends the prefix to the start of the string if the string does not
8916 * already start, case insensitive, with any of the prefixes.
8917 *
8918 * <pre>
8919 * StringUtils.prependIfMissingIgnoreCase(null, null) = null
8920 * StringUtils.prependIfMissingIgnoreCase("abc", null) ="abc"
8921 * StringUtils.prependIfMissingIgnoreCase("", "xyz")= "xyz"
8922 * StringUtils.prependIfMissingIgnoreCase("abc","xyz") = "xyzabc"
8923 * StringUtils.prependIfMissingIgnoreCase("xyzabc","xyz") = "xyzabc"
8924 * StringUtils.prependIfMissingIgnoreCase("XYZabc","xyz") = "XYZabc"
8925 * </pre>
8926 * <p>With additional prefixes,</p>
8927 * <pre>
8928 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
8929 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) ="abc"
8930 * StringUtils.prependIfMissingIgnoreCase("", "xyz",null) = "xyz"
8931 * StringUtils.prependIfMissingIgnoreCase("abc","xyz", new CharSequence[]{null}) = "xyzabc"
8932 * StringUtils.prependIfMissingIgnoreCase("abc","xyz", "") = "abc"
8933 * StringUtils.prependIfMissingIgnoreCase("abc","xyz", "mno") = "xyzabc"
8934 * StringUtils.prependIfMissingIgnoreCase("xyzabc","xyz", "mno") = "xyzabc"
8935 * StringUtils.prependIfMissingIgnoreCase("mnoabc","xyz", "mno") = "mnoabc"
8936 * StringUtils.prependIfMissingIgnoreCase("XYZabc","xyz", "mno") = "XYZabc"
8937 * StringUtils.prependIfMissingIgnoreCase("MNOabc","xyz", "mno") = "MNOabc"
8938 * </pre>
8939 *
8940 * @param str The string.
8941 * @param prefix The prefix to prepend to the start of the string.
8942 * @param prefixes Additional prefixes that are valid (optional).
8943 *
8944 * @return A new String if prefix was prepended, the same stringotherwise.
8945 *
8946 * @since 3.2
8947 */
8948 public static String prependIfMissingIgnoreCase(final String str, finalCharSequence prefix, final CharSequence... prefixes) {
8949 return prependIfMissing(str, prefix, true, prefixes);
8950 }
8951
8952 /**
8953 * Converts a <code>byte[]</code> to a String using thespecified character encoding.
8954 *
8955 * @param bytes
8956 * the byte array toread from
8957 * @param charsetName
8958 * the encoding to use,if null then use the platform default
8959 * @return a new String
8960 * @throws UnsupportedEncodingException
8961 * If the named charsetis not supported
8962 * @throws NullPointerException
8963 * if the input is null
8964 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)}instead of String constants in your code
8965 * @since 3.1
8966 */
8967 @Deprecated
8968 public static String toString(final byte[] bytes, final StringcharsetName) throws UnsupportedEncodingException {
8969 return charsetName != null ? new String(bytes, charsetName) : newString(bytes, Charset.defaultCharset());
8970 }
8971
8972 /**
8973 * Converts a <code>byte[]</code> to a String using thespecified character encoding.
8974 *
8975 * @param bytes
8976 * the byte array toread from
8977 * @param charset
8978 * the encoding to use,if null then use the platform default
8979 * @return a new String
8980 * @throws NullPointerException
8981 * if {@code bytes} isnull
8982 * @since 3.2
8983 * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8984 */
8985 public static String toEncodedString(final byte[] bytes, final Charsetcharset) {
8986 return new String(bytes, charset != null ? charset :Charset.defaultCharset());
8987 }
8988
8989 /**
8990 * <p>
8991 * Wraps a string with a char.
8992 * </p>
8993 *
8994 * <pre>
8995 * StringUtils.wrap(null, *) = null
8996 * StringUtils.wrap("", *) = ""
8997 * StringUtils.wrap("ab", '\0') = "ab"
8998 * StringUtils.wrap("ab", 'x') = "xabx"
8999 * StringUtils.wrap("ab", '\'') = "'ab'"
9000 * StringUtils.wrap("\"ab\"", '\"') ="\"\"ab\"\""
9001 * </pre>
9002 *
9003 * @param str
9004 * the string to bewrapped, may be {@code null}
9005 * @param wrapWith
9006 * the char that willwrap {@code str}
9007 * @return the wrapped string, or {@code null} if {@code str==null}
9008 * @since 3.4
9009 */
9010 public static String wrap(final String str, final char wrapWith) {
9011
9012 if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9013 return str;
9014 }
9015
9016 return wrapWith + str + wrapWith;
9017 }
9018
9019 /**
9020 * <p>
9021 * Wraps a String with another String.
9022 * </p>
9023 *
9024 * <p>
9025 * A {@code null} input String returns {@code null}.
9026 * </p>
9027 *
9028 * <pre>
9029 * StringUtils.wrap(null, *) = null
9030 * StringUtils.wrap("", *) = ""
9031 * StringUtils.wrap("ab", null) = "ab"
9032 * StringUtils.wrap("ab", "x") = "xabx"
9033 * StringUtils.wrap("ab", "\"") = "\"ab\""
9034 * StringUtils.wrap("\"ab\"","\"") ="\"\"ab\"\""
9035 * StringUtils.wrap("ab", "'") = "'ab'"
9036 * StringUtils.wrap("'abcd'", "'") = "''abcd''"
9037 * StringUtils.wrap("\"abcd\"", "'") ="'\"abcd\"'"
9038 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\""
9039 * </pre>
9040 *
9041 * @param str
9042 * the String to bewrapper, may be null
9043 * @param wrapWith
9044 * the String that willwrap str
9045 * @return wrapped String, {@code null} if null String input
9046 * @since 3.4
9047 */
9048 public static String wrap(final String str, final String wrapWith) {
9049
9050 if (isEmpty(str) || isEmpty(wrapWith)) {
9051 return str;
9052 }
9053
9054 return wrapWith.concat(str).concat(wrapWith);
9055 }
9056
9057 /**
9058 * <p>
9059 * Wraps a string with a char if that char is missing from the start orend of the given string.
9060 * </p>
9061 *
9062 * <pre>
9063 * StringUtils.wrap(null, *) = null
9064 * StringUtils.wrap("", *) = ""
9065 * StringUtils.wrap("ab", '\0') = "ab"
9066 * StringUtils.wrap("ab", 'x') = "xabx"
9067 * StringUtils.wrap("ab", '\'') = "'ab'"
9068 * StringUtils.wrap("\"ab\"", '\"') ="\"ab\""
9069 * StringUtils.wrap("/", '/') = "/"
9070 * StringUtils.wrap("a/b/c", '/') = "/a/b/c/"
9071 * StringUtils.wrap("/a/b/c", '/') = "/a/b/c/"
9072 * StringUtils.wrap("a/b/c/", '/') = "/a/b/c/"
9073 * </pre>
9074 *
9075 * @param str
9076 * the string to be wrapped,may be {@code null}
9077 * @param wrapWith
9078 * the char that willwrap {@code str}
9079 * @return the wrapped string, or {@code null} if {@code str==null}
9080 * @since 3.5
9081 */
9082 public static String wrapIfMissing(final String str, final charwrapWith) {
9083 if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9084 return str;
9085 }
9086 final StringBuilder builder = new StringBuilder(str.length() + 2);
9087 if (str.charAt(0) != wrapWith) {
9088 builder.append(wrapWith);
9089 }
9090 builder.append(str);
9091 if (str.charAt(str.length() - 1) != wrapWith) {
9092 builder.append(wrapWith);
9093 }
9094 return builder.toString();
9095 }
9096
9097 /**
9098 * <p>
9099 * Wraps a string with a string if that string is missing from the startor end of the given string.
9100 * </p>
9101 *
9102 * <pre>
9103 * StringUtils.wrap(null, *) = null
9104 * StringUtils.wrap("", *) = ""
9105 * StringUtils.wrap("ab", null) = "ab"
9106 * StringUtils.wrap("ab", "x") = "xabx"
9107 * StringUtils.wrap("ab", "\"") = "\"ab\""
9108 * StringUtils.wrap("\"ab\"","\"") ="\"ab\""
9109 * StringUtils.wrap("ab", "'") = "'ab'"
9110 * StringUtils.wrap("'abcd'", "'") = "'abcd'"
9111 * StringUtils.wrap("\"abcd\"", "'") ="'\"abcd\"'"
9112 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\""
9113 * StringUtils.wrap("/", "/") = "/"
9114 * StringUtils.wrap("a/b/c", "/") = "/a/b/c/"
9115 * StringUtils.wrap("/a/b/c", "/") = "/a/b/c/"
9116 * StringUtils.wrap("a/b/c/", "/") = "/a/b/c/"
9117 * </pre>
9118 *
9119 * @param str
9120 * the string to bewrapped, may be {@code null}
9121 * @param wrapWith
9122 * the char that willwrap {@code str}
9123 * @return the wrapped string, or {@code null} if {@code str==null}
9124 * @since 3.5
9125 */
9126 public static String wrapIfMissing(final String str, final StringwrapWith) {
9127 if (isEmpty(str) || isEmpty(wrapWith)) {
9128 return str;
9129 }
9130 final StringBuilder builder = new StringBuilder(str.length() +wrapWith.length() + wrapWith.length());
9131 if (!str.startsWith(wrapWith)) {
9132 builder.append(wrapWith);
9133 }
9134 builder.append(str);
9135 if (!str.endsWith(wrapWith)) {
9136 builder.append(wrapWith);
9137 }
9138 return builder.toString();
9139 }
9140
9141 /**
9142 * <p>
9143 * Unwraps a given string from anther string.
9144 * </p>
9145 *
9146 * <pre>
9147 * StringUtils.unwrap(null, null) = null
9148 * StringUtils.unwrap(null, "") = null
9149 * StringUtils.unwrap(null, "1") = null
9150 * StringUtils.unwrap("\'abc\'", "\'") = "abc"
9151 * StringUtils.unwrap("\"abc\"","\"") = "abc"
9152 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB"
9153 * StringUtils.unwrap("A", "#") = "A"
9154 * StringUtils.unwrap("#A", "#") = "#A"
9155 * StringUtils.unwrap("A#", "#") = "A#"
9156 * </pre>
9157 *
9158 * @param str
9159 * the String to beunwrapped, can be null
9160 * @param wrapToken
9161 * the String used tounwrap
9162 * @return unwrapped String or the original string
9163 * if it is not quotedproperly with the wrapToken
9164 * @since 3.6
9165 */
9166 public static String unwrap(final String str, final String wrapToken) {
9167 if (isEmpty(str) || isEmpty(wrapToken)) {
9168 return str;
9169 }
9170
9171 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9172 final int startIndex =str.indexOf(wrapToken);
9173 final int endIndex =str.lastIndexOf(wrapToken);
9174 final int wrapLength =wrapToken.length();
9175 if (startIndex != -1 &&endIndex != -1) {
9176 return str.substring(startIndex+ wrapLength, endIndex);
9177 }
9178 }
9179
9180 return str;
9181 }
9182
9183 /**
9184 * <p>
9185 * Unwraps a given string from a character.
9186 * </p>
9187 *
9188 * <pre>
9189 * StringUtils.unwrap(null, null) = null
9190 * StringUtils.unwrap(null, '\0') = null
9191 * StringUtils.unwrap(null, '1') = null
9192 * StringUtils.unwrap("\'abc\'", '\'') = "abc"
9193 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA"
9194 * StringUtils.unwrap("A", '#') = "A"
9195 * StringUtils.unwrap("#A", '#') = "#A"
9196 * StringUtils.unwrap("A#", '#') = "A#"
9197 * </pre>
9198 *
9199 * @param str
9200 * the String to beunwrapped, can be null
9201 * @param wrapChar
9202 * the character used tounwrap
9203 * @return unwrapped String or the original string
9204 * if it is not quotedproperly with the wrapChar
9205 * @since 3.6
9206 */
9207 public static String unwrap(final String str, final char wrapChar) {
9208 if (isEmpty(str) || wrapChar == CharUtils.NUL) {
9209 return str;
9210 }
9211
9212 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) ==wrapChar) {
9213 final int startIndex = 0;
9214 final int endIndex = str.length() -1;
9215 if (startIndex != -1 &&endIndex != -1) {
9216 return str.substring(startIndex+ 1, endIndex);
9217 }
9218 }
9219
9220 return str;
9221 }
9222
9223 /**
9224 * <p>Converts a {@code CharSequence} into an array of codepoints.</p>
9225 *
9226 * <p>Valid pairs of surrogate code units will be converted into asingle supplementary
9227 * code point. Isolated surrogate code units (i.e. a high surrogate notfollowed by a low surrogate or
9228 * a low surrogate not preceeded by a high surrogate) will be returnedas-is.</p>
9229 *
9230 * <pre>
9231 * StringUtils.toCodePoints(null) = null
9232 * StringUtils.toCodePoints("") = [] // empty array
9233 * </pre>
9234 *
9235 * @param str the character sequence to convert
9236 * @return an array of code points
9237 * @since 3.6
9238 */
9239 public static int[] toCodePoints(CharSequence str) {
9240 if (str == null) {
9241 return null;
9242 }
9243 if (str.length() == 0) {
9244 return ArrayUtils.EMPTY_INT_ARRAY;
9245 }
9246
9247 String s = str.toString();
9248 int[] result = new int[s.codePointCount(0, s.length())];
9249 int index = 0;
9250 for (int i = 0; i < result.length; i++) {
9251 result[i] = s.codePointAt(index);
9252 index += Character.charCount(result[i]);
9253 }
9254 return result;
9255 }
9256}
- StringUtils_英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文
- 英文网站
- 英文名言
- 英文缩写
- 英文求职信
- 英文站
- eureka双节点注册中心打包成功后无法启动
- 混合云的五大好处
- iOS审核被拒-副标题包括关键字
- 给定一个数组,找出数组的峰值。返回其下标
- 前端面试题小集
- StringUtils_英文
- 几道经典的递归(可以用动态规划优化)好题源码实现(2)
- 强大的前端数据表格控件
- 【java基础:IO】多个输入流通过SequenceInputStream序列流整合成一个大流然后输出的Demostration
- Linux的shell脚本中获取当前服务器内网ip
- Error 1275
- Caffe从入门到精通09
- SQL的经验累积
- git学习,常用命令