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