org.apache.commons.lang3.StringUtils Maven / Gradle / Ivy
Show all versions of commons-lang3 Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.regex.Pattern;
/**
* Operations on {@link java.lang.String} that are
* {@code null} safe.
*
*
* - IsEmpty/IsBlank
* - checks if a String contains text
* - Trim/Strip
* - removes leading and trailing whitespace
* - Equals/Compare
* - compares two strings null-safe
* - startsWith
* - check if a String starts with a prefix null-safe
* - endsWith
* - check if a String ends with a suffix null-safe
* - IndexOf/LastIndexOf/Contains
* - null-safe index-of checks
*
- IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut
* - index-of any of a set of Strings
* - ContainsOnly/ContainsNone/ContainsAny
* - does String contains only/none/any of these characters
* - Substring/Left/Right/Mid
* - null-safe substring extractions
* - SubstringBefore/SubstringAfter/SubstringBetween
* - substring extraction relative to other strings
* - Split/Join
* - splits a String into an array of substrings and vice versa
* - Remove/Delete
* - removes part of a String
* - Replace/Overlay
* - Searches a String and replaces one String with another
* - Chomp/Chop
* - removes the last part of a String
* - AppendIfMissing
* - appends a suffix to the end of the String if not present
* - PrependIfMissing
* - prepends a prefix to the start of the String if not present
* - LeftPad/RightPad/Center/Repeat
* - pads a String
* - UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize
* - changes the case of a String
* - CountMatches
* - counts the number of occurrences of one String in another
* - IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable
* - checks the characters in a String
* - DefaultString
* - protects against a null input String
* - Rotate
* - rotate (circular shift) a String
* - Reverse/ReverseDelimited
* - reverses a String
* - Abbreviate
* - abbreviates a string using ellipsis or another given String
* - Difference
* - compares Strings and reports on their differences
* - LevenshteinDistance
* - the number of changes needed to change one String into another
*
*
* The {@code StringUtils} class defines certain words related to
* String handling.
*
*
* - null - {@code null}
* - empty - a zero-length string ({@code ""})
* - space - the space character ({@code ' '}, char 32)
* - whitespace - the characters defined by {@link Character#isWhitespace(char)}
* - trim - the characters <= 32 as in {@link String#trim()}
*
*
* {@code StringUtils} handles {@code null} input Strings quietly.
* That is to say that a {@code null} input will return {@code null}.
* Where a {@code boolean} or {@code int} is being returned
* details vary by method.
*
* A side effect of the {@code null} handling is that a
* {@code NullPointerException} should be considered a bug in
* {@code StringUtils}.
*
* Methods in this class give sample code to explain their operation.
* The symbol {@code *} is used to indicate any input including {@code null}.
*
* #ThreadSafe#
* @see java.lang.String
* @since 1.0
*/
//@Immutable
public class StringUtils {
private static final int STRING_BUILDER_SIZE = 256;
// Performance testing notes (JDK 1.4, Jul03, scolebourne)
// Whitespace:
// Character.isWhitespace() is faster than WHITESPACE.indexOf()
// where WHITESPACE is a string of all whitespace characters
//
// Character access:
// String.charAt(n) versus toCharArray(), then array[n]
// String.charAt(n) is about 15% worse for a 10K string
// They are about equal for a length 50 string
// String.charAt(n) is about 4 times better for a length 3 string
// String.charAt(n) is best bet overall
//
// Append:
// String.concat about twice as fast as StringBuffer.append
// (not sure who tested this)
/**
* A String for a space character.
*
* @since 3.2
*/
public static final String SPACE = " ";
/**
* The empty String {@code ""}.
* @since 2.0
*/
public static final String EMPTY = "";
/**
* A String for linefeed LF ("\n").
*
* @see JLF: Escape Sequences
* for Character and String Literals
* @since 3.2
*/
public static final String LF = "\n";
/**
* A String for carriage return CR ("\r").
*
* @see JLF: Escape Sequences
* for Character and String Literals
* @since 3.2
*/
public static final String CR = "\r";
/**
* Represents a failed index search.
* @since 2.1
*/
public static final int INDEX_NOT_FOUND = -1;
/**
* The maximum size to which the padding constant(s) can expand.
*/
private static final int PAD_LIMIT = 8192;
// Abbreviating
//-----------------------------------------------------------------------
/**
* Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "Now is the time for..."
*
* Specifically:
*
* - If the number of characters in {@code str} is less than or equal to
* {@code maxWidth}, return {@code str}.
* - Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.
* - If {@code maxWidth} is less than {@code 4}, throw an
* {@code IllegalArgumentException}.
* - In no case will it return a String of length greater than
* {@code maxWidth}.
*
*
*
* StringUtils.abbreviate(null, *) = null
* StringUtils.abbreviate("", 4) = ""
* StringUtils.abbreviate("abcdefg", 6) = "abc..."
* StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
* StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
* StringUtils.abbreviate("abcdefg", 4) = "a..."
* StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param maxWidth maximum length of result String, must be at least 4
* @return abbreviated String, {@code null} if null String input
* @throws IllegalArgumentException if the width is too small
* @since 2.0
*/
public static String abbreviate(final String str, final int maxWidth) {
return abbreviate(str, "...", 0, maxWidth);
}
/**
* Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "...is the time for..."
*
* Works like {@code abbreviate(String, int)}, but allows you to specify
* a "left edge" offset. Note that this left edge is not necessarily going to
* be the leftmost character in the result, or the first character following the
* ellipses, but it will appear somewhere in the result.
*
*
In no case will it return a String of length greater than
* {@code maxWidth}.
*
*
* StringUtils.abbreviate(null, *, *) = null
* StringUtils.abbreviate("", 0, 4) = ""
* StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
* StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
* StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
* StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param offset left edge of source String
* @param maxWidth maximum length of result String, must be at least 4
* @return abbreviated String, {@code null} if null String input
* @throws IllegalArgumentException if the width is too small
* @since 2.0
*/
public static String abbreviate(final String str, final int offset, final int maxWidth) {
return abbreviate(str, "...", offset, maxWidth);
}
/**
* Abbreviates a String using another given String as replacement marker. This will turn
* "Now is the time for all good men" into "Now is the time for..." if "..." was defined
* as the replacement marker.
*
* Specifically:
*
* - If the number of characters in {@code str} is less than or equal to
* {@code maxWidth}, return {@code str}.
* - Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.
* - If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
* {@code IllegalArgumentException}.
* - In no case will it return a String of length greater than
* {@code maxWidth}.
*
*
*
* StringUtils.abbreviate(null, "...", *) = null
* StringUtils.abbreviate("abcdefg", null, *) = "abcdefg"
* StringUtils.abbreviate("", "...", 4) = ""
* StringUtils.abbreviate("abcdefg", ".", 5) = "abcd."
* StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg"
* StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg"
* StringUtils.abbreviate("abcdefg", "..", 4) = "ab.."
* StringUtils.abbreviate("abcdefg", "..", 3) = "a.."
* StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException
* StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param abbrevMarker the String used as replacement marker
* @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1}
* @return abbreviated String, {@code null} if null String input
* @throws IllegalArgumentException if the width is too small
* @since 3.6
*/
public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
return abbreviate(str, abbrevMarker, 0, maxWidth);
}
/**
* Abbreviates a String using a given replacement marker. This will turn
* "Now is the time for all good men" into "...is the time for..." if "..." was defined
* as the replacement marker.
*
* Works like {@code abbreviate(String, String, int)}, but allows you to specify
* a "left edge" offset. Note that this left edge is not necessarily going to
* be the leftmost character in the result, or the first character following the
* replacement marker, but it will appear somewhere in the result.
*
*
In no case will it return a String of length greater than {@code maxWidth}.
*
*
* StringUtils.abbreviate(null, null, *, *) = null
* StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno"
* StringUtils.abbreviate("", "...", 0, 4) = ""
* StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
* StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi,"
* StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi,"
* StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi,"
* StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::"
* StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..."
* StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno"
* StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno"
* StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno"
* StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException
* StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param abbrevMarker the String used as replacement marker
* @param offset left edge of source String
* @param maxWidth maximum length of result String, must be at least 4
* @return abbreviated String, {@code null} if null String input
* @throws IllegalArgumentException if the width is too small
* @since 3.6
*/
public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
if (isEmpty(str) && isEmpty(abbrevMarker)) {
return str;
} else if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
return str.substring(0, maxWidth);
} else if (isEmpty(str) || isEmpty(abbrevMarker)) {
return str;
}
final int abbrevMarkerLength = abbrevMarker.length();
final int minAbbrevWidth = abbrevMarkerLength + 1;
final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
if (maxWidth < minAbbrevWidth) {
throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
}
if (str.length() <= maxWidth) {
return str;
}
if (offset > str.length()) {
offset = str.length();
}
if (str.length() - offset < maxWidth - abbrevMarkerLength) {
offset = str.length() - (maxWidth - abbrevMarkerLength);
}
if (offset <= abbrevMarkerLength+1) {
return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
}
if (maxWidth < minAbbrevWidthOffset) {
throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
}
if (offset + maxWidth - abbrevMarkerLength < str.length()) {
return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
}
return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
}
/**
* Abbreviates a String to the length passed, replacing the middle characters with the supplied
* replacement String.
*
* This abbreviation only occurs if the following criteria is met:
*
* - Neither the String for abbreviation nor the replacement String are null or empty
* - The length to truncate to is less than the length of the supplied String
* - The length to truncate to is greater than 0
* - The abbreviated String will have enough room for the length supplied replacement String
* and the first and last characters of the supplied String for abbreviation
*
* Otherwise, the returned String will be the same as the supplied String for abbreviation.
*
*
*
* StringUtils.abbreviateMiddle(null, null, 0) = null
* StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
* StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
* StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
* StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
*
*
* @param str the String to abbreviate, may be null
* @param middle the String to replace the middle characters with, may be null
* @param length the length to abbreviate {@code str} to.
* @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
* @since 2.5
*/
public static String abbreviateMiddle(final String str, final String middle, final int length) {
if (isEmpty(str) || isEmpty(middle)) {
return str;
}
if (length >= str.length() || length < middle.length()+2) {
return str;
}
final int targetSting = length-middle.length();
final int startOffset = targetSting/2+targetSting%2;
final int endOffset = str.length()-targetSting/2;
return str.substring(0, startOffset) +
middle +
str.substring(endOffset);
}
/**
* Appends the suffix to the end of the string if the string does not
* already end with the suffix.
*
* @param str The string.
* @param suffix The suffix to append to the end of the string.
* @param ignoreCase Indicates whether the compare should ignore case.
* @param suffixes Additional suffixes that are valid terminators (optional).
*
* @return A new String if suffix was appended, the same string otherwise.
*/
private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
return str;
}
if (ArrayUtils.isNotEmpty(suffixes)) {
for (final CharSequence s : suffixes) {
if (endsWith(str, s, ignoreCase)) {
return str;
}
}
}
return str + suffix.toString();
}
/**
* Appends the suffix to the end of the string if the string does not
* already end with any of the suffixes.
*
*
* StringUtils.appendIfMissing(null, null) = null
* StringUtils.appendIfMissing("abc", null) = "abc"
* StringUtils.appendIfMissing("", "xyz") = "xyz"
* StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
* StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
* StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
*
* With additional suffixes,
*
* StringUtils.appendIfMissing(null, null, null) = null
* StringUtils.appendIfMissing("abc", null, null) = "abc"
* StringUtils.appendIfMissing("", "xyz", null) = "xyz"
* StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
* StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
* StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
* StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
* StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
* StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
* StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
*
*
* @param str The string.
* @param suffix The suffix to append to the end of the string.
* @param suffixes Additional suffixes that are valid terminators.
*
* @return A new String if suffix was appended, the same string otherwise.
*
* @since 3.2
*/
public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
return appendIfMissing(str, suffix, false, suffixes);
}
/**
* Appends the suffix to the end of the string if the string does not
* already end, case insensitive, with any of the suffixes.
*
*
* StringUtils.appendIfMissingIgnoreCase(null, null) = null
* StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
* StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
* StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
* StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
* StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
*
* With additional suffixes,
*
* StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
* StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
* StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
* StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
* StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
* StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
* StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
* StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
* StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
* StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
*
*
* @param str The string.
* @param suffix The suffix to append to the end of the string.
* @param suffixes Additional suffixes that are valid terminators.
*
* @return A new String if suffix was appended, the same string otherwise.
*
* @since 3.2
*/
public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
return appendIfMissing(str, suffix, true, suffixes);
}
/**
* Capitalizes a String changing the first character to title case as
* per {@link Character#toTitleCase(int)}. No other characters are changed.
*
* For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
* A {@code null} input String returns {@code null}.
*
*
* StringUtils.capitalize(null) = null
* StringUtils.capitalize("") = ""
* StringUtils.capitalize("cat") = "Cat"
* StringUtils.capitalize("cAt") = "CAt"
* StringUtils.capitalize("'cat'") = "'cat'"
*
*
* @param str the String to capitalize, may be null
* @return the capitalized String, {@code null} if null String input
* @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
* @see #uncapitalize(String)
* @since 2.0
*/
public static String capitalize(final String str) {
final int strLen = length(str);
if (strLen == 0) {
return str;
}
final int firstCodepoint = str.codePointAt(0);
final int newCodePoint = Character.toTitleCase(firstCodepoint);
if (firstCodepoint == newCodePoint) {
// already capitalized
return str;
}
final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
int outOffset = 0;
newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
final int codepoint = str.codePointAt(inOffset);
newCodePoints[outOffset++] = codepoint; // copy the remaining ones
inOffset += Character.charCount(codepoint);
}
return new String(newCodePoints, 0, outOffset);
}
// Centering
//-----------------------------------------------------------------------
/**
* Centers a String in a larger String of size {@code size}
* using the space character (' ').
*
* If the size is less than the String length, the String is returned.
* A {@code null} String returns {@code null}.
* A negative size is treated as zero.
*
* Equivalent to {@code center(str, size, " ")}.
*
*
* StringUtils.center(null, *) = null
* StringUtils.center("", 4) = " "
* StringUtils.center("ab", -1) = "ab"
* StringUtils.center("ab", 4) = " ab "
* StringUtils.center("abcd", 2) = "abcd"
* StringUtils.center("a", 4) = " a "
*
*
* @param str the String to center, may be null
* @param size the int size of new String, negative treated as zero
* @return centered String, {@code null} if null String input
*/
public static String center(final String str, final int size) {
return center(str, size, ' ');
}
/**
* Centers a String in a larger String of size {@code size}.
* Uses a supplied character as the value to pad the String with.
*
* If the size is less than the String length, the String is returned.
* A {@code null} String returns {@code null}.
* A negative size is treated as zero.
*
*
* StringUtils.center(null, *, *) = null
* StringUtils.center("", 4, ' ') = " "
* StringUtils.center("ab", -1, ' ') = "ab"
* StringUtils.center("ab", 4, ' ') = " ab "
* StringUtils.center("abcd", 2, ' ') = "abcd"
* StringUtils.center("a", 4, ' ') = " a "
* StringUtils.center("a", 4, 'y') = "yayy"
*
*
* @param str the String to center, may be null
* @param size the int size of new String, negative treated as zero
* @param padChar the character to pad the new String with
* @return centered String, {@code null} if null String input
* @since 2.0
*/
public static String center(String str, final int size, final char padChar) {
if (str == null || size <= 0) {
return str;
}
final int strLen = str.length();
final int pads = size - strLen;
if (pads <= 0) {
return str;
}
str = leftPad(str, strLen + pads / 2, padChar);
str = rightPad(str, size, padChar);
return str;
}
/**
* Centers a String in a larger String of size {@code size}.
* Uses a supplied String as the value to pad the String with.
*
* If the size is less than the String length, the String is returned.
* A {@code null} String returns {@code null}.
* A negative size is treated as zero.
*
*
* StringUtils.center(null, *, *) = null
* StringUtils.center("", 4, " ") = " "
* StringUtils.center("ab", -1, " ") = "ab"
* StringUtils.center("ab", 4, " ") = " ab "
* StringUtils.center("abcd", 2, " ") = "abcd"
* StringUtils.center("a", 4, " ") = " a "
* StringUtils.center("a", 4, "yz") = "yayz"
* StringUtils.center("abc", 7, null) = " abc "
* StringUtils.center("abc", 7, "") = " abc "
*
*
* @param str the String to center, may be null
* @param size the int size of new String, negative treated as zero
* @param padStr the String to pad the new String with, must not be null or empty
* @return centered String, {@code null} if null String input
* @throws IllegalArgumentException if padStr is {@code null} or empty
*/
public static String center(String str, final int size, String padStr) {
if (str == null || size <= 0) {
return str;
}
if (isEmpty(padStr)) {
padStr = SPACE;
}
final int strLen = str.length();
final int pads = size - strLen;
if (pads <= 0) {
return str;
}
str = leftPad(str, strLen + pads / 2, padStr);
str = rightPad(str, size, padStr);
return str;
}
// Chomping
//-----------------------------------------------------------------------
/**
* Removes one newline from end of a String if it's there,
* otherwise leave it alone. A newline is "{@code \n}",
* "{@code \r}", or "{@code \r\n}".
*
* NOTE: This method changed in 2.0.
* It now more closely matches Perl chomp.
*
*
* StringUtils.chomp(null) = null
* StringUtils.chomp("") = ""
* StringUtils.chomp("abc \r") = "abc "
* StringUtils.chomp("abc\n") = "abc"
* StringUtils.chomp("abc\r\n") = "abc"
* StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
* StringUtils.chomp("abc\n\r") = "abc\n"
* StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
* StringUtils.chomp("\r") = ""
* StringUtils.chomp("\n") = ""
* StringUtils.chomp("\r\n") = ""
*
*
* @param str the String to chomp a newline from, may be null
* @return String without newline, {@code null} if null String input
*/
public static String chomp(final String str) {
if (isEmpty(str)) {
return str;
}
if (str.length() == 1) {
final char ch = str.charAt(0);
if (ch == CharUtils.CR || ch == CharUtils.LF) {
return EMPTY;
}
return str;
}
int lastIdx = str.length() - 1;
final char last = str.charAt(lastIdx);
if (last == CharUtils.LF) {
if (str.charAt(lastIdx - 1) == CharUtils.CR) {
lastIdx--;
}
} else if (last != CharUtils.CR) {
lastIdx++;
}
return str.substring(0, lastIdx);
}
/**
* Removes {@code separator} from the end of
* {@code str} if it's there, otherwise leave it alone.
*
* NOTE: This method changed in version 2.0.
* It now more closely matches Perl chomp.
* For the previous behavior, use {@link #substringBeforeLast(String, String)}.
* This method uses {@link String#endsWith(String)}.
*
*
* StringUtils.chomp(null, *) = null
* StringUtils.chomp("", *) = ""
* StringUtils.chomp("foobar", "bar") = "foo"
* StringUtils.chomp("foobar", "baz") = "foobar"
* StringUtils.chomp("foo", "foo") = ""
* StringUtils.chomp("foo ", "foo") = "foo "
* StringUtils.chomp(" foo", "foo") = " "
* StringUtils.chomp("foo", "foooo") = "foo"
* StringUtils.chomp("foo", "") = "foo"
* StringUtils.chomp("foo", null) = "foo"
*
*
* @param str the String to chomp from, may be null
* @param separator separator String, may be null
* @return String without trailing separator, {@code null} if null String input
* @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
*/
@Deprecated
public static String chomp(final String str, final String separator) {
return removeEnd(str, separator);
}
// Chopping
//-----------------------------------------------------------------------
/**
* Remove the last character from a String.
*
* If the String ends in {@code \r\n}, then remove both
* of them.
*
*
* StringUtils.chop(null) = null
* StringUtils.chop("") = ""
* StringUtils.chop("abc \r") = "abc "
* StringUtils.chop("abc\n") = "abc"
* StringUtils.chop("abc\r\n") = "abc"
* StringUtils.chop("abc") = "ab"
* StringUtils.chop("abc\nabc") = "abc\nab"
* StringUtils.chop("a") = ""
* StringUtils.chop("\r") = ""
* StringUtils.chop("\n") = ""
* StringUtils.chop("\r\n") = ""
*
*
* @param str the String to chop last character from, may be null
* @return String without last character, {@code null} if null String input
*/
public static String chop(final String str) {
if (str == null) {
return null;
}
final int strLen = str.length();
if (strLen < 2) {
return EMPTY;
}
final int lastIdx = strLen - 1;
final String ret = str.substring(0, lastIdx);
final char last = str.charAt(lastIdx);
if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
return ret.substring(0, lastIdx - 1);
}
return ret;
}
// Compare
//-----------------------------------------------------------------------
/**
* Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
*
* - {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
* - {@code int < 0}, if {@code str1} is less than {@code str2}
* - {@code int > 0}, if {@code str1} is greater than {@code str2}
*
*
* This is a {@code null} safe version of :
* str1.compareTo(str2)
*
* {@code null} value is considered less than non-{@code null} value.
* Two {@code null} references are considered equal.
*
*
* StringUtils.compare(null, null) = 0
* StringUtils.compare(null , "a") < 0
* StringUtils.compare("a", null) > 0
* StringUtils.compare("abc", "abc") = 0
* StringUtils.compare("a", "b") < 0
* StringUtils.compare("b", "a") > 0
* StringUtils.compare("a", "B") > 0
* StringUtils.compare("ab", "abc") < 0
*
*
* @see #compare(String, String, boolean)
* @see String#compareTo(String)
* @param str1 the String to compare from
* @param str2 the String to compare to
* @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2}
* @since 3.5
*/
public static int compare(final String str1, final String str2) {
return compare(str1, str2, true);
}
/**
* Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
*
* - {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
* - {@code int < 0}, if {@code str1} is less than {@code str2}
* - {@code int > 0}, if {@code str1} is greater than {@code str2}
*
*
* This is a {@code null} safe version of :
* str1.compareTo(str2)
*
* {@code null} inputs are handled according to the {@code nullIsLess} parameter.
* Two {@code null} references are considered equal.
*
*
* StringUtils.compare(null, null, *) = 0
* StringUtils.compare(null , "a", true) < 0
* StringUtils.compare(null , "a", false) > 0
* StringUtils.compare("a", null, true) > 0
* StringUtils.compare("a", null, false) < 0
* StringUtils.compare("abc", "abc", *) = 0
* StringUtils.compare("a", "b", *) < 0
* StringUtils.compare("b", "a", *) > 0
* StringUtils.compare("a", "B", *) > 0
* StringUtils.compare("ab", "abc", *) < 0
*
*
* @see String#compareTo(String)
* @param str1 the String to compare from
* @param str2 the String to compare to
* @param nullIsLess whether consider {@code null} value less than non-{@code null} value
* @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
* @since 3.5
*/
public static int compare(final String str1, final String str2, final boolean nullIsLess) {
if (str1 == str2) {
return 0;
}
if (str1 == null) {
return nullIsLess ? -1 : 1;
}
if (str2 == null) {
return nullIsLess ? 1 : - 1;
}
return str1.compareTo(str2);
}
/**
* Compare two Strings lexicographically, ignoring case differences,
* as per {@link String#compareToIgnoreCase(String)}, returning :
*
* - {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
* - {@code int < 0}, if {@code str1} is less than {@code str2}
* - {@code int > 0}, if {@code str1} is greater than {@code str2}
*
*
* This is a {@code null} safe version of :
* str1.compareToIgnoreCase(str2)
*
* {@code null} value is considered less than non-{@code null} value.
* Two {@code null} references are considered equal.
* Comparison is case insensitive.
*
*
* StringUtils.compareIgnoreCase(null, null) = 0
* StringUtils.compareIgnoreCase(null , "a") < 0
* StringUtils.compareIgnoreCase("a", null) > 0
* StringUtils.compareIgnoreCase("abc", "abc") = 0
* StringUtils.compareIgnoreCase("abc", "ABC") = 0
* StringUtils.compareIgnoreCase("a", "b") < 0
* StringUtils.compareIgnoreCase("b", "a") > 0
* StringUtils.compareIgnoreCase("a", "B") < 0
* StringUtils.compareIgnoreCase("A", "b") < 0
* StringUtils.compareIgnoreCase("ab", "ABC") < 0
*
*
* @see #compareIgnoreCase(String, String, boolean)
* @see String#compareToIgnoreCase(String)
* @param str1 the String to compare from
* @param str2 the String to compare to
* @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
* ignoring case differences.
* @since 3.5
*/
public static int compareIgnoreCase(final String str1, final String str2) {
return compareIgnoreCase(str1, str2, true);
}
/**
* Compare two Strings lexicographically, ignoring case differences,
* as per {@link String#compareToIgnoreCase(String)}, returning :
*
* - {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
* - {@code int < 0}, if {@code str1} is less than {@code str2}
* - {@code int > 0}, if {@code str1} is greater than {@code str2}
*
*
* This is a {@code null} safe version of :
* str1.compareToIgnoreCase(str2)
*
* {@code null} inputs are handled according to the {@code nullIsLess} parameter.
* Two {@code null} references are considered equal.
* Comparison is case insensitive.
*
*
* StringUtils.compareIgnoreCase(null, null, *) = 0
* StringUtils.compareIgnoreCase(null , "a", true) < 0
* StringUtils.compareIgnoreCase(null , "a", false) > 0
* StringUtils.compareIgnoreCase("a", null, true) > 0
* StringUtils.compareIgnoreCase("a", null, false) < 0
* StringUtils.compareIgnoreCase("abc", "abc", *) = 0
* StringUtils.compareIgnoreCase("abc", "ABC", *) = 0
* StringUtils.compareIgnoreCase("a", "b", *) < 0
* StringUtils.compareIgnoreCase("b", "a", *) > 0
* StringUtils.compareIgnoreCase("a", "B", *) < 0
* StringUtils.compareIgnoreCase("A", "b", *) < 0
* StringUtils.compareIgnoreCase("ab", "abc", *) < 0
*
*
* @see String#compareToIgnoreCase(String)
* @param str1 the String to compare from
* @param str2 the String to compare to
* @param nullIsLess whether consider {@code null} value less than non-{@code null} value
* @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
* ignoring case differences.
* @since 3.5
*/
public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
if (str1 == str2) {
return 0;
}
if (str1 == null) {
return nullIsLess ? -1 : 1;
}
if (str2 == null) {
return nullIsLess ? 1 : - 1;
}
return str1.compareToIgnoreCase(str2);
}
/**
* Checks if CharSequence contains a search CharSequence, handling {@code null}.
* This method uses {@link String#indexOf(String)} if possible.
*
* A {@code null} CharSequence will return {@code false}.
*
*
* StringUtils.contains(null, *) = false
* StringUtils.contains(*, null) = false
* StringUtils.contains("", "") = true
* StringUtils.contains("abc", "") = true
* StringUtils.contains("abc", "a") = true
* StringUtils.contains("abc", "z") = false
*
*
* @param seq the CharSequence to check, may be null
* @param searchSeq the CharSequence to find, may be null
* @return true if the CharSequence contains the search CharSequence,
* false if not or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
*/
public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
if (seq == null || searchSeq == null) {
return false;
}
return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
}
// Contains
//-----------------------------------------------------------------------
/**
* Checks if CharSequence contains a search character, handling {@code null}.
* This method uses {@link String#indexOf(int)} if possible.
*
* A {@code null} or empty ("") CharSequence will return {@code false}.
*
*
* StringUtils.contains(null, *) = false
* StringUtils.contains("", *) = false
* StringUtils.contains("abc", 'a') = true
* StringUtils.contains("abc", 'z') = false
*
*
* @param seq the CharSequence to check, may be null
* @param searchChar the character to find
* @return true if the CharSequence contains the search character,
* false if not or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
*/
public static boolean contains(final CharSequence seq, final int searchChar) {
if (isEmpty(seq)) {
return false;
}
return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
}
// ContainsAny
//-----------------------------------------------------------------------
/**
* Checks if the CharSequence contains any character in the given
* set of characters.
*
* A {@code null} CharSequence will return {@code false}.
* A {@code null} or zero length search array will return {@code false}.
*
*
* StringUtils.containsAny(null, *) = false
* StringUtils.containsAny("", *) = false
* StringUtils.containsAny(*, null) = false
* StringUtils.containsAny(*, []) = false
* StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
* StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
* StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
* StringUtils.containsAny("aba", ['z']) = false
*
*
* @param cs the CharSequence to check, may be null
* @param searchChars the chars to search for, may be null
* @return the {@code true} if any of the chars are found,
* {@code false} if no match or null input
* @since 2.4
* @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
*/
public static boolean containsAny(final CharSequence cs, final char... searchChars) {
if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
return false;
}
final int csLength = cs.length();
final int searchLength = searchChars.length;
final int csLast = csLength - 1;
final int searchLast = searchLength - 1;
for (int i = 0; i < csLength; i++) {
final char ch = cs.charAt(i);
for (int j = 0; j < searchLength; j++) {
if (searchChars[j] == ch) {
if (Character.isHighSurrogate(ch)) {
if (j == searchLast) {
// missing low surrogate, fine, like String.indexOf(String)
return true;
}
if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
return true;
}
} else {
// ch is in the Basic Multilingual Plane
return true;
}
}
}
}
return false;
}
/**
*
* Checks if the CharSequence contains any character in the given set of characters.
*
*
*
* A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
* {@code false}.
*
*
*
* StringUtils.containsAny(null, *) = false
* StringUtils.containsAny("", *) = false
* StringUtils.containsAny(*, null) = false
* StringUtils.containsAny(*, "") = false
* StringUtils.containsAny("zzabyycdxx", "za") = true
* StringUtils.containsAny("zzabyycdxx", "by") = true
* StringUtils.containsAny("zzabyycdxx", "zy") = true
* StringUtils.containsAny("zzabyycdxx", "\tx") = true
* StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
* StringUtils.containsAny("aba", "z") = false
*
*
* @param cs
* the CharSequence to check, may be null
* @param searchChars
* the chars to search for, may be null
* @return the {@code true} if any of the chars are found, {@code false} if no match or null input
* @since 2.4
* @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
*/
public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
if (searchChars == null) {
return false;
}
return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
}
/**
* Checks if the CharSequence contains any of the CharSequences in the given array.
*
*
* A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
* length search array will return {@code false}.
*
*
*
* StringUtils.containsAny(null, *) = false
* StringUtils.containsAny("", *) = false
* StringUtils.containsAny(*, null) = false
* StringUtils.containsAny(*, []) = false
* StringUtils.containsAny("abcd", "ab", null) = true
* StringUtils.containsAny("abcd", "ab", "cd") = true
* StringUtils.containsAny("abc", "d", "abc") = true
*
*
*
* @param cs The CharSequence to check, may be null
* @param searchCharSequences The array of CharSequences to search for, may be null.
* Individual CharSequences may be null as well.
* @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
* @since 3.4
*/
public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
return false;
}
for (final CharSequence searchCharSequence : searchCharSequences) {
if (contains(cs, searchCharSequence)) {
return true;
}
}
return false;
}
/**
* Checks if CharSequence contains a search CharSequence irrespective of case,
* handling {@code null}. Case-insensitivity is defined as by
* {@link String#equalsIgnoreCase(String)}.
*
*
A {@code null} CharSequence will return {@code false}.
*
*
* StringUtils.containsIgnoreCase(null, *) = false
* StringUtils.containsIgnoreCase(*, null) = false
* StringUtils.containsIgnoreCase("", "") = true
* StringUtils.containsIgnoreCase("abc", "") = true
* StringUtils.containsIgnoreCase("abc", "a") = true
* StringUtils.containsIgnoreCase("abc", "z") = false
* StringUtils.containsIgnoreCase("abc", "A") = true
* StringUtils.containsIgnoreCase("abc", "Z") = false
*
*
* @param str the CharSequence to check, may be null
* @param searchStr the CharSequence to find, may be null
* @return true if the CharSequence contains the search CharSequence irrespective of
* case or false if not or {@code null} string input
* @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
*/
public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
if (str == null || searchStr == null) {
return false;
}
final int len = searchStr.length();
final int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
// ContainsNone
//-----------------------------------------------------------------------
/**
* Checks that the CharSequence does not contain certain characters.
*
* A {@code null} CharSequence will return {@code true}.
* A {@code null} invalid character array will return {@code true}.
* An empty CharSequence (length()=0) always returns true.
*
*
* StringUtils.containsNone(null, *) = true
* StringUtils.containsNone(*, null) = true
* StringUtils.containsNone("", *) = true
* StringUtils.containsNone("ab", '') = true
* StringUtils.containsNone("abab", 'xyz') = true
* StringUtils.containsNone("ab1", 'xyz') = true
* StringUtils.containsNone("abz", 'xyz') = false
*
*
* @param cs the CharSequence to check, may be null
* @param searchChars an array of invalid chars, may be null
* @return true if it contains none of the invalid chars, or is null
* @since 2.0
* @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
*/
public static boolean containsNone(final CharSequence cs, final char... searchChars) {
if (cs == null || searchChars == null) {
return true;
}
final int csLen = cs.length();
final int csLast = csLen - 1;
final int searchLen = searchChars.length;
final int searchLast = searchLen - 1;
for (int i = 0; i < csLen; i++) {
final char ch = cs.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (Character.isHighSurrogate(ch)) {
if (j == searchLast) {
// missing low surrogate, fine, like String.indexOf(String)
return false;
}
if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
return false;
}
} else {
// ch is in the Basic Multilingual Plane
return false;
}
}
}
}
return true;
}
/**
* Checks that the CharSequence does not contain certain characters.
*
* A {@code null} CharSequence will return {@code true}.
* A {@code null} invalid character array will return {@code true}.
* An empty String ("") always returns true.
*
*
* StringUtils.containsNone(null, *) = true
* StringUtils.containsNone(*, null) = true
* StringUtils.containsNone("", *) = true
* StringUtils.containsNone("ab", "") = true
* StringUtils.containsNone("abab", "xyz") = true
* StringUtils.containsNone("ab1", "xyz") = true
* StringUtils.containsNone("abz", "xyz") = false
*
*
* @param cs the CharSequence to check, may be null
* @param invalidChars a String of invalid chars, may be null
* @return true if it contains none of the invalid chars, or is null
* @since 2.0
* @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
*/
public static boolean containsNone(final CharSequence cs, final String invalidChars) {
if (cs == null || invalidChars == null) {
return true;
}
return containsNone(cs, invalidChars.toCharArray());
}
// ContainsOnly
//-----------------------------------------------------------------------
/**
* Checks if the CharSequence contains only certain characters.
*
* A {@code null} CharSequence will return {@code false}.
* A {@code null} valid character array will return {@code false}.
* An empty CharSequence (length()=0) always returns {@code true}.
*
*
* StringUtils.containsOnly(null, *) = false
* StringUtils.containsOnly(*, null) = false
* StringUtils.containsOnly("", *) = true
* StringUtils.containsOnly("ab", '') = false
* StringUtils.containsOnly("abab", 'abc') = true
* StringUtils.containsOnly("ab1", 'abc') = false
* StringUtils.containsOnly("abz", 'abc') = false
*
*
* @param cs the String to check, may be null
* @param valid an array of valid chars, may be null
* @return true if it only contains valid chars and is non-null
* @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
*/
public static boolean containsOnly(final CharSequence cs, final char... valid) {
// All these pre-checks are to maintain API with an older version
if (valid == null || cs == null) {
return false;
}
if (cs.length() == 0) {
return true;
}
if (valid.length == 0) {
return false;
}
return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
}
/**
* Checks if the CharSequence contains only certain characters.
*
* A {@code null} CharSequence will return {@code false}.
* A {@code null} valid character String will return {@code false}.
* An empty String (length()=0) always returns {@code true}.
*
*
* StringUtils.containsOnly(null, *) = false
* StringUtils.containsOnly(*, null) = false
* StringUtils.containsOnly("", *) = true
* StringUtils.containsOnly("ab", "") = false
* StringUtils.containsOnly("abab", "abc") = true
* StringUtils.containsOnly("ab1", "abc") = false
* StringUtils.containsOnly("abz", "abc") = false
*
*
* @param cs the CharSequence to check, may be null
* @param validChars a String of valid chars, may be null
* @return true if it only contains valid chars and is non-null
* @since 2.0
* @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
*/
public static boolean containsOnly(final CharSequence cs, final String validChars) {
if (cs == null || validChars == null) {
return false;
}
return containsOnly(cs, validChars.toCharArray());
}
/**
* Check whether the given CharSequence contains any whitespace characters.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* @param seq the CharSequence to check (may be {@code null})
* @return {@code true} if the CharSequence is not empty and
* contains at least 1 (breaking) whitespace character
* @since 3.0
*/
// From org.springframework.util.StringUtils, under Apache License 2.0
public static boolean containsWhitespace(final CharSequence seq) {
if (isEmpty(seq)) {
return false;
}
final int strLen = seq.length();
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(seq.charAt(i))) {
return true;
}
}
return false;
}
private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
for (int i = 0; i < decomposed.length(); i++) {
if (decomposed.charAt(i) == '\u0141') {
decomposed.deleteCharAt(i);
decomposed.insert(i, 'L');
} else if (decomposed.charAt(i) == '\u0142') {
decomposed.deleteCharAt(i);
decomposed.insert(i, 'l');
}
}
}
/**
* Counts how many times the char appears in the given string.
*
* A {@code null} or empty ("") String input returns {@code 0}.
*
*
* StringUtils.countMatches(null, *) = 0
* StringUtils.countMatches("", *) = 0
* StringUtils.countMatches("abba", 0) = 0
* StringUtils.countMatches("abba", 'a') = 2
* StringUtils.countMatches("abba", 'b') = 2
* StringUtils.countMatches("abba", 'x') = 0
*
*
* @param str the CharSequence to check, may be null
* @param ch the char to count
* @return the number of occurrences, 0 if the CharSequence is {@code null}
* @since 3.4
*/
public static int countMatches(final CharSequence str, final char ch) {
if (isEmpty(str)) {
return 0;
}
int count = 0;
// We could also call str.toCharArray() for faster look ups but that would generate more garbage.
for (int i = 0; i < str.length(); i++) {
if (ch == str.charAt(i)) {
count++;
}
}
return count;
}
// Count matches
//-----------------------------------------------------------------------
/**
* Counts how many times the substring appears in the larger string.
*
* A {@code null} or empty ("") String input returns {@code 0}.
*
*
* StringUtils.countMatches(null, *) = 0
* StringUtils.countMatches("", *) = 0
* StringUtils.countMatches("abba", null) = 0
* StringUtils.countMatches("abba", "") = 0
* StringUtils.countMatches("abba", "a") = 2
* StringUtils.countMatches("abba", "ab") = 1
* StringUtils.countMatches("abba", "xxx") = 0
*
*
* @param str the CharSequence to check, may be null
* @param sub the substring to count, may be null
* @return the number of occurrences, 0 if either CharSequence is {@code null}
* @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
*/
public static int countMatches(final CharSequence str, final CharSequence sub) {
if (isEmpty(str) || isEmpty(sub)) {
return 0;
}
int count = 0;
int idx = 0;
while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
count++;
idx += sub.length();
}
return count;
}
/**
* Returns either the passed in CharSequence, or if the CharSequence is
* whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.defaultIfBlank(null, "NULL") = "NULL"
* StringUtils.defaultIfBlank("", "NULL") = "NULL"
* StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
* StringUtils.defaultIfBlank("bat", "NULL") = "bat"
* StringUtils.defaultIfBlank("", null) = null
*
* @param the specific kind of CharSequence
* @param str the CharSequence to check, may be null
* @param defaultStr the default CharSequence to return
* if the input is whitespace, empty ("") or {@code null}, may be null
* @return the passed in CharSequence, or the default
* @see StringUtils#defaultString(String, String)
*/
public static T defaultIfBlank(final T str, final T defaultStr) {
return isBlank(str) ? defaultStr : str;
}
/**
* Returns either the passed in CharSequence, or if the CharSequence is
* empty or {@code null}, the value of {@code defaultStr}.
*
*
* StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
* StringUtils.defaultIfEmpty("", "NULL") = "NULL"
* StringUtils.defaultIfEmpty(" ", "NULL") = " "
* StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
* StringUtils.defaultIfEmpty("", null) = null
*
* @param the specific kind of CharSequence
* @param str the CharSequence to check, may be null
* @param defaultStr the default CharSequence to return
* if the input is empty ("") or {@code null}, may be null
* @return the passed in CharSequence, or the default
* @see StringUtils#defaultString(String, String)
*/
public static T defaultIfEmpty(final T str, final T defaultStr) {
return isEmpty(str) ? defaultStr : str;
}
/**
* Returns either the passed in String,
* or if the String is {@code null}, an empty String ("").
*
*
* StringUtils.defaultString(null) = ""
* StringUtils.defaultString("") = ""
* StringUtils.defaultString("bat") = "bat"
*
*
* @see ObjectUtils#toString(Object)
* @see String#valueOf(Object)
* @param str the String to check, may be null
* @return the passed in String, or the empty String if it
* was {@code null}
*/
public static String defaultString(final String str) {
return defaultString(str, EMPTY);
}
/**
* Returns either the passed in String, or if the String is
* {@code null}, the value of {@code defaultStr}.
*
*
* StringUtils.defaultString(null, "NULL") = "NULL"
* StringUtils.defaultString("", "NULL") = ""
* StringUtils.defaultString("bat", "NULL") = "bat"
*
*
* @see ObjectUtils#toString(Object,String)
* @see String#valueOf(Object)
* @param str the String to check, may be null
* @param defaultStr the default String to return
* if the input is {@code null}, may be null
* @return the passed in String, or the default if it was {@code null}
*/
public static String defaultString(final String str, final String defaultStr) {
return str == null ? defaultStr : str;
}
// Delete
//-----------------------------------------------------------------------
/**
* Deletes all whitespaces from a String as defined by
* {@link Character#isWhitespace(char)}.
*
*
* StringUtils.deleteWhitespace(null) = null
* StringUtils.deleteWhitespace("") = ""
* StringUtils.deleteWhitespace("abc") = "abc"
* StringUtils.deleteWhitespace(" ab c ") = "abc"
*
*
* @param str the String to delete whitespace from, may be null
* @return the String without whitespaces, {@code null} if null String input
*/
public static String deleteWhitespace(final String str) {
if (isEmpty(str)) {
return str;
}
final int sz = str.length();
final char[] chs = new char[sz];
int count = 0;
for (int i = 0; i < sz; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
chs[count++] = str.charAt(i);
}
}
if (count == sz) {
return str;
}
return new String(chs, 0, count);
}
// Difference
//-----------------------------------------------------------------------
/**
* Compares two Strings, and returns the portion where they differ.
* More precisely, return the remainder of the second String,
* starting from where it's different from the first. This means that
* the difference between "abc" and "ab" is the empty String and not "c".
*
* For example,
* {@code difference("i am a machine", "i am a robot") -> "robot"}.
*
*
* StringUtils.difference(null, null) = null
* StringUtils.difference("", "") = ""
* StringUtils.difference("", "abc") = "abc"
* StringUtils.difference("abc", "") = ""
* StringUtils.difference("abc", "abc") = ""
* StringUtils.difference("abc", "ab") = ""
* StringUtils.difference("ab", "abxyz") = "xyz"
* StringUtils.difference("abcde", "abxyz") = "xyz"
* StringUtils.difference("abcde", "xyz") = "xyz"
*
*
* @param str1 the first String, may be null
* @param str2 the second String, may be null
* @return the portion of str2 where it differs from str1; returns the
* empty String if they are equal
* @see #indexOfDifference(CharSequence,CharSequence)
* @since 2.0
*/
public static String difference(final String str1, final String str2) {
if (str1 == null) {
return str2;
}
if (str2 == null) {
return str1;
}
final int at = indexOfDifference(str1, str2);
if (at == INDEX_NOT_FOUND) {
return EMPTY;
}
return str2.substring(at);
}
/**
* Check if a CharSequence ends with a specified suffix.
*
* {@code null}s are handled without exceptions. Two {@code null}
* references are considered to be equal. The comparison is case sensitive.
*
*
* StringUtils.endsWith(null, null) = true
* StringUtils.endsWith(null, "def") = false
* StringUtils.endsWith("abcdef", null) = false
* StringUtils.endsWith("abcdef", "def") = true
* StringUtils.endsWith("ABCDEF", "def") = false
* StringUtils.endsWith("ABCDEF", "cde") = false
* StringUtils.endsWith("ABCDEF", "") = true
*
*
* @see java.lang.String#endsWith(String)
* @param str the CharSequence to check, may be null
* @param suffix the suffix to find, may be null
* @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
* both {@code null}
* @since 2.4
* @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
*/
public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
return endsWith(str, suffix, false);
}
/**
* Check if a CharSequence ends with a specified suffix (optionally case insensitive).
*
* @see java.lang.String#endsWith(String)
* @param str the CharSequence to check, may be null
* @param suffix the suffix to find, may be null
* @param ignoreCase indicates whether the compare should ignore case
* (case insensitive) or not.
* @return {@code true} if the CharSequence starts with the prefix or
* both {@code null}
*/
private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
if (str == null || suffix == null) {
return str == suffix;
}
if (suffix.length() > str.length()) {
return false;
}
final int strOffset = str.length() - suffix.length();
return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
}
/**
* Check if a CharSequence ends with any of the provided case-sensitive suffixes.
*
*
* StringUtils.endsWithAny(null, null) = false
* StringUtils.endsWithAny(null, new String[] {"abc"}) = false
* StringUtils.endsWithAny("abcxyz", null) = false
* StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
* StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
* StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
* StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
* StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
*
*
* @param sequence the CharSequence to check, may be null
* @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
* @see StringUtils#endsWith(CharSequence, CharSequence)
* @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
* the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
* @since 3.0
*/
public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
return false;
}
for (final CharSequence searchString : searchStrings) {
if (endsWith(sequence, searchString)) {
return true;
}
}
return false;
}
/**
* Case insensitive check if a CharSequence ends with a specified suffix.
*
* {@code null}s are handled without exceptions. Two {@code null}
* references are considered to be equal. The comparison is case insensitive.
*
*
* StringUtils.endsWithIgnoreCase(null, null) = true
* StringUtils.endsWithIgnoreCase(null, "def") = false
* StringUtils.endsWithIgnoreCase("abcdef", null) = false
* StringUtils.endsWithIgnoreCase("abcdef", "def") = true
* StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
* StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
*
*
* @see java.lang.String#endsWith(String)
* @param str the CharSequence to check, may be null
* @param suffix the suffix to find, may be null
* @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
* both {@code null}
* @since 2.4
* @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
*/
public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
return endsWith(str, suffix, true);
}
// Equals
//-----------------------------------------------------------------------
/**
* Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters.
*
* {@code null}s are handled without exceptions. Two {@code null}
* references are considered to be equal. The comparison is case sensitive.
*
*
* StringUtils.equals(null, null) = true
* StringUtils.equals(null, "abc") = false
* StringUtils.equals("abc", null) = false
* StringUtils.equals("abc", "abc") = true
* StringUtils.equals("abc", "ABC") = false
*
*
* @param cs1 the first CharSequence, may be {@code null}
* @param cs2 the second CharSequence, may be {@code null}
* @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
* @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
* @see Object#equals(Object)
* @see #equalsIgnoreCase(CharSequence, CharSequence)
*/
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1.length() != cs2.length()) {
return false;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
// Step-wise comparison
final int length = cs1.length();
for (int i = 0; i < length; i++) {
if (cs1.charAt(i) != cs2.charAt(i)) {
return false;
}
}
return true;
}
/**
* Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
* returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
*
*
* StringUtils.equalsAny(null, (CharSequence[]) null) = false
* StringUtils.equalsAny(null, null, null) = true
* StringUtils.equalsAny(null, "abc", "def") = false
* StringUtils.equalsAny("abc", null, "def") = false
* StringUtils.equalsAny("abc", "abc", "def") = true
* StringUtils.equalsAny("abc", "ABC", "DEF") = false
*
*
* @param string to compare, may be {@code null}.
* @param searchStrings a vararg of strings, may be {@code null}.
* @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
* {@code false} if {@code searchStrings} is null or contains no matches.
* @since 3.5
*/
public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
if (ArrayUtils.isNotEmpty(searchStrings)) {
for (final CharSequence next : searchStrings) {
if (equals(string, next)) {
return true;
}
}
}
return false;
}
/**
* Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
* returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
*
*
* StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
* StringUtils.equalsAnyIgnoreCase(null, null, null) = true
* StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false
* StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false
* StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
* StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
*
*
* @param string to compare, may be {@code null}.
* @param searchStrings a vararg of strings, may be {@code null}.
* @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
* {@code false} if {@code searchStrings} is null or contains no matches.
* @since 3.5
*/
public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
if (ArrayUtils.isNotEmpty(searchStrings)) {
for (final CharSequence next : searchStrings) {
if (equalsIgnoreCase(string, next)) {
return true;
}
}
}
return false;
}
/**
* Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters, ignoring case.
*
* {@code null}s are handled without exceptions. Two {@code null}
* references are considered equal. The comparison is case insensitive.
*
*
* StringUtils.equalsIgnoreCase(null, null) = true
* StringUtils.equalsIgnoreCase(null, "abc") = false
* StringUtils.equalsIgnoreCase("abc", null) = false
* StringUtils.equalsIgnoreCase("abc", "abc") = true
* StringUtils.equalsIgnoreCase("abc", "ABC") = true
*
*
* @param cs1 the first CharSequence, may be {@code null}
* @param cs2 the second CharSequence, may be {@code null}
* @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
* @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
* @see #equals(CharSequence, CharSequence)
*/
public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1.length() != cs2.length()) {
return false;
}
return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
}
/**
* Returns the first value in the array which is not empty (""),
* {@code null} or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* If all values are blank or the array is {@code null}
* or empty then {@code null} is returned.
*
*
* StringUtils.firstNonBlank(null, null, null) = null
* StringUtils.firstNonBlank(null, "", " ") = null
* StringUtils.firstNonBlank("abc") = "abc"
* StringUtils.firstNonBlank(null, "xyz") = "xyz"
* StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
* StringUtils.firstNonBlank(null, "xyz", "abc") = "xyz"
* StringUtils.firstNonBlank() = null
*
*
* @param the specific kind of CharSequence
* @param values the values to test, may be {@code null} or empty
* @return the first value from {@code values} which is not blank,
* or {@code null} if there are no non-blank values
* @since 3.8
*/
@SafeVarargs
public static T firstNonBlank(final T... values) {
if (values != null) {
for (final T val : values) {
if (isNotBlank(val)) {
return val;
}
}
}
return null;
}
/**
* Returns the first value in the array which is not empty.
*
* If all values are empty or the array is {@code null}
* or empty then {@code null} is returned.
*
*
* StringUtils.firstNonEmpty(null, null, null) = null
* StringUtils.firstNonEmpty(null, null, "") = null
* StringUtils.firstNonEmpty(null, "", " ") = " "
* StringUtils.firstNonEmpty("abc") = "abc"
* StringUtils.firstNonEmpty(null, "xyz") = "xyz"
* StringUtils.firstNonEmpty("", "xyz") = "xyz"
* StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
* StringUtils.firstNonEmpty() = null
*
*
* @param the specific kind of CharSequence
* @param values the values to test, may be {@code null} or empty
* @return the first value from {@code values} which is not empty,
* or {@code null} if there are no non-empty values
* @since 3.8
*/
@SafeVarargs
public static T firstNonEmpty(final T... values) {
if (values != null) {
for (final T val : values) {
if (isNotEmpty(val)) {
return val;
}
}
}
return null;
}
/**
* Calls {@link String#getBytes(Charset)} in a null-safe manner.
*
* @param string input string
* @param charset The {@link Charset} to encode the {@code String}. If null, then use the default Charset.
* @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
* @see String#getBytes(Charset)
* @since 3.10
*/
public static byte[] getBytes(final String string, final Charset charset) {
return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
}
/**
* Calls {@link String#getBytes(String)} in a null-safe manner.
*
* @param string input string
* @param charset The {@link Charset} name to encode the {@code String}. If null, then use the default Charset.
* @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
* @throws UnsupportedEncodingException Thrown when the named charset is not supported.
* @see String#getBytes(String)
* @since 3.10
*/
public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
}
/**
* Compares all Strings in an array and returns the initial sequence of
* characters that is common to all of them.
*
* For example,
* {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "}
*
*
* StringUtils.getCommonPrefix(null) = ""
* StringUtils.getCommonPrefix(new String[] {}) = ""
* StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
* StringUtils.getCommonPrefix(new String[] {null, null}) = ""
* StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
* StringUtils.getCommonPrefix(new String[] {"", null}) = ""
* StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
* StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
* StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
* StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
* StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
* StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
* StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
* StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
* StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
* StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
* StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
*
*
* @param strs array of String objects, entries may be null
* @return the initial sequence of characters that are common to all Strings
* in the array; empty String if the array is null, the elements are all null
* or if there is no common prefix.
* @since 2.4
*/
public static String getCommonPrefix(final String... strs) {
if (ArrayUtils.isEmpty(strs)) {
return EMPTY;
}
final int smallestIndexOfDiff = indexOfDifference(strs);
if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
// all strings were identical
if (strs[0] == null) {
return EMPTY;
}
return strs[0];
} else if (smallestIndexOfDiff == 0) {
// there were no common initial characters
return EMPTY;
} else {
// we found a common initial character sequence
return strs[0].substring(0, smallestIndexOfDiff);
}
}
/**
* Checks if a String {@code str} contains Unicode digits,
* if yes then concatenate all the digits in {@code str} and return it as a String.
*
* An empty ("") String will be returned if no digits found in {@code str}.
*
*
* StringUtils.getDigits(null) = null
* StringUtils.getDigits("") = ""
* StringUtils.getDigits("abc") = ""
* StringUtils.getDigits("1000$") = "1000"
* StringUtils.getDigits("1123~45") = "112345"
* StringUtils.getDigits("(541) 754-3010") = "5417543010"
* StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
*
*
* @param str the String to extract digits from, may be null
* @return String with only digits,
* or an empty ("") String if no digits found,
* or {@code null} String if {@code str} is null
* @since 3.6
*/
public static String getDigits(final String str) {
if (isEmpty(str)) {
return str;
}
final int sz = str.length();
final StringBuilder strDigits = new StringBuilder(sz);
for (int i = 0; i < sz; i++) {
final char tempChar = str.charAt(i);
if (Character.isDigit(tempChar)) {
strDigits.append(tempChar);
}
}
return strDigits.toString();
}
/**
* Find the Fuzzy Distance which indicates the similarity score between two Strings.
*
* This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
* TextMate, Atom and others. One point is given for every matched character. Subsequent
* matches yield two bonus points. A higher score indicates a higher similarity.
*
*
* StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException
* StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0
* StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0
* StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1
* StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1
* StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2
* StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4
* StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
*
*
* @param term a full term that should be matched against, must not be null
* @param query the query that will be matched against a term, must not be null
* @param locale This string matching logic is case insensitive. A locale is necessary to normalize
* both Strings to lower case.
* @return result score
* @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
* @since 3.4
* @deprecated as of 3.6, use commons-text
*
* FuzzyScore instead
*/
@Deprecated
public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
if (term == null || query == null) {
throw new IllegalArgumentException("Strings must not be null");
} else if (locale == null) {
throw new IllegalArgumentException("Locale must not be null");
}
// fuzzy logic is case insensitive. We normalize the Strings to lower
// case right from the start. Turning characters to lower case
// via Character.toLowerCase(char) is unfortunately insufficient
// as it does not accept a locale.
final String termLowerCase = term.toString().toLowerCase(locale);
final String queryLowerCase = query.toString().toLowerCase(locale);
// the resulting score
int score = 0;
// the position in the term which will be scanned next for potential
// query character matches
int termIndex = 0;
// index of the previously matched character in the term
int previousMatchingCharacterIndex = Integer.MIN_VALUE;
for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
final char queryChar = queryLowerCase.charAt(queryIndex);
boolean termCharacterMatchFound = false;
for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
final char termChar = termLowerCase.charAt(termIndex);
if (queryChar == termChar) {
// simple character matches result in one point
score++;
// subsequent character matches further improve
// the score.
if (previousMatchingCharacterIndex + 1 == termIndex) {
score += 2;
}
previousMatchingCharacterIndex = termIndex;
// we can leave the nested loop. Every character in the
// query can match at most one character in the term.
termCharacterMatchFound = true;
}
}
}
return score;
}
/**
* Returns either the passed in CharSequence, or if the CharSequence is
* whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* Caller responsible for thread-safety and exception handling of default value supplier
*
*
* {@code
* StringUtils.getIfBlank(null, () -> "NULL") = "NULL"
* StringUtils.getIfBlank("", () -> "NULL") = "NULL"
* StringUtils.getIfBlank(" ", () -> "NULL") = "NULL"
* StringUtils.getIfBlank("bat", () -> "NULL") = "bat"
* StringUtils.getIfBlank("", () -> null) = null
* StringUtils.getIfBlank("", null) = null
* }
* @param the specific kind of CharSequence
* @param str the CharSequence to check, may be null
* @param defaultSupplier the supplier of default CharSequence to return
* if the input is whitespace, empty ("") or {@code null}, may be null
* @return the passed in CharSequence, or the default
* @see StringUtils#defaultString(String, String)
* @since 3.10
*/
public static T getIfBlank(final T str, final Supplier defaultSupplier) {
return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
}
/**
* Returns either the passed in CharSequence, or if the CharSequence is
* empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
*
* Caller responsible for thread-safety and exception handling of default value supplier
*
*
* {@code
* StringUtils.getIfEmpty(null, () -> "NULL") = "NULL"
* StringUtils.getIfEmpty("", () -> "NULL") = "NULL"
* StringUtils.getIfEmpty(" ", () -> "NULL") = " "
* StringUtils.getIfEmpty("bat", () -> "NULL") = "bat"
* StringUtils.getIfEmpty("", () -> null) = null
* StringUtils.getIfEmpty("", null) = null
* }
*
* @param the specific kind of CharSequence
* @param str the CharSequence to check, may be null
* @param defaultSupplier the supplier of default CharSequence to return
* if the input is empty ("") or {@code null}, may be null
* @return the passed in CharSequence, or the default
* @see StringUtils#defaultString(String, String)
* @since 3.10
*/
public static T getIfEmpty(final T str, final Supplier defaultSupplier) {
return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
}
/**
* Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
*
* The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
* Winkler increased this measure for matching initial characters.
*
* This implementation is based on the Jaro Winkler similarity algorithm
* from http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance.
*
*
* StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException
* StringUtils.getJaroWinklerDistance("", "") = 0.0
* StringUtils.getJaroWinklerDistance("", "a") = 0.0
* StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0
* StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93
* StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0
* StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
* StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
* StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
* StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88
* StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
* StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95
* StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
* StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
*
*
* @param first the first String, must not be null
* @param second the second String, must not be null
* @return result distance
* @throws IllegalArgumentException if either String input {@code null}
* @since 3.3
* @deprecated as of 3.6, use commons-text
*
* JaroWinklerDistance instead
*/
@Deprecated
public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
final double DEFAULT_SCALING_FACTOR = 0.1;
if (first == null || second == null) {
throw new IllegalArgumentException("Strings must not be null");
}
final int[] mtp = matches(first, second);
final double m = mtp[0];
if (m == 0) {
return 0D;
}
final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
return Math.round(jw * 100.0D) / 100.0D;
}
// Misc
//-----------------------------------------------------------------------
/**
* Find the Levenshtein distance between two Strings.
*
* This is the number of changes needed to change one String into
* another, where each change is a single character modification (deletion,
* insertion or substitution).
*
* The implementation uses a single-dimensional array of length s.length() + 1. See
*
* http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html for details.
*
*
* StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
* StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
* StringUtils.getLevenshteinDistance("", "") = 0
* StringUtils.getLevenshteinDistance("", "a") = 1
* StringUtils.getLevenshteinDistance("aaapppp", "") = 7
* StringUtils.getLevenshteinDistance("frog", "fog") = 1
* StringUtils.getLevenshteinDistance("fly", "ant") = 3
* StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
* StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
* StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
* StringUtils.getLevenshteinDistance("hello", "hallo") = 1
*
*
* @param s the first String, must not be null
* @param t the second String, must not be null
* @return result distance
* @throws IllegalArgumentException if either String input {@code null}
* @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
* getLevenshteinDistance(CharSequence, CharSequence)
* @deprecated as of 3.6, use commons-text
*
* LevenshteinDistance instead
*/
@Deprecated
public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
int n = s.length();
int m = t.length();
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
if (n > m) {
// swap the input strings to consume less memory
final CharSequence tmp = s;
s = t;
t = tmp;
n = m;
m = t.length();
}
final int p[] = new int[n + 1];
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
int upper_left;
int upper;
char t_j; // jth character of t
int cost;
for (i = 0; i <= n; i++) {
p[i] = i;
}
for (j = 1; j <= m; j++) {
upper_left = p[0];
t_j = t.charAt(j - 1);
p[0] = j;
for (i = 1; i <= n; i++) {
upper = p[i];
cost = s.charAt(i - 1) == t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
upper_left = upper;
}
}
return p[n];
}
/**
* Find the Levenshtein distance between two Strings if it's less than or equal to a given
* threshold.
*
* This is the number of changes needed to change one String into
* another, where each change is a single character modification (deletion,
* insertion or substitution).
*
* This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
* and Chas Emerick's implementation of the Levenshtein distance algorithm from
* http://www.merriampark.com/ld.htm
*
*
* StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
* StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
* StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
* StringUtils.getLevenshteinDistance("", "", 0) = 0
* StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
* StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
* StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
* StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
* StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
* StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
* StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
*
*
* @param s the first String, must not be null
* @param t the second String, must not be null
* @param threshold the target threshold, must not be negative
* @return result distance, or {@code -1} if the distance would be greater than the threshold
* @throws IllegalArgumentException if either String input {@code null} or negative threshold
* @deprecated as of 3.6, use commons-text
*
* LevenshteinDistance instead
*/
@Deprecated
public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
if (threshold < 0) {
throw new IllegalArgumentException("Threshold must not be negative");
}
/*
This implementation only computes the distance if it's less than or equal to the
threshold value, returning -1 if it's greater. The advantage is performance: unbounded
distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
computing a diagonal stripe of width 2k + 1 of the cost table.
It is also possible to use this to compute the unbounded Levenshtein distance by starting
the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
d is the distance.
One subtlety comes from needing to ignore entries on the border of our stripe
eg.
p[] = |#|#|#|*
d[] = *|#|#|#|
We must ignore the entry to the left of the leftmost member
We must ignore the entry above the rightmost member
Another subtlety comes from our stripe running off the matrix if the strings aren't
of the same size. Since string s is always swapped to be the shorter of the two,
the stripe will always run off to the upper right instead of the lower left of the matrix.
As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
In this case we're going to walk a stripe of length 3. The matrix would look like so:
1 2 3 4 5
1 |#|#| | | |
2 |#|#|#| | |
3 | |#|#|#| |
4 | | |#|#|#|
5 | | | |#|#|
6 | | | | |#|
7 | | | | | |
Note how the stripe leads off the table as there is no possible way to turn a string of length 5
into one of length 7 in edit distance of 1.
Additionally, this implementation decreases memory usage by using two
single-dimensional arrays and swapping them back and forth instead of allocating
an entire n by m matrix. This requires a few minor changes, such as immediately returning
when it's detected that the stripe has run off the matrix and initially filling the arrays with
large values so that entries we don't compute are ignored.
See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
*/
int n = s.length(); // length of s
int m = t.length(); // length of t
// if one string is empty, the edit distance is necessarily the length of the other
if (n == 0) {
return m <= threshold ? m : -1;
} else if (m == 0) {
return n <= threshold ? n : -1;
} else if (Math.abs(n - m) > threshold) {
// no need to calculate the distance if the length difference is greater than the threshold
return -1;
}
if (n > m) {
// swap the two strings to consume less memory
final CharSequence tmp = s;
s = t;
t = tmp;
n = m;
m = t.length();
}
int p[] = new int[n + 1]; // 'previous' cost array, horizontally
int d[] = new int[n + 1]; // cost array, horizontally
int _d[]; // placeholder to assist in swapping p and d
// fill in starting table values
final int boundary = Math.min(n, threshold) + 1;
for (int i = 0; i < boundary; i++) {
p[i] = i;
}
// these fills ensure that the value above the rightmost entry of our
// stripe will be ignored in following loop iterations
Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
Arrays.fill(d, Integer.MAX_VALUE);
// iterates through t
for (int j = 1; j <= m; j++) {
final char t_j = t.charAt(j - 1); // jth character of t
d[0] = j;
// compute stripe indices, constrain to array size
final int min = Math.max(1, j - threshold);
final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
// the stripe may lead off of the table if s and t are of different sizes
if (min > max) {
return -1;
}
// ignore entry left of leftmost
if (min > 1) {
d[min - 1] = Integer.MAX_VALUE;
}
// iterates through [min, max] in s
for (int i = min; i <= max; i++) {
if (s.charAt(i - 1) == t_j) {
// diagonally left and up
d[i] = p[i - 1];
} else {
// 1 + minimum of cell to the left, to the top, diagonally left and up
d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
}
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// if p[n] is greater than the threshold, there's no guarantee on it being the correct
// distance
if (p[n] <= threshold) {
return p[n];
}
return -1;
}
/**
* Finds the first index within a CharSequence, handling {@code null}.
* This method uses {@link String#indexOf(String, int)} if possible.
*
* A {@code null} CharSequence will return {@code -1}.
*
*
* StringUtils.indexOf(null, *) = -1
* StringUtils.indexOf(*, null) = -1
* StringUtils.indexOf("", "") = 0
* StringUtils.indexOf("", *) = -1 (except when * = "")
* StringUtils.indexOf("aabaabaa", "a") = 0
* StringUtils.indexOf("aabaabaa", "b") = 2
* StringUtils.indexOf("aabaabaa", "ab") = 1
* StringUtils.indexOf("aabaabaa", "") = 0
*
*
* @param seq the CharSequence to check, may be null
* @param searchSeq the CharSequence to find, may be null
* @return the first index of the search CharSequence,
* -1 if no match or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
*/
public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
if (seq == null || searchSeq == null) {
return INDEX_NOT_FOUND;
}
return CharSequenceUtils.indexOf(seq, searchSeq, 0);
}
/**
* Finds the first index within a CharSequence, handling {@code null}.
* This method uses {@link String#indexOf(String, int)} if possible.
*
* A {@code null} CharSequence will return {@code -1}.
* A negative start position is treated as zero.
* An empty ("") search CharSequence always matches.
* A start position greater than the string length only matches
* an empty search CharSequence.
*
*
* StringUtils.indexOf(null, *, *) = -1
* StringUtils.indexOf(*, null, *) = -1
* StringUtils.indexOf("", "", 0) = 0
* StringUtils.indexOf("", *, 0) = -1 (except when * = "")
* StringUtils.indexOf("aabaabaa", "a", 0) = 0
* StringUtils.indexOf("aabaabaa", "b", 0) = 2
* StringUtils.indexOf("aabaabaa", "ab", 0) = 1
* StringUtils.indexOf("aabaabaa", "b", 3) = 5
* StringUtils.indexOf("aabaabaa", "b", 9) = -1
* StringUtils.indexOf("aabaabaa", "b", -1) = 2
* StringUtils.indexOf("aabaabaa", "", 2) = 2
* StringUtils.indexOf("abc", "", 9) = 3
*
*
* @param seq the CharSequence to check, may be null
* @param searchSeq the CharSequence to find, may be null
* @param startPos the start position, negative treated as zero
* @return the first index of the search CharSequence (always ≥ startPos),
* -1 if no match or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
*/
public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
if (seq == null || searchSeq == null) {
return INDEX_NOT_FOUND;
}
return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
}
// IndexOf
//-----------------------------------------------------------------------
/**
* Returns the index within {@code seq} of the first occurrence of
* the specified character. If a character with value
* {@code searchChar} occurs in the character sequence represented by
* {@code seq} {@code CharSequence} object, then the index (in Unicode
* code units) of the first such occurrence is returned. For
* values of {@code searchChar} in the range from 0 to 0xFFFF
* (inclusive), this is the smallest value k such that:
*
* this.charAt(k) == searchChar
*
* is true. For other values of {@code searchChar}, it is the
* smallest value k such that:
*
* this.codePointAt(k) == searchChar
*
* is true. In either case, if no such character occurs in {@code seq},
* then {@code INDEX_NOT_FOUND (-1)} is returned.
*
* Furthermore, a {@code null} or empty ("") CharSequence will
* return {@code INDEX_NOT_FOUND (-1)}.
*
*
* StringUtils.indexOf(null, *) = -1
* StringUtils.indexOf("", *) = -1
* StringUtils.indexOf("aabaabaa", 'a') = 0
* StringUtils.indexOf("aabaabaa", 'b') = 2
*
*
* @param seq the CharSequence to check, may be null
* @param searchChar the character to find
* @return the first index of the search character,
* -1 if no match or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
* @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
*/
public static int indexOf(final CharSequence seq, final int searchChar) {
if (isEmpty(seq)) {
return INDEX_NOT_FOUND;
}
return CharSequenceUtils.indexOf(seq, searchChar, 0);
}
/**
*
* Returns the index within {@code seq} of the first occurrence of the
* specified character, starting the search at the specified index.
*
* If a character with value {@code searchChar} occurs in the
* character sequence represented by the {@code seq} {@code CharSequence}
* object at an index no smaller than {@code startPos}, then
* the index of the first such occurrence is returned. For values
* of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
* this is the smallest value k such that:
*
* (this.charAt(k) == searchChar) && (k >= startPos)
*
* is true. For other values of {@code searchChar}, it is the
* smallest value k such that:
*
* (this.codePointAt(k) == searchChar) && (k >= startPos)
*
* is true. In either case, if no such character occurs in {@code seq}
* at or after position {@code startPos}, then
* {@code -1} is returned.
*
*
* There is no restriction on the value of {@code startPos}. If it
* is negative, it has the same effect as if it were zero: this entire
* string may be searched. If it is greater than the length of this
* string, it has the same effect as if it were equal to the length of
* this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
* {@code null} or empty ("") CharSequence will
* return {@code (INDEX_NOT_FOUND) -1}.
*
*
All indices are specified in {@code char} values
* (Unicode code units).
*
*
* StringUtils.indexOf(null, *, *) = -1
* StringUtils.indexOf("", *, *) = -1
* StringUtils.indexOf("aabaabaa", 'b', 0) = 2
* StringUtils.indexOf("aabaabaa", 'b', 3) = 5
* StringUtils.indexOf("aabaabaa", 'b', 9) = -1
* StringUtils.indexOf("aabaabaa", 'b', -1) = 2
*
*
* @param seq the CharSequence to check, may be null
* @param searchChar the character to find
* @param startPos the start position, negative treated as zero
* @return the first index of the search character (always ≥ startPos),
* -1 if no match or {@code null} string input
* @since 2.0
* @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
* @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
*/
public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
if (isEmpty(seq)) {
return INDEX_NOT_FOUND;
}
return CharSequenceUtils.indexOf(seq, searchChar, startPos);
}
// IndexOfAny chars
//-----------------------------------------------------------------------
/**
* Search a CharSequence to find the first index of any
* character in the given set of characters.
*
* A {@code null} String will return {@code -1}.
* A {@code null} or zero length search array will return {@code -1}.
*
*
* StringUtils.indexOfAny(null, *) = -1
* StringUtils.indexOfAny("", *) = -1
* StringUtils.indexOfAny(*, null) = -1
* StringUtils.indexOfAny(*, []) = -1
* StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
* StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
* StringUtils.indexOfAny("aba", ['z']) = -1
*
*
* @param cs the CharSequence to check, may be null
* @param searchChars the chars to search for, may be null
* @return the index of any of the chars, -1 if no match or null input
* @since 2.0
* @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
*/
public static int indexOfAny(final CharSequence cs, final char... searchChars) {
if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
final int csLen = cs.length();
final int csLast = csLen - 1;
final int searchLen = searchChars.length;
final int searchLast = searchLen - 1;
for (int i = 0; i < csLen; i++) {
final char ch = cs.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
// ch is a supplementary character
if (searchChars[j + 1] == cs.charAt(i + 1)) {
return i;
}
} else {
return i;
}
}
}
}
return INDEX_NOT_FOUND;
}
// IndexOfAny strings
//-----------------------------------------------------------------------
/**
* Find the first index of any of a set of potential substrings.
*
* A {@code null} CharSequence will return {@code -1}.
* A {@code null} or zero length search array will return {@code -1}.
* A {@code null} search array entry will be ignored, but a search
* array containing "" will return {@code 0} if {@code str} is not
* null. This method uses {@link String#indexOf(String)} if possible.
*
*
* StringUtils.indexOfAny(null, *) = -1
* StringUtils.indexOfAny(*, null) = -1
* StringUtils.indexOfAny(*, []) = -1
* StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"]) = 2
* StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"]) = 2
* StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"]) = -1
* StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
* StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
* StringUtils.indexOfAny("", [""]) = 0
* StringUtils.indexOfAny("", ["a"]) = -1
*
*
* @param str the CharSequence to check, may be null
* @param searchStrs the CharSequences to search for, may be null
* @return the first index of any of the searchStrs in str, -1 if no match
* @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
*/
public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
if (str == null || searchStrs == null) {
return INDEX_NOT_FOUND;
}
// String's can't have a MAX_VALUEth index.
int ret = Integer.MAX_VALUE;
int tmp = 0;
for (final CharSequence search : searchStrs) {
if (search == null) {
continue;
}
tmp = CharSequenceUtils.indexOf(str, search, 0);
if (tmp == INDEX_NOT_FOUND) {
continue;
}
if (tmp < ret) {
ret = tmp;
}
}
return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
}
/**
* Search a CharSequence to find the first index of any
* character in the given set of characters.
*
* A {@code null} String will return {@code -1}.
* A {@code null} search string will return {@code -1}.
*
*
* StringUtils.indexOfAny(null, *) = -1
* StringUtils.indexOfAny("", *) = -1
* StringUtils.indexOfAny(*, null) = -1
* StringUtils.indexOfAny(*, "") = -1
* StringUtils.indexOfAny("zzabyycdxx", "za") = 0
* StringUtils.indexOfAny("zzabyycdxx", "by") = 3
* StringUtils.indexOfAny("aba", "z") = -1
*
*
* @param cs the CharSequence to check, may be null
* @param searchChars the chars to search for, may be null
* @return the index of any of the chars, -1 if no match or null input
* @since 2.0
* @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
*/
public static int indexOfAny(final CharSequence cs, final String searchChars) {
if (isEmpty(cs) || isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
return indexOfAny(cs, searchChars.toCharArray());
}
// IndexOfAnyBut chars
//-----------------------------------------------------------------------
/**
* Searches a CharSequence to find the first index of any
* character not in the given set of characters.
*
* A {@code null} CharSequence will return {@code -1}.
* A {@code null} or zero length search array will return {@code -1}.
*
*
* StringUtils.indexOfAnyBut(null, *) = -1
* StringUtils.indexOfAnyBut("", *) = -1
* StringUtils.indexOfAnyBut(*, null) = -1
* StringUtils.indexOfAnyBut(*, []) = -1
* StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
* StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
* StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
*
*
* @param cs the CharSequence to check, may be null
* @param searchChars the chars to search for, may be null
* @return the index of any of the chars, -1 if no match or null input
* @since 2.0
* @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
*/
public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
final int csLen = cs.length();
final int csLast = csLen - 1;
final int searchLen = searchChars.length;
final int searchLast = searchLen - 1;
outer:
for (int i = 0; i < csLen; i++) {
final char ch = cs.charAt(i);
for (int j = 0; j < searchLen; j++) {
if (searchChars[j] == ch) {
if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
if (searchChars[j + 1] == cs.charAt(i + 1)) {
continue outer;
}
} else {
continue outer;
}
}
}
return i;
}
return INDEX_NOT_FOUND;
}
/**
* Search a CharSequence to find the first index of any
* character not in the given set of characters.
*
* A {@code null} CharSequence will return {@code -1}.
* A {@code null} or empty search string will return {@code -1}.
*
*
* StringUtils.indexOfAnyBut(null, *) = -1
* StringUtils.indexOfAnyBut("", *) = -1
* StringUtils.indexOfAnyBut(*, null) = -1
* StringUtils.indexOfAnyBut(*, "") = -1
* StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
* StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
* StringUtils.indexOfAnyBut("aba", "ab") = -1
*
*
* @param seq the CharSequence to check, may be null
* @param searchChars the chars to search for, may be null
* @return the index of any of the chars, -1 if no match or null input
* @since 2.0
* @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
*/
public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
if (isEmpty(seq) || isEmpty(searchChars)) {
return INDEX_NOT_FOUND;
}
final int strLen = seq.length();
for (int i = 0; i < strLen; i++) {
final char ch = seq.charAt(i);
final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
final char ch2 = seq.charAt(i + 1);
if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
return i;
}
} else {
if (!chFound) {
return i;
}
}
}
return INDEX_NOT_FOUND;
}
/**
* Compares all CharSequences in an array and returns the index at which the
* CharSequences begin to differ.
*
* For example,
* {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
*
*
* StringUtils.indexOfDifference(null) = -1
* StringUtils.indexOfDifference(new String[] {}) = -1
* StringUtils.indexOfDifference(new String[] {"abc"}) = -1
* StringUtils.indexOfDifference(new String[] {null, null}) = -1
* StringUtils.indexOfDifference(new String[] {"", ""}) = -1
* StringUtils.indexOfDifference(new String[] {"", null}) = 0
* StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
* StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
* StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
* StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
* StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
* StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
* StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
* StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
* StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
* StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
* StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
*
*
* @param css array of CharSequences, entries may be null
* @return the index where the strings begin to differ; -1 if they are all equal
* @since 2.4
* @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
*/
public static int indexOfDifference(final CharSequence... css) {
if (ArrayUtils.getLength(css) <= 1) {
return INDEX_NOT_FOUND;
}
boolean anyStringNull = false;
boolean allStringsNull = true;
final int arrayLen = css.length;
int shortestStrLen = Integer.MAX_VALUE;
int longestStrLen = 0;
// find the min and max string lengths; this avoids checking to make
// sure we are not exceeding the length of the string each time through
// the bottom loop.
for (final CharSequence cs : css) {
if (cs == null) {
anyStringNull = true;
shortestStrLen = 0;
} else {
allStringsNull = false;
shortestStrLen = Math.min(cs.length(), shortestStrLen);
longestStrLen = Math.max(cs.length(), longestStrLen);
}
}
// handle lists containing all nulls or all empty strings
if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
return INDEX_NOT_FOUND;
}
// handle lists containing some nulls or some empty strings
if (shortestStrLen == 0) {
return 0;
}
// find the position with the first difference across all strings
int firstDiff = -1;
for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
final char comparisonChar = css[0].charAt(stringPos);
for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
if (css[arrayPos].charAt(stringPos) != comparisonChar) {
firstDiff = stringPos;
break;
}
}
if (firstDiff != -1) {
break;
}
}
if (firstDiff == -1 && shortestStrLen != longestStrLen) {
// we compared all of the characters up to the length of the
// shortest string and didn't find a match, but the string lengths
// vary, so return the length of the shortest string.
return shortestStrLen;
}
return firstDiff;
}
/**
* Compares two CharSequences, and returns the index at which the
* CharSequences begin to differ.
*
* For example,
* {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
*
*
* StringUtils.indexOfDifference(null, null) = -1
* StringUtils.indexOfDifference("", "") = -1
* StringUtils.indexOfDifference("", "abc") = 0
* StringUtils.indexOfDifference("abc", "") = 0
* StringUtils.indexOfDifference("abc", "abc") = -1
* StringUtils.indexOfDifference("ab", "abxyz") = 2
* StringUtils.indexOfDifference("abcde", "abxyz") = 2
* StringUtils.indexOfDifference("abcde", "xyz") = 0
*
*
* @param cs1 the first CharSequence, may be null
* @param cs2 the second CharSequence, may be null
* @return the index where cs1 and cs2 begin to differ; -1 if they are equal
* @since 2.0
* @since 3.0 Changed signature from indexOfDifference(String, String) to
* indexOfDifference(CharSequence, CharSequence)
*/
public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return INDEX_NOT_FOUND;
}
if (cs1 == null || cs2 == null) {
return 0;
}
int i;
for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
if (cs1.charAt(i) != cs2.charAt(i)) {
break;
}
}
if (i < cs2.length() || i < cs1.length()) {
return i;
}
return INDEX_NOT_FOUND;
}
/**
* Case in-sensitive find of the first index within a CharSequence.
*
* A {@code null} CharSequence will return {@code -1}.
* A negative start position is treated as zero.
* An empty ("") search CharSequence always matches.
* A start position greater than the string length only matches
* an empty search CharSequence.
*
*
* StringUtils.indexOfIgnoreCase(null, *) = -1
* StringUtils.indexOfIgnoreCase(*, null) = -1
* StringUtils.indexOfIgnoreCase("", "") = 0
* StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
* StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
* StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
*
*
* @param str the CharSequence to check, may be null
* @param searchStr the CharSequence to find, may be null
* @return the first index of the search CharSequence,
* -1 if no match or {@code null} string input
* @since 2.5
* @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
*/
public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
return indexOfIgnoreCase(str, searchStr, 0);
}
/**
* Case in-sensitive find of the first index within a CharSequence
* from the specified position.
*
* A {@code null} CharSequence will return {@code -1}.
* A negative start position is treated as zero.
* An empty ("") search CharSequence always matches.
* A start position greater than the string length only matches
* an empty search CharSequence.
*
*
* StringUtils.indexOfIgnoreCase(null, *, *) = -1
* StringUtils.indexOfIgnoreCase(*, null, *) = -1
* StringUtils.indexOfIgnoreCase("", "", 0) = 0
* StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
* StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
* StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
* StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
* StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
* StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
* StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
* StringUtils.indexOfIgnoreCase("abc", "", 9) = -1
*
*
* @param str the CharSequence to check, may be null
* @param searchStr the CharSequence to find, may be null
* @param startPos the start position, negative treated as zero
* @return the first index of the search CharSequence (always ≥ startPos),
* -1 if no match or {@code null} string input
* @since 2.5
* @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
*/
public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
if (str == null || searchStr == null) {
return INDEX_NOT_FOUND;
}
if (startPos < 0) {
startPos = 0;
}
final int endLimit = str.length() - searchStr.length() + 1;
if (startPos > endLimit) {
return INDEX_NOT_FOUND;
}
if (searchStr.length() == 0) {
return startPos;
}
for (int i = startPos; i < endLimit; i++) {
if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
return i;
}
}
return INDEX_NOT_FOUND;
}
/**
* Checks if all of the CharSequences are empty (""), null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.isAllBlank(null) = true
* StringUtils.isAllBlank(null, "foo") = false
* StringUtils.isAllBlank(null, null) = true
* StringUtils.isAllBlank("", "bar") = false
* StringUtils.isAllBlank("bob", "") = false
* StringUtils.isAllBlank(" bob ", null) = false
* StringUtils.isAllBlank(" ", "bar") = false
* StringUtils.isAllBlank("foo", "bar") = false
* StringUtils.isAllBlank(new String[] {}) = true
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if all of the CharSequences are empty or null or whitespace only
* @since 3.6
*/
public static boolean isAllBlank(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotBlank(cs)) {
return false;
}
}
return true;
}
/**
* Checks if all of the CharSequences are empty ("") or null.
*
*
* StringUtils.isAllEmpty(null) = true
* StringUtils.isAllEmpty(null, "") = true
* StringUtils.isAllEmpty(new String[] {}) = true
* StringUtils.isAllEmpty(null, "foo") = false
* StringUtils.isAllEmpty("", "bar") = false
* StringUtils.isAllEmpty("bob", "") = false
* StringUtils.isAllEmpty(" bob ", null) = false
* StringUtils.isAllEmpty(" ", "bar") = false
* StringUtils.isAllEmpty("foo", "bar") = false
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if all of the CharSequences are empty or null
* @since 3.6
*/
public static boolean isAllEmpty(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotEmpty(cs)) {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only lowercase characters.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code false}.
*
*
* StringUtils.isAllLowerCase(null) = false
* StringUtils.isAllLowerCase("") = false
* StringUtils.isAllLowerCase(" ") = false
* StringUtils.isAllLowerCase("abc") = true
* StringUtils.isAllLowerCase("abC") = false
* StringUtils.isAllLowerCase("ab c") = false
* StringUtils.isAllLowerCase("ab1c") = false
* StringUtils.isAllLowerCase("ab/c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains lowercase characters, and is non-null
* @since 2.5
* @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
*/
public static boolean isAllLowerCase(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isLowerCase(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only uppercase characters.
*
* {@code null} will return {@code false}.
* An empty String (length()=0) will return {@code false}.
*
*
* StringUtils.isAllUpperCase(null) = false
* StringUtils.isAllUpperCase("") = false
* StringUtils.isAllUpperCase(" ") = false
* StringUtils.isAllUpperCase("ABC") = true
* StringUtils.isAllUpperCase("aBC") = false
* StringUtils.isAllUpperCase("A C") = false
* StringUtils.isAllUpperCase("A1C") = false
* StringUtils.isAllUpperCase("A/C") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains uppercase characters, and is non-null
* @since 2.5
* @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
*/
public static boolean isAllUpperCase(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isUpperCase(cs.charAt(i))) {
return false;
}
}
return true;
}
// Character Tests
//-----------------------------------------------------------------------
/**
* Checks if the CharSequence contains only Unicode letters.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code false}.
*
*
* StringUtils.isAlpha(null) = false
* StringUtils.isAlpha("") = false
* StringUtils.isAlpha(" ") = false
* StringUtils.isAlpha("abc") = true
* StringUtils.isAlpha("ab2c") = false
* StringUtils.isAlpha("ab-c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains letters, and is non-null
* @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
* @since 3.0 Changed "" to return false and not true
*/
public static boolean isAlpha(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isLetter(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only Unicode letters or digits.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code false}.
*
*
* StringUtils.isAlphanumeric(null) = false
* StringUtils.isAlphanumeric("") = false
* StringUtils.isAlphanumeric(" ") = false
* StringUtils.isAlphanumeric("abc") = true
* StringUtils.isAlphanumeric("ab c") = false
* StringUtils.isAlphanumeric("ab2c") = true
* StringUtils.isAlphanumeric("ab-c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains letters or digits,
* and is non-null
* @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
* @since 3.0 Changed "" to return false and not true
*/
public static boolean isAlphanumeric(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isLetterOrDigit(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only Unicode letters, digits
* or space ({@code ' '}).
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code true}.
*
*
* StringUtils.isAlphanumericSpace(null) = false
* StringUtils.isAlphanumericSpace("") = true
* StringUtils.isAlphanumericSpace(" ") = true
* StringUtils.isAlphanumericSpace("abc") = true
* StringUtils.isAlphanumericSpace("ab c") = true
* StringUtils.isAlphanumericSpace("ab2c") = true
* StringUtils.isAlphanumericSpace("ab-c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains letters, digits or space,
* and is non-null
* @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
*/
public static boolean isAlphanumericSpace(final CharSequence cs) {
if (cs == null) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only Unicode letters and
* space (' ').
*
* {@code null} will return {@code false}
* An empty CharSequence (length()=0) will return {@code true}.
*
*
* StringUtils.isAlphaSpace(null) = false
* StringUtils.isAlphaSpace("") = true
* StringUtils.isAlphaSpace(" ") = true
* StringUtils.isAlphaSpace("abc") = true
* StringUtils.isAlphaSpace("ab c") = true
* StringUtils.isAlphaSpace("ab2c") = false
* StringUtils.isAlphaSpace("ab-c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains letters and space,
* and is non-null
* @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
*/
public static boolean isAlphaSpace(final CharSequence cs) {
if (cs == null) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') {
return false;
}
}
return true;
}
/**
* Checks if any of the CharSequences are empty ("") or null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.isAnyBlank((String) null) = true
* StringUtils.isAnyBlank((String[]) null) = false
* StringUtils.isAnyBlank(null, "foo") = true
* StringUtils.isAnyBlank(null, null) = true
* StringUtils.isAnyBlank("", "bar") = true
* StringUtils.isAnyBlank("bob", "") = true
* StringUtils.isAnyBlank(" bob ", null) = true
* StringUtils.isAnyBlank(" ", "bar") = true
* StringUtils.isAnyBlank(new String[] {}) = false
* StringUtils.isAnyBlank(new String[]{""}) = true
* StringUtils.isAnyBlank("foo", "bar") = false
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if any of the CharSequences are empty or null or whitespace only
* @since 3.2
*/
public static boolean isAnyBlank(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isBlank(cs)) {
return true;
}
}
return false;
}
/**
* Checks if any of the CharSequences are empty ("") or null.
*
*
* StringUtils.isAnyEmpty((String) null) = true
* StringUtils.isAnyEmpty((String[]) null) = false
* StringUtils.isAnyEmpty(null, "foo") = true
* StringUtils.isAnyEmpty("", "bar") = true
* StringUtils.isAnyEmpty("bob", "") = true
* StringUtils.isAnyEmpty(" bob ", null) = true
* StringUtils.isAnyEmpty(" ", "bar") = false
* StringUtils.isAnyEmpty("foo", "bar") = false
* StringUtils.isAnyEmpty(new String[]{}) = false
* StringUtils.isAnyEmpty(new String[]{""}) = true
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if any of the CharSequences are empty or null
* @since 3.2
*/
public static boolean isAnyEmpty(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isEmpty(cs)) {
return true;
}
}
return false;
}
/**
* Checks if the CharSequence contains only ASCII printable characters.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code true}.
*
*
* StringUtils.isAsciiPrintable(null) = false
* StringUtils.isAsciiPrintable("") = true
* StringUtils.isAsciiPrintable(" ") = true
* StringUtils.isAsciiPrintable("Ceki") = true
* StringUtils.isAsciiPrintable("ab2c") = true
* StringUtils.isAsciiPrintable("!ab-c~") = true
* StringUtils.isAsciiPrintable("\u0020") = true
* StringUtils.isAsciiPrintable("\u0021") = true
* StringUtils.isAsciiPrintable("\u007e") = true
* StringUtils.isAsciiPrintable("\u007f") = false
* StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if every character is in the range
* 32 thru 126
* @since 2.1
* @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
*/
public static boolean isAsciiPrintable(final CharSequence cs) {
if (cs == null) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
return false;
}
}
return true;
}
// Nested extraction
//-----------------------------------------------------------------------
/**
* Checks if a CharSequence is empty (""), null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.isBlank(null) = true
* StringUtils.isBlank("") = true
* StringUtils.isBlank(" ") = true
* StringUtils.isBlank("bob") = false
* StringUtils.isBlank(" bob ") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is null, empty or whitespace only
* @since 2.0
* @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
*/
public static boolean isBlank(final CharSequence cs) {
final int strLen = length(cs);
if (strLen == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
// Empty checks
//-----------------------------------------------------------------------
/**
* Checks if a CharSequence is empty ("") or null.
*
*
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
*
*
* NOTE: This method changed in Lang version 2.0.
* It no longer trims the CharSequence.
* That functionality is available in isBlank().
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is empty or null
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
*/
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
/**
* Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
*
* {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
* {@code false}.
*
*
* StringUtils.isMixedCase(null) = false
* StringUtils.isMixedCase("") = false
* StringUtils.isMixedCase("ABC") = false
* StringUtils.isMixedCase("abc") = false
* StringUtils.isMixedCase("aBc") = true
* StringUtils.isMixedCase("A c") = true
* StringUtils.isMixedCase("A1c") = true
* StringUtils.isMixedCase("a/C") = true
* StringUtils.isMixedCase("aC\t") = true
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence contains both uppercase and lowercase characters
* @since 3.5
*/
public static boolean isMixedCase(final CharSequence cs) {
if (isEmpty(cs) || cs.length() == 1) {
return false;
}
boolean containsUppercase = false;
boolean containsLowercase = false;
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (containsUppercase && containsLowercase) {
return true;
} else if (Character.isUpperCase(cs.charAt(i))) {
containsUppercase = true;
} else if (Character.isLowerCase(cs.charAt(i))) {
containsLowercase = true;
}
}
return containsUppercase && containsLowercase;
}
/**
* Checks if none of the CharSequences are empty (""), null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.isNoneBlank((String) null) = false
* StringUtils.isNoneBlank((String[]) null) = true
* StringUtils.isNoneBlank(null, "foo") = false
* StringUtils.isNoneBlank(null, null) = false
* StringUtils.isNoneBlank("", "bar") = false
* StringUtils.isNoneBlank("bob", "") = false
* StringUtils.isNoneBlank(" bob ", null) = false
* StringUtils.isNoneBlank(" ", "bar") = false
* StringUtils.isNoneBlank(new String[] {}) = true
* StringUtils.isNoneBlank(new String[]{""}) = false
* StringUtils.isNoneBlank("foo", "bar") = true
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if none of the CharSequences are empty or null or whitespace only
* @since 3.2
*/
public static boolean isNoneBlank(final CharSequence... css) {
return !isAnyBlank(css);
}
/**
* Checks if none of the CharSequences are empty ("") or null.
*
*
* StringUtils.isNoneEmpty((String) null) = false
* StringUtils.isNoneEmpty((String[]) null) = true
* StringUtils.isNoneEmpty(null, "foo") = false
* StringUtils.isNoneEmpty("", "bar") = false
* StringUtils.isNoneEmpty("bob", "") = false
* StringUtils.isNoneEmpty(" bob ", null) = false
* StringUtils.isNoneEmpty(new String[] {}) = true
* StringUtils.isNoneEmpty(new String[]{""}) = false
* StringUtils.isNoneEmpty(" ", "bar") = true
* StringUtils.isNoneEmpty("foo", "bar") = true
*
*
* @param css the CharSequences to check, may be null or empty
* @return {@code true} if none of the CharSequences are empty or null
* @since 3.2
*/
public static boolean isNoneEmpty(final CharSequence... css) {
return !isAnyEmpty(css);
}
/**
* Checks if a CharSequence is not empty (""), not null and not whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.isNotBlank(null) = false
* StringUtils.isNotBlank("") = false
* StringUtils.isNotBlank(" ") = false
* StringUtils.isNotBlank("bob") = true
* StringUtils.isNotBlank(" bob ") = true
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is
* not empty and not null and not whitespace only
* @since 2.0
* @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
*/
public static boolean isNotBlank(final CharSequence cs) {
return !isBlank(cs);
}
/**
* Checks if a CharSequence is not empty ("") and not null.
*
*
* StringUtils.isNotEmpty(null) = false
* StringUtils.isNotEmpty("") = false
* StringUtils.isNotEmpty(" ") = true
* StringUtils.isNotEmpty("bob") = true
* StringUtils.isNotEmpty(" bob ") = true
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is not empty and not null
* @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
*/
public static boolean isNotEmpty(final CharSequence cs) {
return !isEmpty(cs);
}
/**
* Checks if the CharSequence contains only Unicode digits.
* A decimal point is not a Unicode digit and returns false.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code false}.
*
* Note that the method does not allow for a leading sign, either positive or negative.
* Also, if a String passes the numeric test, it may still generate a NumberFormatException
* when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
* for int or long respectively.
*
*
* StringUtils.isNumeric(null) = false
* StringUtils.isNumeric("") = false
* StringUtils.isNumeric(" ") = false
* StringUtils.isNumeric("123") = true
* StringUtils.isNumeric("\u0967\u0968\u0969") = true
* StringUtils.isNumeric("12 3") = false
* StringUtils.isNumeric("ab2c") = false
* StringUtils.isNumeric("12-3") = false
* StringUtils.isNumeric("12.3") = false
* StringUtils.isNumeric("-123") = false
* StringUtils.isNumeric("+123") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains digits, and is non-null
* @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
* @since 3.0 Changed "" to return false and not true
*/
public static boolean isNumeric(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isDigit(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only Unicode digits or space
* ({@code ' '}).
* A decimal point is not a Unicode digit and returns false.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code true}.
*
*
* StringUtils.isNumericSpace(null) = false
* StringUtils.isNumericSpace("") = true
* StringUtils.isNumericSpace(" ") = true
* StringUtils.isNumericSpace("123") = true
* StringUtils.isNumericSpace("12 3") = true
* StringUtils.isNumeric("\u0967\u0968\u0969") = true
* StringUtils.isNumeric("\u0967\u0968 \u0969") = true
* StringUtils.isNumericSpace("ab2c") = false
* StringUtils.isNumericSpace("12-3") = false
* StringUtils.isNumericSpace("12.3") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains digits or space,
* and is non-null
* @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
*/
public static boolean isNumericSpace(final CharSequence cs) {
if (cs == null) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
return false;
}
}
return true;
}
/**
* Checks if the CharSequence contains only whitespace.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* {@code null} will return {@code false}.
* An empty CharSequence (length()=0) will return {@code true}.
*
*
* StringUtils.isWhitespace(null) = false
* StringUtils.isWhitespace("") = true
* StringUtils.isWhitespace(" ") = true
* StringUtils.isWhitespace("abc") = false
* StringUtils.isWhitespace("ab2c") = false
* StringUtils.isWhitespace("ab-c") = false
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if only contains whitespace, and is non-null
* @since 2.0
* @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
*/
public static boolean isWhitespace(final CharSequence cs) {
if (cs == null) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final byte[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final char[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final double[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final float[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final int[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
* Joins the elements of the provided {@code Iterable} into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list. Null objects or empty
* strings within the iteration are represented by empty strings.
*
* See the examples here: {@link #join(Object[],char)}.
*
* @param iterable the {@code Iterable} providing the values to join together, may be null
* @param separator the separator character to use
* @return the joined String, {@code null} if null iterator input
* @since 2.3
*/
public static String join(final Iterable> iterable, final char separator) {
if (iterable == null) {
return null;
}
return join(iterable.iterator(), separator);
}
/**
* Joins the elements of the provided {@code Iterable} into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list.
* A {@code null} separator is the same as an empty String ("").
*
* See the examples here: {@link #join(Object[],String)}.
*
* @param iterable the {@code Iterable} providing the values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, {@code null} if null iterator input
* @since 2.3
*/
public static String join(final Iterable> iterable, final String separator) {
if (iterable == null) {
return null;
}
return join(iterable.iterator(), separator);
}
/**
* Joins the elements of the provided {@code Iterator} into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list. Null objects or empty
* strings within the iteration are represented by empty strings.
*
* See the examples here: {@link #join(Object[],char)}.
*
* @param iterator the {@code Iterator} of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, {@code null} if null iterator input
* @since 2.0
*/
public static String join(final Iterator> iterator, final char separator) {
// handle null, zero and one elements before building a buffer
if (iterator == null) {
return null;
}
if (!iterator.hasNext()) {
return EMPTY;
}
final Object first = iterator.next();
if (!iterator.hasNext()) {
return Objects.toString(first, EMPTY);
}
// two or more elements
final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
buf.append(separator);
final Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided {@code Iterator} into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list.
* A {@code null} separator is the same as an empty String ("").
*
* See the examples here: {@link #join(Object[],String)}.
*
* @param iterator the {@code Iterator} of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, {@code null} if null iterator input
*/
public static String join(final Iterator> iterator, final String separator) {
// handle null, zero and one elements before building a buffer
if (iterator == null) {
return null;
}
if (!iterator.hasNext()) {
return EMPTY;
}
final Object first = iterator.next();
if (!iterator.hasNext()) {
return Objects.toString(first, "");
}
// two or more elements
final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
if (separator != null) {
buf.append(separator);
}
final Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided {@code List} into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join([null, "", "a"], ';') = ";;a"
*
*
* @param list the {@code List} of values to join together, may be null
* @param separator the separator character to use
* @param startIndex the first index to start joining from. It is
* an error to pass in a start index past the end of the list
* @param endIndex the index to stop joining from (exclusive). It is
* an error to pass in an end index past the end of the list
* @return the joined String, {@code null} if null list input
* @since 3.8
*/
public static String join(final List> list, final char separator, final int startIndex, final int endIndex) {
if (list == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final List> subList = list.subList(startIndex, endIndex);
return join(subList.iterator(), separator);
}
/**
* Joins the elements of the provided {@code List} into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join([null, "", "a"], ';') = ";;a"
*
*
* @param list the {@code List} of values to join together, may be null
* @param separator the separator character to use
* @param startIndex the first index to start joining from. It is
* an error to pass in a start index past the end of the list
* @param endIndex the index to stop joining from (exclusive). It is
* an error to pass in an end index past the end of the list
* @return the joined String, {@code null} if null list input
* @since 3.8
*/
public static String join(final List> list, final String separator, final int startIndex, final int endIndex) {
if (list == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final List> subList = list.subList(startIndex, endIndex);
return join(subList.iterator(), separator);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final long[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join([null, "", "a"], ';') = ";;a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, {@code null} if null array input
* @since 2.0
*/
public static String join(final Object[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join([null, "", "a"], ';') = ";;a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use
* @param startIndex the first index to start joining from. It is
* an error to pass in a start index past the end of the array
* @param endIndex the index to stop joining from (exclusive). It is
* an error to pass in an end index past the end of the array
* @return the joined String, {@code null} if null array input
* @since 2.0
*/
public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
if (array[startIndex] != null) {
buf.append(array[startIndex]);
}
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* A {@code null} separator is the same as an empty String ("").
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join(["a", "b", "c"], "") = "abc"
* StringUtils.join([null, "", "a"], ',') = ",,a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, {@code null} if null array input
*/
public static String join(final Object[] array, final String separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* A {@code null} separator is the same as an empty String ("").
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *, *, *) = null
* StringUtils.join([], *, *, *) = ""
* StringUtils.join([null], *, *, *) = ""
* StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c"
* StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c"
* StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c"
* StringUtils.join(["a", "b", "c"], "--", 2, 2) = ""
* StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc"
* StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc"
* StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @param startIndex the first index to start joining from.
* @param endIndex the index to stop joining from (exclusive).
* @return the joined String, {@code null} if null array input; or the empty string
* if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
* {@code endIndex - startIndex}
* @throws ArrayIndexOutOfBoundsException ife
* {@code startIndex < 0} or
* {@code startIndex >= array.length()} or
* {@code endIndex < 0} or
* {@code endIndex > array.length()}
*/
public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
if (separator == null) {
separator = EMPTY;
}
// endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
// (Assuming that all Strings are roughly equally long)
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
if (array[startIndex] != null) {
buf.append(array[startIndex]);
}
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final short[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
/**
*
* Joins the elements of the provided array into a single String containing the provided list of elements.
*
*
*
* No delimiter is added before or after the list. Null objects or empty strings within the array are represented
* by empty strings.
*
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join([1, 2, 3], ';') = "1;2;3"
* StringUtils.join([1, 2, 3], null) = "123"
*
*
* @param array
* the array of values to join together, may be null
* @param separator
* the separator character to use
* @param startIndex
* the first index to start joining from. It is an error to pass in a start index past the end of the
* array
* @param endIndex
* the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
* the array
* @return the joined String, {@code null} if null array input
* @since 3.2
*/
public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = newStringBuilder(noOfItems);
buf.append(array[startIndex]);
for (int i = startIndex + 1; i < endIndex; i++) {
buf.append(separator);
buf.append(array[i]);
}
return buf.toString();
}
// Joining
//-----------------------------------------------------------------------
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No separator is added to the joined String.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null) = null
* StringUtils.join([]) = ""
* StringUtils.join([null]) = ""
* StringUtils.join(["a", "b", "c"]) = "abc"
* StringUtils.join([null, "", "a"]) = "a"
*
*
* @param the specific type of values to join together
* @param elements the values to join together, may be null
* @return the joined String, {@code null} if null array input
* @since 2.0
* @since 3.0 Changed signature to use varargs
*/
@SafeVarargs
public static String join(final T... elements) {
return join(elements, null);
}
/**
* Joins the elements of the provided varargs into a
* single String containing the provided elements.
*
* No delimiter is added before or after the list.
* {@code null} elements and separator are treated as empty Strings ("").
*
*
* StringUtils.joinWith(",", {"a", "b"}) = "a,b"
* StringUtils.joinWith(",", {"a", "b",""}) = "a,b,"
* StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b"
* StringUtils.joinWith(null, {"a", "b"}) = "ab"
*
*
* @param separator the separator character to use, null treated as ""
* @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
* @return the joined String.
* @throws java.lang.IllegalArgumentException if a null varargs is provided
* @since 3.5
*/
public static String joinWith(final String separator, final Object... objects) {
if (objects == null) {
throw new IllegalArgumentException("Object varargs must not be null");
}
final String sanitizedSeparator = defaultString(separator);
final StringBuilder result = new StringBuilder();
final Iterator