Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.util.Strings Maven / Gradle / Ivy
Go to download
A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.
/*
* Copyright (c) 2015, Haiyang Li.
*
* Licensed 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 com.landawn.abacus.util;
import static com.landawn.abacus.util.WD._BACKSLASH;
import static com.landawn.abacus.util.WD._QUOTATION_D;
import static com.landawn.abacus.util.WD._QUOTATION_S;
import static java.util.logging.Level.WARNING;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.RandomAccess;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalChar;
/**
*
* Note: This class includes codes copied from Apache Commons Lang, Google Guava and other open source projects under the Apache License 2.0.
* The methods copied from other libraries/frameworks/projects may be modified in this class.
*
*
*
* @see {@code Joiner}, {@code Splitter}
*
* @see com.landawn.abacus.util.N
* @see com.landawn.abacus.util.Array
* @see com.landawn.abacus.util.Iterables
* @see com.landawn.abacus.util.Iterators
* @see com.landawn.abacus.util.Maps
*/
public abstract class Strings {
public static final String ELEMENT_SEPARATOR = ", ".intern();
static final char[] ELEMENT_SEPARATOR_CHAR_ARRAY = ELEMENT_SEPARATOR.toCharArray();
/**
* String with value {@code "null"}.
*/
public static final String NULL_STRING = "null".intern();
/**
*
* Char array with value {@code "['n', 'u', 'l', 'l']"}.
*/
static final char[] NULL_CHAR_ARRAY = NULL_STRING.toCharArray();
/**
* The empty String {@code ""}.
* @since 2.0
*/
public static final String EMPTY = N.EMPTY_STRING;
/**
* A String for a space character.
*
* @since 3.2
*/
public static final String SPACE = WD.SPACE;
/**
* 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";
@Beta
public static final char CHAR_ZERO = (char) 0;
@Beta
public static final char CHAR_SPACE = SPACE.charAt(0);
@Beta
public static final char CHAR_LF = LF.charAt(0);
@Beta
public static final char CHAR_CR = CR.charAt(0);
/**
* A regex pattern for recognizing blocks of whitespace characters. The
* apparent convolutedness of the pattern serves the purpose of ignoring
* "blocks" consisting of only a single space: the pattern is used only to
* normalize whitespace, condensing "blocks" down to a single space, thus
* matching the same would likely cause a great many noop replacements.
*/
private static final Pattern WHITESPACE_PATTERN = Pattern.compile("(?: |\\u00A0|\\s|[\\s&&[^ ]])\\s*");
private static final Map splitterPool = new HashMap<>();
private static final Map trimSplitterPool = new HashMap<>();
private static final Map preserveSplitterPool = new HashMap<>();
private static final Map trimPreserveSplitterPool = new HashMap<>();
static {
final List delimiters = Array.asList(" ", " ", " ", "\t", "\n", "\r", ",", ", ", ";", "; ", ":", ": ", " : ", "-", " - ", "_", " _ ", "#",
"##", " # ", "=", "==", " = ", "|", " | ", "||", " || ", "&", "&&", "@", "@@", "$", "$$", "*", "**", "+", "++");
for (String delimiter : delimiters) {
splitterPool.put(delimiter, Splitter.with(delimiter).omitEmptyStrings());
trimSplitterPool.put(delimiter, Splitter.with(delimiter).omitEmptyStrings().trimResults());
preserveSplitterPool.put(delimiter, Splitter.with(delimiter));
trimPreserveSplitterPool.put(delimiter, Splitter.with(delimiter).trimResults());
if (delimiter.length() == 1) {
char delimiterChar = delimiter.charAt(0);
splitterPool.put(delimiterChar, Splitter.with(delimiterChar).omitEmptyStrings());
trimSplitterPool.put(delimiterChar, Splitter.with(delimiterChar).omitEmptyStrings().trimResults());
preserveSplitterPool.put(delimiterChar, Splitter.with(delimiterChar));
trimPreserveSplitterPool.put(delimiterChar, Splitter.with(delimiterChar).trimResults());
}
}
}
private static final Pattern JAVA_IDENTIFIER_PATTERN = Pattern.compile("^([a-zA-Z_$][a-zA-Z\\d_$]*)$");
private Strings() {
// Utility class.
}
/**
* Returns the string representation of the {@code char} array or null.
*
* @param value the character array.
* @return a String or null
* @see String#valueOf(char[])
* @since 3.9
*/
public static String valueOf(final char[] value) {
return value == null ? null : String.valueOf(value);
}
public static boolean isValidJavaIdentifier(String str) {
if (N.isNullOrEmpty(str)) {
return false;
}
return JAVA_IDENTIFIER_PATTERN.matcher(str).matches();
}
/**
* Same as {@code N.isNullOrEmpty(CharSequence)}.
*
* @param cs
* @return
* @see N#isNullOrEmpty(CharSequence)
*/
public static boolean isEmpty(final CharSequence cs) {
return (cs == null) || (cs.length() == 0);
}
/**
* Same as {@code N.isNullOrEmptyOrBlank(CharSequence)}.
*
* @param cs
* @return
* @see N#isNullOrEmptyOrBlank(CharSequence)
*/
public static boolean isBlank(final CharSequence cs) {
return N.isNullOrEmptyOrBlank(cs);
}
/**
* Same as {@code N.notNullOrEmpty(CharSequence)}.
*
* @param cs
* @return
* @see N#notNullOrEmpty(CharSequence)
*/
public static boolean isNotEmpty(final CharSequence cs) {
return (cs != null) && (cs.length() > 0);
}
/**
* Same as {@code N.notNullOrEmptyOrBlank(CharSequence)}.
*
* @param cs
* @return
* @see N#notNullOrEmptyOrBlank(CharSequence)
*/
public static boolean isNotBlank(final CharSequence cs) {
return N.notNullOrEmptyOrBlank(cs);
}
/**
* Checks if all of the CharSequences are empty ("") or null.
*
*
* StringUtil.isAllEmpty(null) = true
* StringUtil.isAllEmpty(null, "") = true
* StringUtil.isAllEmpty(new String[] {}) = true
* StringUtil.isAllEmpty(null, "foo") = false
* StringUtil.isAllEmpty("", "bar") = false
* StringUtil.isAllEmpty("bob", "") = false
* StringUtil.isAllEmpty(" bob ", null) = false
* StringUtil.isAllEmpty(" ", "bar") = false
* StringUtil.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 (N.isNullOrEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotEmpty(cs)) {
return false;
}
}
return true;
}
public static boolean isAllEmpty(final Collection extends CharSequence> css) {
if (N.isNullOrEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotEmpty(cs)) {
return false;
}
}
return true;
}
/**
* Checks if all of the CharSequences are empty (""), null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtil.isAllBlank(null) = true
* StringUtil.isAllBlank(null, "foo") = false
* StringUtil.isAllBlank(null, null) = true
* StringUtil.isAllBlank("", "bar") = false
* StringUtil.isAllBlank("bob", "") = false
* StringUtil.isAllBlank(" bob ", null) = false
* StringUtil.isAllBlank(" ", "bar") = false
* StringUtil.isAllBlank("foo", "bar") = false
* StringUtil.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 (N.isNullOrEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotBlank(cs)) {
return false;
}
}
return true;
}
public static boolean isAllBlank(final Collection extends CharSequence> css) {
if (N.isNullOrEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotBlank(cs)) {
return false;
}
}
return true;
}
/**
* Checks if any of the CharSequences are empty ("") or null.
*
*
* StringUtil.isAnyEmpty((String) null) = true
* StringUtil.isAnyEmpty((String[]) null) = false
* StringUtil.isAnyEmpty(null, "foo") = true
* StringUtil.isAnyEmpty("", "bar") = true
* StringUtil.isAnyEmpty("bob", "") = true
* StringUtil.isAnyEmpty(" bob ", null) = true
* StringUtil.isAnyEmpty(" ", "bar") = false
* StringUtil.isAnyEmpty("foo", "bar") = false
* StringUtil.isAnyEmpty(new String[]{}) = false
* StringUtil.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 (N.isNullOrEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isEmpty(cs)) {
return true;
}
}
return false;
}
public static boolean isAnyEmpty(final Collection extends CharSequence> css) {
if (N.isNullOrEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isEmpty(cs)) {
return true;
}
}
return false;
}
/**
* Checks if any of the CharSequences are empty ("") or null or whitespace only.
*
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtil.isAnyBlank((String) null) = true
* StringUtil.isAnyBlank((String[]) null) = false
* StringUtil.isAnyBlank(null, "foo") = true
* StringUtil.isAnyBlank(null, null) = true
* StringUtil.isAnyBlank("", "bar") = true
* StringUtil.isAnyBlank("bob", "") = true
* StringUtil.isAnyBlank(" bob ", null) = true
* StringUtil.isAnyBlank(" ", "bar") = true
* StringUtil.isAnyBlank(new String[] {}) = false
* StringUtil.isAnyBlank(new String[]{""}) = true
* StringUtil.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 (N.isNullOrEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isBlank(cs)) {
return true;
}
}
return false;
}
public static boolean isAnyBlank(final Collection extends CharSequence> css) {
if (N.isNullOrEmpty(css)) {
return false;
}
for (final CharSequence cs : css) {
if (isBlank(cs)) {
return true;
}
}
return false;
}
/**
* Same as {@code N.defaultIfNullOrEmpty(CharSequence, CharSequence)}.
*
* @param
* @param str
* @param defaultStr
* @return
* @see N#defaultIfNullOrEmpty(CharSequence, CharSequence)
*/
public static T defaultIfEmpty(final T str, final T defaultStr) {
return isEmpty(str) ? defaultStr : str;
}
/**
*
* @param
* @param str
* @param getterForDefaultStr
* @return
*/
public static T defaultIfEmpty(final T str, final Supplier extends T> getterForDefaultStr) {
if (isEmpty(str)) {
return getterForDefaultStr.get();
}
return str;
}
/**
* Same as {@code N.defaultIfNullOrEmptyOrBlank(CharSequence, CharSequence)}.
*
* @param
* @param str
* @param defaultStr
* @return
* @see N#defaultIfNullOrEmptyOrBlank(CharSequence, CharSequence)
*/
public static T defaultIfBlank(final T str, final T defaultStr) {
return isBlank(str) ? defaultStr : str;
}
/**
*
* @param
* @param str
* @param getterForDefaultStr
* @return
*/
public static T defaultIfBlank(final T str, final Supplier extends T> getterForDefaultStr) {
if (isBlank(str)) {
return getterForDefaultStr.get();
}
return str;
}
@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.
*
*
* StringUtil.firstNonEmpty(null, null, null) = null
* StringUtil.firstNonEmpty(null, null, "") = null
* StringUtil.firstNonEmpty(null, "", " ") = " "
* StringUtil.firstNonEmpty("abc") = "abc"
* StringUtil.firstNonEmpty(null, "xyz") = "xyz"
* StringUtil.firstNonEmpty("", "xyz") = "xyz"
* StringUtil.firstNonEmpty(null, "xyz", "abc") = "xyz"
* StringUtil.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;
}
// 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}.
*
*
*
* StringUtil.abbreviate(null, 4) = null
* StringUtil.abbreviate("", 4) = ""
* StringUtil.abbreviate("abcdefg", 6) = "abc..."
* StringUtil.abbreviate("abcdefg", 7) = "abcdefg"
* StringUtil.abbreviate("abcdefg", 8) = "abcdefg"
* StringUtil.abbreviate("abcdefg", 4) = "a..."
* StringUtil.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
* @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);
}
public static String nullToEmpty(String str) {
return str == null ? N.EMPTY_STRING : str;
}
public static void nullToEmpty(String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = strs[i] == null ? N.EMPTY_STRING : strs[i];
}
}
public static String emptyToNull(String str) {
return str == null || str.length() > 0 ? str : null;
}
public static void emptyToNull(String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = strs[i] == null || strs[i].length() > 0 ? strs[i] : null;
}
}
/**
* 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}.
*
*
* StringUtil.abbreviate(null, 0, 4) = null
* StringUtil.abbreviate("", 0, 4) = ""
* StringUtil.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
* StringUtil.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
* StringUtil.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
* StringUtil.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
* StringUtil.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
* StringUtil.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
* StringUtil.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
* StringUtil.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
* StringUtil.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
* StringUtil.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
* StringUtil.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
* @deprecated
*/
@Deprecated
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}.
*
*
*
* StringUtil.abbreviate(null, "...", 4) = null
* StringUtil.abbreviate("", "...", 4) = ""
* StringUtil.abbreviate("abcdefg", null, *) = "abcdefg"
* StringUtil.abbreviate("abcdefg", ".", 5) = "abcd."
* StringUtil.abbreviate("abcdefg", ".", 7) = "abcdefg"
* StringUtil.abbreviate("abcdefg", ".", 8) = "abcdefg"
* StringUtil.abbreviate("abcdefg", "..", 4) = "ab.."
* StringUtil.abbreviate("abcdefg", "..", 3) = "a.."
* StringUtil.abbreviate("abcdefg", "..", 2) = IllegalArgumentException
* StringUtil.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
* @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}.
*
*
* StringUtil.abbreviate(null, "...", 0, 4) = null
* StringUtil.abbreviate("", "...", 0, 4) = ""
* StringUtil.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno"
* StringUtil.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
* StringUtil.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi,"
* StringUtil.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi,"
* StringUtil.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi,"
* StringUtil.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::"
* StringUtil.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..."
* StringUtil.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno"
* StringUtil.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno"
* StringUtil.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno"
* StringUtil.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException
* StringUtil.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
* @throws IllegalArgumentException if the width is too small
* @since 3.6
* @deprecated
*/
@Deprecated
static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
final int abbrevMarkerLength = N.len(abbrevMarker);
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 (N.notNullOrEmpty(str) && N.EMPTY_STRING.equals(abbrevMarker) && maxWidth > 0) {
return Strings.substring(str, 0, maxWidth);
} else if (N.anyNullOrEmpty(str, abbrevMarker)) {
return str;
}
final int strLen = str.length();
if (strLen <= maxWidth) {
return str;
}
if (offset > strLen) {
offset = strLen;
}
if (strLen - offset < maxWidth - abbrevMarkerLength) {
offset = strLen - (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 < strLen) {
return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
}
return abbrevMarker + str.substring(strLen - (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.
*
*
*
* StringUtil.abbreviateMiddle(null, null, 0) = null
* StringUtil.abbreviateMiddle("abc", null, 0) = "abc"
* StringUtil.abbreviateMiddle("abc", ".", 0) = "abc"
* StringUtil.abbreviateMiddle("abc", ".", 3) = "abc"
* StringUtil.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 (N.anyNullOrEmpty(str, middle) || 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);
}
// 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 original String is returned.
*
*
Equivalent to {@code center(str, size, " ")}.
*
*
* StringUtil.center(null, 4) = " "
* StringUtil.center("", 4) = " "
* StringUtil.center("ab", 4) = " ab "
* StringUtil.center("abcd", 2) = "abcd"
* StringUtil.center("a", 4) = " a "
*
*
* @param str the String to center, may be null
* @param size the int size of new String
* @return centered String
*/
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.
*
*
* StringUtil.center(null, 4, ' ') = " "
* StringUtil.center("", 4, ' ') = " "
* StringUtil.center("ab", 4, ' ') = " ab "
* StringUtil.center("abcd", 2, ' ') = "abcd"
* StringUtil.center("a", 4, ' ') = " a "
* StringUtil.center("a", 4, 'y') = "yayy"
*
*
* @param str the String to center, may be null
* @param size the int size of new String.
* @param padChar the character to pad the new String with
* @return centered String
* @since 2.0
*/
public static String center(String str, final int size, final char padChar) {
N.checkArgNotNegative(size, "size");
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= size) {
return str;
}
final int strLen = str.length();
final int pads = size - strLen;
str = padStart(str, strLen + pads / 2, padChar);
return padEnd(str, size, padChar);
}
/**
* Centers a String in a larger String of size {@code minLength}.
* 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.
*
*
* StringUtil.center(null, 4, " ") = " "
* StringUtil.center("", 4, " ") = " "
* StringUtil.center("ab", 4, " ") = " ab "
* StringUtil.center("abcd", 2, " ") = "abcd"
* StringUtil.center("a", 4, " ") = " a "
* StringUtil.center("a", 4, "yz") = "yzayz"
* StringUtil.center("abc", 7, "") = " abc "
*
*
* @param str the String to center, may be null
* @param minLength the minimum size of new String.
* @param padStr the String to pad the new String with, must not be null or empty
* @return centered String
*/
public static String center(String str, final int minLength, String padStr) {
N.checkArgNotNegative(minLength, "minLength");
// N.checkArgNotNullOrEmpty(padStr, "padStr");
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= minLength) {
return str;
}
if (isEmpty(padStr)) {
padStr = " ";
}
final int strLen = str.length();
final int pads = minLength - strLen;
str = padStart(str, strLen + pads / 2, padStr);
return padEnd(str, minLength, padStr);
}
/**
*
* @param str
* @param minLength
* @return
*/
public static String padStart(final String str, final int minLength) {
return padStart(str, minLength, WD._SPACE);
}
/**
*
* @param str
* @param minLength
* @param padChar
* @return
*/
@SuppressWarnings("deprecation")
public static String padStart(String str, final int minLength, final char padChar) {
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= minLength) {
return str;
}
int delta = minLength - str.length();
final char[] chars = new char[minLength];
N.fill(chars, 0, delta, padChar);
str.getChars(0, str.length(), chars, delta);
return InternalUtil.newString(chars, true);
}
/**
*
* @param str
* @param minLength
* @param padStr
* @return
*/
public static String padStart(String str, final int minLength, final String padStr) {
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= minLength) {
return str;
}
final int delta = ((minLength - str.length()) % padStr.length() == 0) ? ((minLength - str.length()) / padStr.length())
: ((minLength - str.length()) / padStr.length() + 1);
switch (delta) {
case 1:
return padStr + str;
case 2:
return padStr + padStr + str;
case 3:
return padStr + padStr + padStr + str;
default: {
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = 0; i < delta; i++) {
sb.append(padStr);
}
sb.append(str);
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
}
}
/**
*
* @param str
* @param minLength
* @return
*/
public static String padEnd(final String str, final int minLength) {
return padEnd(str, minLength, WD._SPACE);
}
/**
*
* @param str
* @param minLength
* @param padChar
* @return
*/
@SuppressWarnings("deprecation")
public static String padEnd(String str, final int minLength, final char padChar) {
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= minLength) {
return str;
}
final char[] chars = new char[minLength];
str.getChars(0, str.length(), chars, 0);
N.fill(chars, str.length(), minLength, padChar);
return InternalUtil.newString(chars, true);
}
/**
*
* @param str
* @param minLength
* @param padStr
* @return
*/
public static String padEnd(String str, final int minLength, final String padStr) {
if (str == null) {
str = N.EMPTY_STRING;
}
if (str.length() >= minLength) {
return str;
}
final int delta = ((minLength - str.length()) % padStr.length() == 0) ? ((minLength - str.length()) / padStr.length())
: ((minLength - str.length()) / padStr.length() + 1);
switch (delta) {
case 1:
return str + padStr;
case 2:
return str + padStr + padStr;
case 3:
return str + padStr + padStr + padStr;
default: {
StringBuilder sb = Objectory.createStringBuilder();
try {
sb.append(str);
for (int i = 0; i < delta; i++) {
sb.append(padStr);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
}
}
/**
*
* @param ch
* @param n
* @return
*/
@SuppressWarnings("deprecation")
public static String repeat(final char ch, final int n) {
N.checkArgNotNegative(n, "n");
if (n == 0) {
return N.EMPTY_STRING;
} else if (n == 1) {
return String.valueOf(ch);
}
if (n < 16) {
final char[] array = new char[n];
Arrays.fill(array, ch);
return InternalUtil.newString(array, true);
} else {
final char[] array = new char[n];
array[0] = ch;
int cnt = 1;
for (; cnt < n - cnt; cnt <<= 1) {
N.copy(array, 0, array, cnt, cnt);
}
if (cnt < n) {
N.copy(array, 0, array, cnt, n - cnt);
}
return InternalUtil.newString(array, true);
}
}
/**
*
* @param ch
* @param n
* @param delimiter
* @return
*/
public static String repeat(final char ch, final int n, final char delimiter) {
return repeat(String.valueOf(ch), n, String.valueOf(delimiter));
}
/**
*
* @param str
* @param repeat
* @return
*/
public static String repeat(final String str, final int repeat) {
return repeat(str, repeat, N.EMPTY_STRING);
}
/**
*
* @param str
* @param n
* @param delimiter
* @return
*/
public static String repeat(final String str, final int n, final String delimiter) {
return repeat(str, n, delimiter, N.EMPTY_STRING, N.EMPTY_STRING);
}
/**
*
* @param str
* @param n
* @param delimiter
* @param prefix
* @param suffix
* @return
*/
@SuppressWarnings("deprecation")
public static String repeat(String str, final int n, String delimiter, String prefix, String suffix) {
N.checkArgNotNegative(n, "n");
str = str == null ? N.EMPTY_STRING : str;
delimiter = delimiter == null ? N.EMPTY_STRING : delimiter;
prefix = prefix == null ? N.EMPTY_STRING : prefix;
suffix = suffix == null ? N.EMPTY_STRING : suffix;
if (n == 0 || (N.isNullOrEmpty(str) && N.isNullOrEmpty(delimiter))) {
return prefix + suffix;
} else if (n == 1) {
return prefix + str + suffix;
}
final int strLen = str.length();
final int delimiterLen = delimiter.length();
final int prefixLen = prefix.length();
final int suffixLen = suffix.length();
final int pieceLen = strLen + delimiterLen;
if ((Integer.MAX_VALUE - prefixLen - suffixLen) / pieceLen < n) {
throw new ArrayIndexOutOfBoundsException("Required array size too large: " + 1L * pieceLen * n);
}
final int size = pieceLen * n - delimiterLen + prefixLen + suffixLen;
final char[] cbuf = new char[size];
prefix.getChars(0, prefixLen, cbuf, 0);
str.getChars(0, strLen, cbuf, prefixLen);
delimiter.getChars(0, delimiterLen, cbuf, strLen + prefixLen);
int filledLen = pieceLen;
int lenToFill = size - (prefixLen + suffixLen);
for (; filledLen <= lenToFill - filledLen; filledLen <<= 1) {
N.copy(cbuf, prefixLen, cbuf, filledLen + prefixLen, filledLen);
}
if (filledLen < lenToFill) {
N.copy(cbuf, prefixLen, cbuf, filledLen + prefixLen, size - filledLen - prefixLen - suffixLen);
}
suffix.getChars(0, suffixLen, cbuf, size - suffixLen);
return InternalUtil.newString(cbuf, true);
}
/**
* To lower case.
*
* @param ch
* @return
*/
public static char toLowerCase(final char ch) {
return Character.toLowerCase(ch);
}
/**
*
* Converts a String to lower case as per {@link String#toLowerCase()}.
*
*
*
* A {@code null} input String returns {@code null}.
*
*
*
* StringUtil.toLowerCase(null) = null
* StringUtil.toLowerCase("") = ""
* StringUtil.toLowerCase("aBc") = "abc"
*
*
*
* Note: As described in the documentation for
* {@link String#toLowerCase()}, the result of this method is affected by
* the current locale. For platform-independent case transformations, the
* method {@link #toLowerCase(String, Locale)} should be used with a specific
* locale (e.g. {@link Locale#ENGLISH}).
*
*
* @param str
* the String to lower case, may be null
* @return
*/
public static String toLowerCase(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
return str.toLowerCase();
}
/**
*
* Converts a String to lower case as per {@link String#toLowerCase(Locale)}
* .
*
*
*
* A {@code null} input String returns {@code null}.
*
*
*
* StringUtil.toLowerCase(null, Locale.ENGLISH) = null
* StringUtil.toLowerCase("", Locale.ENGLISH) = ""
* StringUtil.toLowerCase("aBc", Locale.ENGLISH) = "abc"
*
*
* @param str
* the String to lower case, may be null
* @param locale
* the locale that defines the case transformation rules, must
* not be null
* @return
* @since 2.5
*/
public static String toLowerCase(final String str, final Locale locale) {
if (N.isNullOrEmpty(str)) {
return str;
}
return str.toLowerCase(locale);
}
/**
* To lower case with underscore.
*
* @param str
* @return
*/
public static String toLowerCaseWithUnderscore(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
char ch = 0;
try {
for (int i = 0, len = str.length(); i < len; i++) {
ch = str.charAt(i);
if (Character.isUpperCase(ch)) {
if (i > 0 && (Character.isLowerCase(str.charAt(i - 1)) || (i < len - 1 && Character.isLowerCase(str.charAt(i + 1))))) {
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {
sb.append(WD._UNDERSCORE);
}
}
sb.append(Character.toLowerCase(ch));
} else {
// if (i > 0 && ((isAsciiNumeric(ch) && !isAsciiNumeric(str.charAt(i - 1))) || (isAsciiNumeric(str.charAt(i - 1)) && !isAsciiNumeric(ch)))) {
// if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {
// sb.append(WD._UNDERSCORE);
// }
// }
sb.append(ch);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
* To upper case.
*
* @param ch
* @return
*/
public static char toUpperCase(final char ch) {
return Character.toUpperCase(ch);
}
// Case conversion
// -----------------------------------------------------------------------
/**
*
* Converts a String to upper case as per {@link String#toUpperCase()}.
*
*
*
* A {@code null} input String returns {@code null}.
*
*
*
* N.toUpperCase(null) = null
* N.toUpperCase("") = ""
* N.toUpperCase("aBc") = "ABC"
*
*
*
* Note: As described in the documentation for
* {@link String#toUpperCase()}, the result of this method is affected by
* the current locale. For platform-independent case transformations, the
* method {@link #toLowerCase(String, Locale)} should be used with a specific
* locale (e.g. {@link Locale#ENGLISH}).
*
*
* @param str
* the String to upper case, may be null
* @return
*/
public static String toUpperCase(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
return str.toUpperCase();
}
/**
*
* Converts a String to upper case as per {@link String#toUpperCase(Locale)}
* .
*
*
*
* A {@code null} input String returns {@code null}.
*
*
*
* N.toUpperCase(null, Locale.ENGLISH) = null
* N.toUpperCase("", Locale.ENGLISH) = ""
* N.toUpperCase("aBc", Locale.ENGLISH) = "ABC"
*
*
* @param str
* the String to upper case, may be null
* @param locale
* the locale that defines the case transformation rules, must
* not be null
* @return
* @since 2.5
*/
public static String toUpperCase(final String str, final Locale locale) {
if (N.isNullOrEmpty(str)) {
return str;
}
return str.toUpperCase(locale);
}
/**
* To upper case with underscore.
*
* @param str
* @return
*/
public static String toUpperCaseWithUnderscore(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
char ch = 0;
try {
for (int i = 0, len = str.length(); i < len; i++) {
ch = str.charAt(i);
if (Character.isUpperCase(ch)) {
if (i > 0 && (Character.isLowerCase(str.charAt(i - 1)) || (i < len - 1 && Character.isLowerCase(str.charAt(i + 1))))) {
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {
sb.append(WD._UNDERSCORE);
}
}
sb.append(ch);
} else {
// if (i > 0 && ((isAsciiNumeric(ch) && !isAsciiNumeric(str.charAt(i - 1))) || (isAsciiNumeric(str.charAt(i - 1)) && !isAsciiNumeric(ch)))) {
// if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {
// sb.append(WD._UNDERSCORE);
// }
// }
sb.append(Character.toUpperCase(ch));
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
*
* @param str
* @return
*/
public static String toCamelCase(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
if (str.indexOf(WD._UNDERSCORE) >= 0) {
String[] substrs = Strings.split(str, WD._UNDERSCORE);
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (String substr : substrs) {
if (N.notNullOrEmpty(substr)) {
sb.append(Strings.toLowerCase(substr));
if (sb.length() > substr.length()) {
sb.setCharAt(sb.length() - substr.length(), Character.toTitleCase(substr.charAt(0)));
}
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
for (int i = 0, len = str.length(); i < len; i++) {
if (Character.isLowerCase(str.charAt(i))) {
if (i == 1) {
return Strings.uncapitalize(str);
} else if (i > 1) {
return str.substring(0, i - 1).toLowerCase() + str.substring(i - 1);
}
break;
} else if ((i + 1) == str.length()) {
return str.toLowerCase();
}
}
return str;
}
public static char[] toCharArray(final CharSequence source) {
final int len = N.len(source);
if (len == 0) {
return N.EMPTY_CHAR_ARRAY;
}
if (source instanceof String) {
return ((String) source).toCharArray();
}
final char[] array = new char[len];
for (int i = 0; i < len; i++) {
array[i] = source.charAt(i);
}
return array;
}
/**
* Converts a {@code CharSequence} into an array of code points.
*
* Valid pairs of surrogate code units will be converted into a single supplementary
* code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
* a low surrogate not preceded by a high surrogate) will be returned as-is.
*
*
* StringUtil.toCodePoints(null) = [] // empty array
* StringUtil.toCodePoints("") = [] // empty array
*
*
* @param str the character sequence to convert
* @return an empty array is the specified String {@code str} is null or empty.
* @since 3.6
*/
public static int[] toCodePoints(final CharSequence str) {
if (N.isNullOrEmpty(str)) {
return N.EMPTY_INT_ARRAY;
}
final String s = str.toString();
final int[] result = new int[s.codePointCount(0, s.length())];
int index = 0;
for (int i = 0; i < result.length; i++) {
result[i] = s.codePointAt(index);
index += Character.charCount(result[i]);
}
return result;
}
/**
*
* @param ch
* @return
*/
public static char swapCase(final char ch) {
return Character.isLowerCase(ch) ? Character.toUpperCase(ch) : Character.toLowerCase(ch);
}
/**
*
* Swaps the case of a String changing upper and title case to lower case,
* and lower case to upper case.
*
*
*
* Upper case character converts to Lower case
* Title case character converts to Lower case
* Lower case character converts to Upper case
*
*
*
* For a word based algorithm, see
* {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. A
* {@code null} input String returns {@code null}.
*
*
*
* N.swapCase(null) = null
* N.swapCase("") = ""
* N.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
*
*
*
* NOTE: This method changed in Lang version 2.0. It no longer performs a
* word based algorithm. If you only use ASCII, you will notice no change.
* That functionality is available in
* org.apache.commons.lang3.text.WordUtils.
*
*
* @param str
* the String to swap case, may be null
* @return
*/
@SuppressWarnings("deprecation")
public static String swapCase(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
final char[] cbuf = str.toCharArray();
char ch = 0;
for (int i = 0, len = cbuf.length; i < len; i++) {
ch = cbuf[i];
if (Character.isUpperCase(ch) || Character.isTitleCase(ch)) {
cbuf[i] = Character.toLowerCase(ch);
} else if (Character.isLowerCase(ch)) {
cbuf[i] = Character.toUpperCase(ch);
}
}
return InternalUtil.newString(cbuf, true);
}
/**
*
* @param str
* @return
*/
public static String capitalize(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
char ch = str.charAt(0);
if (Character.isTitleCase(ch)) {
return str;
}
if (str.length() == 1) {
return String.valueOf(Character.toTitleCase(ch));
} else {
return Character.toTitleCase(ch) + str.substring(1);
}
}
/**
*
* @param str
* @return
*/
public static String uncapitalize(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
char ch = str.charAt(0);
if (Character.isLowerCase(ch)) {
return str;
}
if (str.length() == 1) {
return String.valueOf(Character.toLowerCase(ch));
} else {
return Character.toLowerCase(ch) + str.substring(1);
}
}
/**
* Replace ''' or '"' with '\'' or '\"' if the previous char of the
* quotation is not '\'. original String is returned if the specified String
* is {@code null} or empty.
*
* @param str
* @return
*/
public static String quoteEscaped(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
char ch = 0;
for (int i = 0, len = str.length(); i < len; i++) {
ch = str.charAt(i);
if ((ch == _BACKSLASH) && (i < (len - 1))) {
sb.append(ch);
sb.append(str.charAt(++i));
} else if ((ch == _QUOTATION_S) || (ch == _QUOTATION_D)) {
sb.append(_BACKSLASH);
sb.append(ch);
} else {
sb.append(ch);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param str
* @param quoteChar it should be {@code "} or {@code '}.
* @return
*/
public static String quoteEscaped(final String str, final char quoteChar) {
if (N.isNullOrEmpty(str)) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
char ch = 0;
for (int i = 0, len = str.length(); i < len; i++) {
ch = str.charAt(i);
if ((ch == _BACKSLASH) && (i < (len - 1))) {
sb.append(ch);
sb.append(str.charAt(++i));
} else if (ch == quoteChar) {
sb.append(_BACKSLASH);
sb.append(ch);
} else {
sb.append(ch);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
// --------------------------------------------------------------------------
/**
*
* Converts the char to the unicode format '\u0020'.
*
*
*
* This format is the Java source code format.
*
*
*
* StringUtil.unicodeEscaped(' ') = "\u0020"
* StringUtil.unicodeEscaped('A') = "\u0041"
*
*
* @param ch
* the character to convert
* @return
*/
public static String unicodeEscaped(final char ch) {
if (ch < 0x10) {
return "\\u000" + Integer.toHexString(ch);
} else if (ch < 0x100) {
return "\\u00" + Integer.toHexString(ch);
} else if (ch < 0x1000) {
return "\\u0" + Integer.toHexString(ch);
}
return "\\u" + Integer.toHexString(ch);
}
/**
*
* Similar to
* http://www.w3.org/TR/xpath/#function-normalize -space
*
*
* The function returns the argument string with whitespace normalized by
* using {@link #trim(String)}
to remove leading and trailing
* whitespace and then replacing sequences of whitespace characters by a
* single space.
*
* In XML Whitespace characters are the same as those allowed by the S production, which is S
* ::= (#x20 | #x9 | #xD | #xA)+
*
* Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
*
*
* For reference:
*
*
* \x0B = vertical tab
* \f = #xC = form feed
* #x20 = space
* #x9 = \t
* #xA = \n
* #xD = \r
*
*
*
* The difference is that Java's whitespace includes vertical tab and form
* feed, which this functional will also normalize. Additionally
* {@link #trim(String)}
removes control characters (char <=
* 32) from both ends of this String.
*
*
* @param str the source String to normalize whitespaces from, may be null
* @return
* null String input
* @see Pattern
* @see #trim(String)
* @see http://www.w3.org/TR/xpath/#function-normalize-space
* @since 3.0
*/
public static String normalizeSpace(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
return WHITESPACE_PATTERN.matcher(str.trim()).replaceAll(WD.SPACE);
}
/**
*
* Replaces all occurrences of a String within another String.
*
*
*
* A {@code null} reference passed to this method is a no-op.
*
*
*
* N.replaceAll(null, *, *) = null
* N.replaceAll("", *, *) = ""
* N.replaceAll("any", null, *) = "any"
* N.replaceAll("any", *, null) = "any"
* N.replaceAll("any", "", *) = "any"
* N.replaceAll("aba", "a", null) = "b"
* N.replaceAll("aba", "a", "") = "b"
* N.replaceAll("aba", "a", "z") = "zbz"
*
*
* @param str text to search and replace in, may be null
* @param target the String to search for, may be null
* @param replacement the String to replace it with, may be null
* @return
* String input
* @see #replaceAll(String text, String searchString, String replacement,
* int max)
*/
public static String replaceAll(final String str, final String target, final String replacement) {
return replaceAll(str, 0, target, replacement);
}
/**
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @return
*/
public static String replaceAll(final String str, final int fromIndex, final String target, final String replacement) {
return replace(str, fromIndex, target, replacement, -1);
}
/**
* Replaces a String with another String inside a larger String, once.
*
* A {@code null} reference passed to this method is a no-op.
*
*
* StringUtil.replaceOnce(null, *, *) = null
* StringUtil.replaceOnce("", *, *) = ""
* StringUtil.replaceOnce("any", null, *) = "any"
* StringUtil.replaceOnce("any", *, null) = "any"
* StringUtil.replaceOnce("any", "", *) = "any"
* StringUtil.replaceOnce("aba", "a", null) = "ba"
* StringUtil.replaceOnce("aba", "a", "") = "ba"
* StringUtil.replaceOnce("aba", "a", "z") = "zba"
*
*
* @see #replace(String text, String searchString, String replacement, int max)
* @param text text to search and replace in, may be null
* @param searchString the String to search for, may be null
* @param replacement the String to replace with, may be null
* @return the text with any replacements processed,
* {@code null} if null String input
*/
public static String replaceOnce(final String str, final String target, final String replacement) {
return replaceOnce(str, 0, target, replacement);
}
/**
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @return
*/
public static String replaceOnce(final String str, final int fromIndex, final String target, final String replacement) {
return replace(str, fromIndex, target, replacement, 1);
}
/**
*
* Replaces a String with another String inside a larger String, for the
* first {@code max} values of the search String.
*
*
*
* A {@code null} reference passed to this method is a no-op.
*
*
*
* replace(null, *, *, *) = null
* replace("", *, *, *) = ""
* replace("any", null, *, *) = "any"
* replace("any", "", *, *) = "any"
* replace("any", *, *, 0) = "any"
* replace("abaa", 0, "a", null, -1) = "b"
* replace("abaa", 0, "a", "", -1) = "b"
* replace("abaa", 0, "a", "z", 0) = "abaa"
* replace("abaa", 0, "a", "z", 1) = "zbaa"
* replace("abaa", 0, "a", "z", 2) = "zbza"
* replace("abaa", 0, "a", "z", -1) = "zbzz"
*
*
* @param str text to search and replace in, may be null
* @param fromIndex
* @param target the String to search for, may be null
* @param replacement the String to replace it with, can't be null
* @param max maximum number of values to replace, or {@code -1} if no
* maximum
* @return
* String input
*/
public static String replace(final String str, final int fromIndex, final String target, final String replacement, int max) {
return replace(str, fromIndex, target, replacement, max, false);
}
/**
* Replace all ignore case.
*
* @param str
* @param target
* @param replacement
* @return
*/
public static String replaceAllIgnoreCase(final String str, final String target, final String replacement) {
return replaceAllIgnoreCase(str, 0, target, replacement);
}
/**
* Replace all ignore case.
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @return
*/
public static String replaceAllIgnoreCase(final String str, final int fromIndex, final String target, final String replacement) {
return replaceIgnoreCase(str, fromIndex, target, replacement, -1);
}
/**
* Replace once ignore case.
*
* @param str
* @param target
* @param replacement
* @return
*/
public static String replaceOnceIgnoreCase(final String str, final String target, final String replacement) {
return replaceOnceIgnoreCase(str, 0, target, replacement);
}
/**
* Replace once ignore case.
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @return
*/
public static String replaceOnceIgnoreCase(final String str, final int fromIndex, final String target, final String replacement) {
return replaceIgnoreCase(str, fromIndex, target, replacement, 1);
}
/**
* Replace ignore case.
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @param max
* @return
*/
public static String replaceIgnoreCase(final String str, final int fromIndex, final String target, final String replacement, int max) {
return replace(str, fromIndex, target, replacement, max, true);
}
/**
*
* @param str
* @param fromIndex
* @param target
* @param replacement
* @param max
* @param ignoreCase
* @return
*/
private static String replace(final String str, final int fromIndex, final String target, String replacement, int max, boolean ignoreCase) {
// TODO
// if (replacement == null) {
// throw new IllegalArgumentException("Replacement can't be null");
// }
if (replacement == null) {
replacement = "";
}
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(target) || max == 0) {
return str;
}
final String searchText = ignoreCase ? str.toLowerCase() : str;
final String searchTarget = ignoreCase ? target.toLowerCase() : target;
int end = searchText.indexOf(searchTarget, fromIndex);
if (end == N.INDEX_NOT_FOUND) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
final int substrLength = target.length();
sb.append(str, 0, fromIndex);
int start = fromIndex;
try {
while (end != N.INDEX_NOT_FOUND) {
sb.append(str, start, end).append(replacement);
start = end + substrLength;
if (--max == 0) {
break;
}
end = searchText.indexOf(searchTarget, start);
}
sb.append(str, start, str.length());
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
* Replaces each substring of the source String that matches the given
* regular expression with the given replacement using the
* {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in
* Perl. This call is also equivalent to:
*
* {@code source.replaceAll("(?s)" + regex, replacement)}
*
* {@code Pattern.compile(regex, Pattern.DOTALL).filter(source).replaceAll(replacement)}
*
*
*
* @param source
* the source string
* @param regex
* the regular expression to which this string is to be matched
* @param replacement
* the string to be substituted for each match
* @return The resulting {@code String}
* @see String#replaceAll(String, String)
* @see Pattern#DOTALL
* @since 3.2
*/
public static String replacePattern(final String source, final String regex, final String replacement) {
return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement);
}
// Remove
// -----------------------------------------------------------------------
/**
*
* Removes a substring only if it is at the beginning of a source string,
* otherwise returns the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string. A {@code null} search string
* will return the source string.
*
*
*
* N.removeStart(null, *) = null
* N.removeStart("", *) = ""
* N.removeStart(*, null) = *
* N.removeStart("www.domain.com", "www.") = "domain.com"
* N.removeStart("domain.com", "www.") = "domain.com"
* N.removeStart("www.domain.com", "domain") = "www.domain.com"
* N.removeStart("abc", "") = "abc"
*
*
* @param str
* the source String to search, may be null
* @param removeStr
* the String to search for and remove, may be null
* @return
* null String input
* @since 2.1
*/
public static String removeStart(final String str, final String removeStr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(removeStr)) {
return str;
}
if (str.startsWith(removeStr)) {
return str.substring(removeStr.length());
}
return str;
}
/**
*
* Case insensitive removal of a substring if it is at the beginning of a
* source string, otherwise returns the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string. A {@code null} search string
* will return the source string.
*
*
*
* N.removeStartIgnoreCase(null, *) = null
* N.removeStartIgnoreCase("", *) = ""
* N.removeStartIgnoreCase(*, null) = *
* N.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
* N.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
* N.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
* N.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
* N.removeStartIgnoreCase("abc", "") = "abc"
*
*
* @param str
* the source String to search, may be null
* @param removeStr
* the String to search for (case insensitive) and remove, may be
* null
* @return
* null String input
* @since 2.4
*/
public static String removeStartIgnoreCase(final String str, final String removeStr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(removeStr)) {
return str;
}
if (startsWithIgnoreCase(str, removeStr)) {
return str.substring(removeStr.length());
}
return str;
}
/**
*
* Removes a substring only if it is at the end of a source string,
* otherwise returns the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string. A {@code null} search string
* will return the source string.
*
*
*
* N.removeEnd(null, *) = null
* N.removeEnd("", *) = ""
* N.removeEnd(*, null) = *
* N.removeEnd("www.domain.com", ".com.") = "www.domain.com"
* N.removeEnd("www.domain.com", ".com") = "www.domain"
* N.removeEnd("www.domain.com", "domain") = "www.domain.com"
* N.removeEnd("abc", "") = "abc"
*
*
* @param str
* the source String to search, may be null
* @param removeStr
* the String to search for and remove, may be null
* @return
* null String input
* @since 2.1
*/
public static String removeEnd(final String str, final String removeStr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(removeStr)) {
return str;
}
if (str.endsWith(removeStr)) {
return str.substring(0, str.length() - removeStr.length());
}
return str;
}
/**
*
* Case insensitive removal of a substring if it is at the end of a source
* string, otherwise returns the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string. A {@code null} search string
* will return the source string.
*
*
*
* N.removeEndIgnoreCase(null, *) = null
* N.removeEndIgnoreCase("", *) = ""
* N.removeEndIgnoreCase(*, null) = *
* N.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
* N.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
* N.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
* N.removeEndIgnoreCase("abc", "") = "abc"
* N.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
* N.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
*
*
* @param str
* the source String to search, may be null
* @param removeStr
* the String to search for (case insensitive) and remove, may be
* null
* @return
* null String input
* @since 2.4
*/
public static String removeEndIgnoreCase(final String str, final String removeStr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(removeStr)) {
return str;
}
if (endsWithIgnoreCase(str, removeStr)) {
return str.substring(0, str.length() - removeStr.length());
}
return str;
}
/**
*
* Removes all occurrences of a character from within the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string.
*
*
*
* N.remove(null, *) = null
* N.remove("", *) = ""
* N.remove("queued", 'u') = "qeed"
* N.remove("queued", 'z') = "queued"
*
*
* @param str
* the source String to search, may be null
* @param removeChar
* the char to search for and remove, may be null
* @return
* null String input
* @since 2.1
*/
public static String removeAll(final String str, final char removeChar) {
return removeAll(str, 0, removeChar);
}
/**
* Removes the all.
*
* @param str
* @param fromIndex
* @param removeChar
* @return
*/
public static String removeAll(final String str, final int fromIndex, final char removeChar) {
if (N.isNullOrEmpty(str)) {
return str;
}
int index = str.indexOf(removeChar, fromIndex);
if (index == N.INDEX_NOT_FOUND) {
return str;
} else {
final char[] cbuf = new char[str.length()];
if (index > 0) {
str.getChars(0, index, cbuf, 0);
}
int count = index;
char ch = 0;
for (int i = index + 1, len = str.length(); i < len; i++) {
ch = str.charAt(i);
if (ch != removeChar) {
cbuf[count++] = ch;
}
}
return count == cbuf.length ? str : new String(cbuf, 0, count);
}
}
/**
*
* Removes all occurrences of a substring from within the source string.
*
*
*
* A {@code null} source string will return {@code null}. An empty ("")
* source string will return the empty string. A {@code null} remove string
* will return the source string. An empty ("") remove string will return
* the source string.
*
*
*
* N.remove(null, *) = null
* N.remove("", *) = ""
* N.remove(*, null) = *
* N.remove(*, "") = *
* N.remove("queued", "ue") = "qd"
* N.remove("queued", "zz") = "queued"
*
*
* @param str
* the source String to search, may be null
* @param removeStr
* the String to search for and remove, may be null
* @return
* null String input
* @since 2.1
*/
public static String removeAll(final String str, final String removeStr) {
return removeAll(str, 0, removeStr);
}
/**
* Removes the all.
*
* @param str
* @param fromIndex
* @param removeStr
* @return
*/
public static String removeAll(final String str, final int fromIndex, final String removeStr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(removeStr)) {
return str;
}
return replace(str, fromIndex, removeStr, N.EMPTY_STRING, -1);
}
/**
* Removes each substring of the source String that matches the given
* regular expression using the DOTALL option.
*
* @param source
* the source string
* @param regex
* the regular expression to which this string is to be matched
* @return The resulting {@code String}
* @see String#replaceAll(String, String)
* @see Pattern#DOTALL
* @since 3.2
*/
public static String removePattern(final String source, final String regex) {
return replacePattern(source, regex, N.EMPTY_STRING);
}
/**
*
* @param str
* @param delimiter
* @return
*/
public static String[] split(final String str, final char delimiter) {
final Splitter splitter = splitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings() : splitter).splitToArray(str);
}
/**
*
* @param str
* @param delimiter
* @param trim
* @return
*/
@SuppressWarnings("deprecation")
public static String[] split(final String str, final char delimiter, final boolean trim) {
if (trim) {
final Splitter splitter = trimSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings().trim(trim) : splitter).splitToArray(str);
} else {
return split(str, delimiter);
}
}
/**
*
* @param str
* @param delimiter
* @return
*/
public static String[] split(final String str, final String delimiter) {
final Splitter splitter = splitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings() : splitter).splitToArray(str);
}
/**
*
* @param str
* @param delimiter
* @param trim
* @return
*/
@SuppressWarnings("deprecation")
public static String[] split(final String str, final String delimiter, final boolean trim) {
if (trim) {
final Splitter splitter = trimSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings().trim(trim) : splitter).splitToArray(str);
} else {
return split(str, delimiter);
}
}
/**
*
* @param str
* @param delimiter
* @param max
* @return
* @deprecated {@code Splitter} is recommended.
*/
@Deprecated
public static String[] split(final String str, final String delimiter, final int max) {
return Splitter.with(delimiter).omitEmptyStrings().limit(max).splitToArray(str);
}
/**
*
* @param str
* @param delimiter
* @param max
* @param trim
* @return
* @deprecated {@code Splitter} is recommended.
*/
@Deprecated
public static String[] split(final String str, final String delimiter, final int max, final boolean trim) {
return Splitter.with(delimiter).omitEmptyStrings().trim(trim).limit(max).splitToArray(str);
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @return
*/
public static String[] splitPreserveAllTokens(final String str, final char delimiter) {
final Splitter splitter = preserveSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter) : splitter).splitToArray(str);
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @param trim
* @return
*/
@SuppressWarnings("deprecation")
public static String[] splitPreserveAllTokens(final String str, final char delimiter, boolean trim) {
if (trim) {
final Splitter splitter = trimPreserveSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).trim(trim) : splitter).splitToArray(str);
} else {
return splitPreserveAllTokens(str, delimiter);
}
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @return
*/
public static String[] splitPreserveAllTokens(final String str, final String delimiter) {
final Splitter splitter = preserveSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter) : splitter).splitToArray(str);
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @param trim
* @return
*/
@SuppressWarnings("deprecation")
public static String[] splitPreserveAllTokens(final String str, final String delimiter, boolean trim) {
if (trim) {
final Splitter splitter = trimPreserveSplitterPool.get(delimiter);
return (splitter == null ? Splitter.with(delimiter).trim(trim) : splitter).splitToArray(str);
} else {
return splitPreserveAllTokens(str, delimiter);
}
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @param max
* @return
* @deprecated {@code Splitter} is recommended.
*/
@Deprecated
public static String[] splitPreserveAllTokens(final String str, final String delimiter, final int max) {
return Splitter.with(delimiter).limit(max).splitToArray(str);
}
/**
* Split preserve all tokens.
*
* @param str
* @param delimiter
* @param max
* @param trim
* @return
* @deprecated {@code Splitter} is recommended.
*/
@Deprecated
public static String[] splitPreserveAllTokens(final String str, final String delimiter, final int max, boolean trim) {
return Splitter.with(delimiter).trim(trim).limit(max).splitToArray(str);
}
// -----------------------------------------------------------------------
/**
*
* Removes control characters (char <= 32) from both ends of this String,
* handling {@code null} by returning {@code null}.
*
*
*
* The String is trimmed using {@link String#trim()}. Trim removes start and
* end characters <= 32. To strip whitespace use {@link #strip(String)}.
*
*
*
* To trim your choice of characters, use the {@link #strip(String, String)}
* methods.
*
*
*
* StringUtil.trim(null) = null
* StringUtil.trim("") = ""
* StringUtil.trim(" ") = ""
* StringUtil.trim("abc") = "abc"
* StringUtil.trim(" abc ") = "abc"
*
*
* @param str
* the String to be trimmed, may be null
* @return
*/
public static String trim(final String str) {
return N.isNullOrEmpty(str) || (str.charAt(0) != ' ' && str.charAt(str.length() - 1) != ' ') ? str : str.trim();
}
public static void trim(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = trim(strs[i]);
}
}
/**
*
* Removes control characters (char <= 32) from both ends of this String
* returning {@code null} if the String is empty ("") after the trim or if
* it is {@code null}.
*
*
* The String is trimmed using {@link String#trim()}. Trim removes start and
* end characters <= 32. To strip whitespace use
* {@link #stripToNull(String)}.
*
*
*
* N.trimToNull(null) = null
* N.trimToNull("") = null
* N.trimToNull(" ") = null
* N.trimToNull("abc") = "abc"
* N.trimToNull(" abc ") = "abc"
*
*
* @param str
* the String to be trimmed, may be null
* @return
* null String input
* @since 2.0
*/
public static String trimToNull(String str) {
str = trim(str);
return N.isNullOrEmpty(str) ? null : str;
}
public static void trimToNull(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = trimToNull(strs[i]);
}
}
/**
*
* Removes control characters (char <= 32) from both ends of this String
* returning an empty String ("") if the String is empty ("") after the trim
* or if it is {@code null}.
*
*
* The String is trimmed using {@link String#trim()}. Trim removes start and
* end characters <= 32. To strip whitespace use
* {@link #stripToEmpty(String)}.
*
*
*
* N.trimToEmpty(null) = ""
* N.trimToEmpty("") = ""
* N.trimToEmpty(" ") = ""
* N.trimToEmpty("abc") = "abc"
* N.trimToEmpty(" abc ") = "abc"
*
*
* @param str
* the String to be trimmed, may be null
* @return
* @since 2.0
*/
public static String trimToEmpty(final String str) {
return N.isNullOrEmpty(str) ? N.EMPTY_STRING : str.trim();
}
public static void trimToEmpty(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = trimToEmpty(strs[i]);
}
}
// Stripping
// -----------------------------------------------------------------------
/**
*
* Strips whitespace from the start and end of a String.
*
*
*
* This is similar to {@link #trim(String)} but removes whitespace.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
*
* A {@code null} input String returns {@code null}.
*
*
*
* N.strip(null) = null
* N.strip("") = ""
* N.strip(" ") = ""
* N.strip("abc") = "abc"
* N.strip(" abc") = "abc"
* N.strip("abc ") = "abc"
* N.strip(" abc ") = "abc"
* N.strip(" ab c ") = "ab c"
*
*
* @param str
* the String to remove whitespace from, may be null
* @return
*/
public static String strip(final String str) {
return strip(str, null);
}
public static void strip(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = strip(strs[i]);
}
}
/**
*
* Strips whitespace from the start and end of a String returning
* {@code null} if the String is empty ("") after the strip.
*
*
*
* This is similar to {@link #trimToNull(String)} but removes whitespace.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
*
* N.stripToNull(null) = null
* N.stripToNull("") = null
* N.stripToNull(" ") = null
* N.stripToNull("abc") = "abc"
* N.stripToNull(" abc") = "abc"
* N.stripToNull("abc ") = "abc"
* N.stripToNull(" abc ") = "abc"
* N.stripToNull(" ab c ") = "ab c"
*
*
* @param str
* the String to be stripped, may be null
* @return
* String input
* @since 2.0
*/
public static String stripToNull(String str) {
str = strip(str, null);
return N.isNullOrEmpty(str) ? null : str;
}
public static void stripToNull(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = stripToNull(strs[i]);
}
}
/**
*
* Strips whitespace from the start and end of a String returning an empty
* String if {@code null} input.
*
*
*
* This is similar to {@link #trimToEmpty(String)} but removes whitespace.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
*
*
* N.stripToEmpty(null) = ""
* N.stripToEmpty("") = ""
* N.stripToEmpty(" ") = ""
* N.stripToEmpty("abc") = "abc"
* N.stripToEmpty(" abc") = "abc"
* N.stripToEmpty("abc ") = "abc"
* N.stripToEmpty(" abc ") = "abc"
* N.stripToEmpty(" ab c ") = "ab c"
*
*
* @param str
* the String to be stripped, may be null
* @return
* @since 2.0
*/
public static String stripToEmpty(final String str) {
return N.isNullOrEmpty(str) ? N.EMPTY_STRING : strip(str, null);
}
public static void stripToEmpty(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = stripToEmpty(strs[i]);
}
}
/**
*
* Strips any of a set of characters from the start and end of a String.
* This is similar to {@link String#trim()} but allows the characters to be
* stripped to be controlled.
*
*
*
* A {@code null} input String returns {@code null}. An empty string ("")
* input returns the empty string.
*
*
*
* If the stripChars String is {@code null}, whitespace is stripped as
* defined by {@link Character#isWhitespace(char)}. Alternatively use
* {@link #strip(String)}.
*
*
*
* N.strip(null, *) = null
* N.strip("", *) = ""
* N.strip("abc", null) = "abc"
* N.strip(" abc", null) = "abc"
* N.strip("abc ", null) = "abc"
* N.strip(" abc ", null) = "abc"
* N.strip(" abcyx", "xyz") = " abc"
*
*
* @param str
* the String to remove characters from, may be null
* @param stripChars
* the characters to remove, null treated as whitespace
* @return
*/
public static String strip(final String str, final String stripChars) {
if (N.isNullOrEmpty(str)) {
return str;
}
return stripEnd(stripStart(str, stripChars), stripChars);
}
public static void strip(final String[] strs, final String stripChars) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = strip(strs[i], stripChars);
}
}
/**
*
* Strips any of a set of characters from the start of a String.
*
*
*
* A {@code null} input String returns {@code null}. An empty string ("")
* input returns the empty string.
*
*
*
* If the stripChars String is {@code null}, whitespace is stripped as
* defined by {@link Character#isWhitespace(char)}.
*
*
*
* N.stripStart(null, *) = null
* N.stripStart("", *) = ""
* N.stripStart("abc", "") = "abc"
* N.stripStart("abc", null) = "abc"
* N.stripStart(" abc", null) = "abc"
* N.stripStart("abc ", null) = "abc "
* N.stripStart(" abc ", null) = "abc "
* N.stripStart("yxabc ", "xyz") = "abc "
*
*
* @param str
* the String to remove characters from, may be null
* @param stripChars
* the characters to remove, null treated as whitespace
* @return
*/
public static String stripStart(final String str, final String stripChars) {
if (N.isNullOrEmpty(str) || (stripChars != null && stripChars.isEmpty())) {
return str;
}
final int strLen = str.length();
int start = 0;
if (stripChars == null) {
while (start != strLen && Character.isWhitespace(str.charAt(start))) {
start++;
}
} else {
while (start != strLen && stripChars.indexOf(str.charAt(start)) != N.INDEX_NOT_FOUND) {
start++;
}
}
return start == 0 ? str : str.substring(start);
}
public static void stripStart(final String[] strs, final String stripChars) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = stripStart(strs[i], stripChars);
}
}
/**
*
* Strips any of a set of characters from the end of a String.
*
*
*
* A {@code null} input String returns {@code null}. An empty string ("")
* input returns the empty string.
*
*
*
* If the stripChars String is {@code null}, whitespace is stripped as
* defined by {@link Character#isWhitespace(char)}.
*
*
*
* N.stripEnd(null, *) = null
* N.stripEnd("", *) = ""
* N.stripEnd("abc", "") = "abc"
* N.stripEnd("abc", null) = "abc"
* N.stripEnd(" abc", null) = " abc"
* N.stripEnd("abc ", null) = "abc"
* N.stripEnd(" abc ", null) = " abc"
* N.stripEnd(" abcyx", "xyz") = " abc"
* N.stripEnd("120.00", ".0") = "12"
*
*
* @param str
* the String to remove characters from, may be null
* @param stripChars
* the set of characters to remove, null treated as whitespace
* @return
*/
public static String stripEnd(final String str, final String stripChars) {
if (N.isNullOrEmpty(str) || (stripChars != null && stripChars.isEmpty())) {
return str;
}
int end = str.length();
if (stripChars == null) {
while (end > 0 && Character.isWhitespace(str.charAt(end - 1))) {
end--;
}
} else {
while (end > 0 && stripChars.indexOf(str.charAt(end - 1)) != N.INDEX_NOT_FOUND) {
end--;
}
}
return end == str.length() ? str : str.substring(0, end);
}
public static void stripEnd(final String[] strs, final String stripChars) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = stripEnd(strs[i], stripChars);
}
}
/**
*
* Removes diacritics (~= accents) from a string. The case will not be
* altered.
*
*
* For instance, 'à' will be replaced by 'a'.
*
*
* Note that ligatures will be left as is.
*
*
*
* N.stripAccents(null) = null
* N.stripAccents("") = ""
* N.stripAccents("control") = "control"
* N.stripAccents("éclair") = "eclair"
*
*
* @param str
* @return input text with diacritics removed
* @since 3.0
*/
// See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented
// characters by their unaccented equivalent (and uncommitted bug fix:
// https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
public static String stripAccents(final String str) {
if (str == null) {
return null;
}
final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(str, Normalizer.Form.NFD));
convertRemainingAccentCharacters(decomposed);
// Note that this doesn't correctly remove ligatures...
return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
}
/**
* Pattern used in {@link #stripAccents(String)}.
*/
private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
char ch = 0;
for (int i = 0; i < decomposed.length(); i++) {
ch = decomposed.charAt(i);
if (ch == '\u0141') {
decomposed.setCharAt(i, 'L');
} else if (ch == '\u0142') {
decomposed.setCharAt(i, 'l');
}
}
}
public static void stripAccents(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = stripAccents(strs[i]);
}
}
// 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.
*
*
*
* N.chomp(null) = null
* N.chomp("") = ""
* N.chomp("abc \r") = "abc "
* N.chomp("abc\n") = "abc"
* N.chomp("abc\r\n") = "abc"
* N.chomp("abc\r\n\r\n") = "abc\r\n"
* N.chomp("abc\n\r") = "abc\n"
* N.chomp("abc\n\rabc") = "abc\n\rabc"
* N.chomp("\r") = ""
* N.chomp("\n") = ""
* N.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 (N.isNullOrEmpty(str)) {
return str;
}
if (str.length() == 1) {
final char ch = str.charAt(0);
if (ch == N.CHAR_CR || ch == N.CHAR_LF) {
return N.EMPTY_STRING;
}
return str;
}
int lastIdx = str.length() - 1;
final char last = str.charAt(lastIdx);
if (last == N.CHAR_LF) {
if (str.charAt(lastIdx - 1) == N.CHAR_CR) {
lastIdx--;
}
} else if (last != N.CHAR_CR) {
lastIdx++;
}
return lastIdx == str.length() ? str : str.substring(0, lastIdx);
}
public static void chomp(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = chomp(strs[i]);
}
}
// Chopping
// -----------------------------------------------------------------------
/**
*
* Remove the last character from a String.
*
*
*
* If the String ends in {@code \r\n}, then remove both of them.
*
*
*
* StringUtil.chop(null) = null
* StringUtil.chop("") = ""
* StringUtil.chop("abc \r") = "abc "
* StringUtil.chop("abc\n") = "abc"
* StringUtil.chop("abc\r\n") = "abc"
* StringUtil.chop("abc") = "ab"
* StringUtil.chop("abc\nabc") = "abc\nab"
* StringUtil.chop("a") = ""
* StringUtil.chop("\r") = ""
* StringUtil.chop("\n") = ""
* StringUtil.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 (N.isNullOrEmpty(str)) {
return str;
}
final int strLen = str.length();
if (strLen < 2) {
return N.EMPTY_STRING;
}
final int lastIdx = strLen - 1;
if (str.charAt(lastIdx) == N.CHAR_LF && str.charAt(lastIdx - 1) == N.CHAR_CR) {
return str.substring(0, lastIdx - 1);
} else {
return str.substring(0, lastIdx);
}
}
public static void chop(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = chop(strs[i]);
}
}
/**
* Truncates a String. This will turn
* "Now is the time for all good men" into "Now is the time for".
*
* Specifically:
*
* If {@code str} is less than {@code maxWidth} characters
* long, return it.
* Else truncate it to {@code substring(str, 0, maxWidth)}.
* If {@code maxWidth} is less than {@code 0}, throw an
* {@code IllegalArgumentException}.
* In no case will it return a String of length greater than
* {@code maxWidth}.
*
*
*
* StringUtil.truncate(null, 0) = null
* StringUtil.truncate(null, 2) = null
* StringUtil.truncate("", 4) = ""
* StringUtil.truncate("abcdefg", 4) = "abcd"
* StringUtil.truncate("abcdefg", 6) = "abcdef"
* StringUtil.truncate("abcdefg", 7) = "abcdefg"
* StringUtil.truncate("abcdefg", 8) = "abcdefg"
* StringUtil.truncate("abcdefg", -1) = throws an IllegalArgumentException
*
*
* @param str the String to truncate, may be null
* @param maxWidth maximum length of result String, must be positive
* @return truncated String, {@code null} if null String input
* @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
* @since 3.5
*/
public static String truncate(final String str, final int maxWidth) {
return truncate(str, 0, maxWidth);
}
/**
* Truncates a String. This will turn
* "Now is the time for all good men" into "is the time for all".
*
* Works like {@code truncate(String, int)}, but allows you to specify
* a "left edge" offset.
*
*
Specifically:
*
* If {@code str} is less than {@code maxWidth} characters
* long, return it.
* Else truncate it to {@code substring(str, offset, maxWidth)}.
* If {@code maxWidth} is less than {@code 0}, throw an
* {@code IllegalArgumentException}.
* If {@code offset} is less than {@code 0}, throw an
* {@code IllegalArgumentException}.
* In no case will it return a String of length greater than
* {@code maxWidth}.
*
*
*
* StringUtil.truncate(null, 0, 0) = null
* StringUtil.truncate(null, 2, 4) = null
* StringUtil.truncate("", 0, 10) = ""
* StringUtil.truncate("", 2, 10) = ""
* StringUtil.truncate("abcdefghij", 0, 3) = "abc"
* StringUtil.truncate("abcdefghij", 5, 6) = "fghij"
* StringUtil.truncate("raspberry peach", 10, 15) = "peach"
* StringUtil.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
* StringUtil.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
* StringUtil.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
* StringUtil.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
* StringUtil.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
* StringUtil.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
* StringUtil.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
* StringUtil.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
* StringUtil.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
* StringUtil.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
* StringUtil.truncate("abcdefghijklmno", 5, 5) = "fghij"
* StringUtil.truncate("abcdefghijklmno", 5, 3) = "fgh"
* StringUtil.truncate("abcdefghijklmno", 10, 3) = "klm"
* StringUtil.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
* StringUtil.truncate("abcdefghijklmno", 13, 1) = "n"
* StringUtil.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
* StringUtil.truncate("abcdefghijklmno", 14, 1) = "o"
* StringUtil.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
* StringUtil.truncate("abcdefghijklmno", 15, 1) = ""
* StringUtil.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
* StringUtil.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
* StringUtil.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
* StringUtil.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
*
*
* @param str the String to truncate, may be null
* @param offset left edge of source String
* @param maxWidth maximum length of result String, must be positive
* @return truncated String, {@code null} if null String input
* @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
* @since 3.5
*/
public static String truncate(final String str, final int offset, final int maxWidth) {
N.checkArgNotNegative(offset, "offset");
N.checkArgNotNegative(maxWidth, "maxWidth");
if (str == null) {
return null;
} else if (str.length() <= offset || maxWidth == 0) {
return EMPTY;
} else if (str.length() - offset <= maxWidth) {
return offset == 0 ? str : str.substring(offset);
} else {
return str.substring(offset, offset + maxWidth);
}
}
// Delete
// -----------------------------------------------------------------------
/**
*
* Deletes all white spaces from a String as defined by
* {@link Character#isWhitespace(char)}.
*
*
*
* N.deleteWhitespace(null) = null
* N.deleteWhitespace("") = ""
* N.deleteWhitespace("abc") = "abc"
* N.deleteWhitespace(" ab c ") = "abc"
*
*
* @param str
* the String to delete whitespace from, may be null
* @return
*/
public static String deleteWhitespace(final String str) {
if (N.isNullOrEmpty(str)) {
return str;
}
final int len = str.length();
final char[] cbuf = new char[len];
int count = 0;
char ch = 0;
for (int i = 0; i < len; i++) {
ch = str.charAt(i);
if (!Character.isWhitespace(ch)) {
cbuf[count++] = ch;
}
}
return count == cbuf.length ? str : new String(cbuf, 0, count);
}
public static void deleteWhitespace(final String[] strs) {
if (N.isNullOrEmpty(strs)) {
return;
}
for (int i = 0, len = strs.length; i < len; i++) {
strs[i] = deleteWhitespace(strs[i]);
}
}
/**
* Append if missing.
*
* @param str
* @param suffix
* @return
*/
public static String appendIfMissing(final String str, final String suffix) {
N.checkArgNotNull(suffix);
if (N.isNullOrEmpty(str)) {
return suffix;
} else if (str.endsWith(suffix)) {
return str;
} else {
return str + suffix;
}
}
/**
*
* @param str
* @param suffix
* @return
*/
public static String appendIfMissingIgnoreCase(final String str, final String suffix) {
N.checkArgNotNull(suffix);
if (N.isNullOrEmpty(str)) {
return suffix;
} else if (Strings.endsWithIgnoreCase(str, suffix)) {
return str;
} else {
return str + suffix;
}
}
/**
* Prepend if missing.
*
* @param str
* @param prefix
* @return
*/
public static String prependIfMissing(final String str, final String prefix) {
N.checkArgNotNull(prefix);
if (N.isNullOrEmpty(str)) {
return prefix;
} else if (str.startsWith(prefix)) {
return str;
} else {
return prefix + str;
}
}
public static String prependIfMissingIgnoreCase(final String str, final String prefix) {
N.checkArgNotNull(prefix);
if (N.isNullOrEmpty(str)) {
return prefix;
} else if (Strings.startsWithIgnoreCase(str, prefix)) {
return str;
} else {
return prefix + str;
}
}
/**
* Wrap if missing.
*
* @param str
* @param prefixSuffix
* @return
*/
public static String wrapIfMissing(final String str, final String prefixSuffix) {
return wrapIfMissing(str, prefixSuffix, prefixSuffix);
}
/**
*
* N.wrapIfMissing(null, "[", "]") -> "[]"
* N.wrapIfMissing("", "[", "]") -> "[]"
* N.wrapIfMissing("[", "[", "]") -> "[]"
* N.wrapIfMissing("]", "[", "]") -> "[]"
* N.wrapIfMissing("abc", "[", "]") -> "[abc]"
* N.wrapIfMissing("a", "aa", "aa") -> "aaaaa"
* N.wrapIfMissing("aa", "aa", "aa") -> "aaaa"
* N.wrapIfMissing("aaa", "aa", "aa") -> "aaaaa"
* N.wrapIfMissing("aaaa", "aa", "aa") -> "aaaa"
*
*
* @param str
* @param prefix
* @param suffix
* @return
*/
public static String wrapIfMissing(final String str, final String prefix, final String suffix) {
N.checkArgNotNull(prefix);
N.checkArgNotNull(suffix);
if (N.isNullOrEmpty(str)) {
return prefix + suffix;
} else if (str.startsWith(prefix)) {
return (str.length() - prefix.length() >= suffix.length() && str.endsWith(suffix)) ? str : str + suffix;
} else if (str.endsWith(suffix)) {
return prefix + str;
} else {
return concat(prefix, str, suffix);
}
}
/**
*
* @param str
* @param prefixSuffix
* @return
*/
public static String wrap(final String str, final String prefixSuffix) {
return wrap(str, prefixSuffix, prefixSuffix);
}
/**
*
* N.wrap(null, "[", "]") -> "[]"
* N.wrap("", "[", "]") -> "[]"
* N.wrap("[", "[", "]") -> "[[]"
* N.wrap("]", "[", "]") -> "[]]"
* N.wrap("abc", "[", "]") -> "[abc]"
* N.wrap("a", "aa", "aa") -> "aaaaa"
* N.wrap("aa", "aa", "aa") -> "aaaaaa"
* N.wrap("aaa", "aa", "aa") -> "aaaaaaa"
*
*
* @param str
* @param prefix
* @param suffix
* @return
*/
public static String wrap(final String str, final String prefix, final String suffix) {
N.checkArgNotNull(prefix);
N.checkArgNotNull(suffix);
if (N.isNullOrEmpty(str)) {
return prefix + suffix;
} else {
return concat(prefix, str, suffix);
}
}
/**
*
* @param str
* @param prefixSuffix
* @return
*/
public static String unwrap(final String str, final String prefixSuffix) {
return unwrap(str, prefixSuffix, prefixSuffix);
}
/**
*
*
* Unwraps the specified string {@code str} if and only if it's wrapped by the specified {@code prefix} and {@code suffix}
*
*
*
* N.unwrap(null, "[", "]") -> ""
* N.unwrap("", "[", "]") -> ""
* N.unwrap("[", "[", "]") -> "["
* N.unwrap("]", "[", "]") -> "["
* N.unwrap("[abc]", "[", "]") -> "abc"
* N.unwrap("aaaaa", "aa", "aa") -> "a"
* N.unwrap("aa", "aa", "aa") -> "aa"
* N.unwrap("aaa", "aa", "aa") -> "aaa"
* N.unwrap("aaaa", "aa", "aa") -> ""
*
*
* @param str
* @param prefix
* @param suffix
* @return
*/
public static String unwrap(final String str, final String prefix, final String suffix) {
N.checkArgNotNull(prefix);
N.checkArgNotNull(suffix);
if (N.isNullOrEmpty(str)) {
return N.EMPTY_STRING;
} else if (str.length() - prefix.length() >= suffix.length() && str.startsWith(prefix) && str.endsWith(suffix)) {
return str.substring(prefix.length(), str.length() - suffix.length());
} else {
return str;
}
}
/**
* Checks if is lower case.
*
* @param ch
* @return true, if is lower case
*/
public static boolean isLowerCase(final char ch) {
return Character.isLowerCase(ch);
}
/**
* Checks if is ascii lower case.
*
* @param ch
* @return true, if is ascii lower case
*/
public static boolean isAsciiLowerCase(final char ch) {
return (ch >= 'a') && (ch <= 'z');
}
/**
* Checks if is upper case.
*
* @param ch
* @return true, if is upper case
*/
public static boolean isUpperCase(final char ch) {
return Character.isUpperCase(ch);
}
/**
* Checks if is ascii upper case.
*
* @param ch
* @return true, if is ascii upper case
*/
public static boolean isAsciiUpperCase(final char ch) {
return (ch >= 'A') && (ch <= 'Z');
}
/**
* Checks if is all lower case.
*
* @param cs
* @return true, if is all lower case
*/
public static boolean isAllLowerCase(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (Character.isUpperCase(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if is all upper case.
*
* @param cs
* @return true, if is all upper case
*/
public static boolean isAllUpperCase(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (Character.isLowerCase(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Copied from Apache Commons Lang: StringUtils#isMixedCase.
*
* @param cs
* @return true, if is mixed case
*/
public static boolean isMixedCase(final CharSequence cs) {
if (N.isNullOrEmpty(cs) || cs.length() == 1) {
return false;
}
boolean containsUppercase = false;
boolean containsLowercase = false;
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
if (containsUppercase && containsLowercase) {
return true;
}
ch = cs.charAt(i);
if (Character.isUpperCase(ch)) {
containsUppercase = true;
} else if (Character.isLowerCase(ch)) {
containsLowercase = true;
}
}
return containsUppercase && containsLowercase;
}
/**
* Checks if is digit.
*
* @param ch
* @return true, if is digit
* @see Character#isDigit(char)
*/
public static boolean isDigit(final char ch) {
return Character.isDigit(ch);
}
/**
* Checks if is letter.
*
* @param ch
* @return true, if is letter
* @see Character#isLetter(char)
*/
public static boolean isLetter(final char ch) {
return Character.isLetter(ch);
}
/**
* Checks if is letter or digit.
*
* @param ch
* @return true, if is letter or digit
* @see Character#isLetterOrDigit(char)
*/
public static boolean isLetterOrDigit(final char ch) {
return Character.isLetterOrDigit(ch);
}
// --------------------------------------------------------------------------
/**
*
* Checks whether the character is ASCII 7 bit.
*
*
*
* StringUtil.isAscii('a') = true
* StringUtil.isAscii('A') = true
* StringUtil.isAscii('3') = true
* StringUtil.isAscii('-') = true
* StringUtil.isAscii('\n') = true
* StringUtil.isAscii('©') = false
*
*
* @param ch
* the character to check
* @return true if less than 128
*/
public static boolean isAscii(final char ch) {
return ch < 128;
}
/**
*
* Checks whether the character is ASCII 7 bit printable.
*
*
*
* StringUtil.isAsciiPrintable('a') = true
* StringUtil.isAsciiPrintable('A') = true
* StringUtil.isAsciiPrintable('3') = true
* StringUtil.isAsciiPrintable('-') = true
* StringUtil.isAsciiPrintable('\n') = false
* StringUtil.isAsciiPrintable('©') = false
*
*
* @param ch
* the character to check
* @return true if between 32 and 126 inclusive
*/
public static boolean isAsciiPrintable(final char ch) {
return ch > 31 && ch < 127;
}
/**
*
* Checks whether the character is ASCII 7 bit control.
*
*
*
* StringUtil.isAsciiControl('a') = false
* StringUtil.isAsciiControl('A') = false
* StringUtil.isAsciiControl('3') = false
* StringUtil.isAsciiControl('-') = false
* StringUtil.isAsciiControl('\n') = true
* StringUtil.isAsciiControl('©') = false
*
*
* @param ch
* the character to check
* @return true if less than 32 or equals 127
*/
public static boolean isAsciiControl(final char ch) {
return ch < 32 || ch == 127;
}
/**
*
* Checks whether the character is ASCII 7 bit alphabetic.
*
*
*
* StringUtil.isAsciiAlpha('a') = true
* StringUtil.isAsciiAlpha('A') = true
* StringUtil.isAsciiAlpha('3') = false
* StringUtil.isAsciiAlpha('-') = false
* StringUtil.isAsciiAlpha('\n') = false
* StringUtil.isAsciiAlpha('©') = false
*
*
* @param ch
* the character to check
* @return true if between 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlpha(final char ch) {
return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
}
/**
*
* Checks whether the character is ASCII 7 bit alphabetic upper case.
*
*
*
* StringUtil.isAsciiAlphaUpper('a') = false
* StringUtil.isAsciiAlphaUpper('A') = true
* StringUtil.isAsciiAlphaUpper('3') = false
* StringUtil.isAsciiAlphaUpper('-') = false
* StringUtil.isAsciiAlphaUpper('\n') = false
* StringUtil.isAsciiAlphaUpper('©') = false
*
*
* @param ch
* the character to check
* @return true if between 65 and 90 inclusive
*/
public static boolean isAsciiAlphaUpper(final char ch) {
return ch >= 'A' && ch <= 'Z';
}
/**
*
* Checks whether the character is ASCII 7 bit alphabetic lower case.
*
*
*
* StringUtil.isAsciiAlphaLower('a') = true
* StringUtil.isAsciiAlphaLower('A') = false
* StringUtil.isAsciiAlphaLower('3') = false
* StringUtil.isAsciiAlphaLower('-') = false
* StringUtil.isAsciiAlphaLower('\n') = false
* StringUtil.isAsciiAlphaLower('©') = false
*
*
* @param ch
* the character to check
* @return true if between 97 and 122 inclusive
*/
public static boolean isAsciiAlphaLower(final char ch) {
return ch >= 'a' && ch <= 'z';
}
/**
*
* Checks whether the character is ASCII 7 bit numeric.
*
*
*
* StringUtil.isAsciiNumeric('a') = false
* StringUtil.isAsciiNumeric('A') = false
* StringUtil.isAsciiNumeric('3') = true
* StringUtil.isAsciiNumeric('-') = false
* StringUtil.isAsciiNumeric('\n') = false
* StringUtil.isAsciiNumeric('©') = false
*
*
* @param ch
* the character to check
* @return true if between 48 and 57 inclusive
*/
public static boolean isAsciiNumeric(final char ch) {
return ch >= '0' && ch <= '9';
}
/**
*
* Checks whether the character is ASCII 7 bit numeric.
*
*
*
* StringUtil.isAsciiAlphanumeric('a') = true
* StringUtil.isAsciiAlphanumeric('A') = true
* StringUtil.isAsciiAlphanumeric('3') = true
* StringUtil.isAsciiAlphanumeric('-') = false
* StringUtil.isAsciiAlphanumeric('\n') = false
* StringUtil.isAsciiAlphanumeric('©') = false
*
*
* @param ch
* the character to check
* @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlphanumeric(final char ch) {
return isAsciiAlpha(ch) || isAsciiNumeric(ch);
}
/**
* Checks if is ascii printable.
*
* @param cs
* @return true, if is ascii printable
*/
public static boolean isAsciiPrintable(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!isAsciiPrintable(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if is ascii alpha.
*
* @param cs
* @return true, if is ascii alpha
*/
public static boolean isAsciiAlpha(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!isAsciiAlpha(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if is ascii alpha space.
*
* @param cs
* @return true, if is ascii alpha space
*/
public static boolean isAsciiAlphaSpace(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
ch = cs.charAt(i);
if (!isAsciiAlpha(ch) && ch != ' ') {
return false;
}
}
return true;
}
/**
* Checks if is ascii alphanumeric.
*
* @param cs
* @return true, if is ascii alphanumeric
*/
public static boolean isAsciiAlphanumeric(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!isAsciiAlphanumeric(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Checks if is ascii alphanumeric space.
*
* @param cs
* @return true, if is ascii alphanumeric space
*/
public static boolean isAsciiAlphanumericSpace(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
ch = cs.charAt(i);
if (!isAsciiAlphanumeric(ch) && ch != ' ') {
return false;
}
}
return true;
}
/**
* Checks if is ascii numeric.
*
* @param cs
* @return true, if is ascii numeric
*/
public static boolean isAsciiNumeric(final CharSequence cs) {
if (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!isAsciiNumeric(cs.charAt(i))) {
return false;
}
}
return true;
}
// Character Tests
// -----------------------------------------------------------------------
/**
*
* Checks if the CharSequence contains only Unicode letters.
*
*
*
* {@code null} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isAlpha(null) = false
* N.isAlpha("") = false
* N.isAlpha(" ") = false
* N.isAlpha("abc") = true
* N.isAlpha("ab2c") = false
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!Character.isLetter(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
*
* Checks if the CharSequence contains only Unicode letters and space (' ').
*
*
*
* {@code null} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isAlphaSpace(null) = false
* N.isAlphaSpace("") = false
* N.isAlphaSpace(" ") = true
* N.isAlphaSpace("abc") = true
* N.isAlphaSpace("ab c") = true
* N.isAlphaSpace("ab2c") = false
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
ch = cs.charAt(i);
if (!Character.isLetter(ch) && ch != ' ') {
return false;
}
}
return true;
}
/**
*
* Checks if the CharSequence contains only Unicode letters or digits.
*
*
*
* {@code null} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isAlphanumeric(null) = false
* N.isAlphanumeric("") = false
* N.isAlphanumeric(" ") = false
* N.isAlphanumeric("abc") = true
* N.isAlphanumeric("ab c") = false
* N.isAlphanumeric("ab2c") = true
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; 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} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isAlphanumericSpace(null) = false
* N.isAlphanumericSpace("") = false
* N.isAlphanumericSpace(" ") = true
* N.isAlphanumericSpace("abc") = true
* N.isAlphanumericSpace("ab c") = true
* N.isAlphanumericSpace("ab2c") = true
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
ch = cs.charAt(i);
if (!Character.isLetterOrDigit(ch) && ch != ' ') {
return false;
}
}
return true;
}
/**
*
* 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.
*
*
*
* N.isNumeric(null) = false
* N.isNumeric("") = false
* N.isNumeric(" ") = false
* N.isNumeric("123") = true
* N.isNumeric("12 3") = false
* N.isNumeric("ab2c") = false
* N.isNumeric("12-3") = false
* N.isNumeric("12.3") = false
* N.isNumeric("-123") = false
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; 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} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isNumericSpace(null) = false
* N.isNumericSpace("") = false
* N.isNumericSpace(" ") = true
* N.isNumericSpace("123") = true
* N.isNumericSpace("12 3") = true
* N.isNumericSpace("ab2c") = false
* N.isNumericSpace("12-3") = false
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
char ch = 0;
for (int i = 0; i < len; i++) {
ch = cs.charAt(i);
if (!Character.isDigit(ch) && ch != ' ') {
return false;
}
}
return true;
}
/**
*
* Checks if the CharSequence contains only whitespace.
*
*
*
* {@code null} or empty CharSequence (length()=0) will return {@code false}
* .
*
*
*
* N.isWhitespace(null) = false
* N.isWhitespace("") = false
* N.isWhitespace(" ") = true
* N.isWhitespace("abc") = false
* N.isWhitespace("ab2c") = false
* N.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 (N.isNullOrEmpty(cs)) {
return false;
}
final int len = cs.length();
for (int i = 0; i < len; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
/**
* Note: It's copied from NumberUtils in Apache Commons Lang under Apache
* License 2.0
*
*
* Checks whether the String a valid Java number. true
is
* returned if there is a number which can be initialized by
* createNumber
with specified String.
*
*
*
* Null
and empty String will return false
.
*
*
* @param str
* the String
to check
* @return true
if the string is a correctly formatted number
* @since 3.3 the code supports hex {@code 0Xhhh} and octal {@code 0ddd}
* validation
*/
public static boolean isNumber(final String str) {
return Numbers.createNumber(str).isPresent();
}
/**
* true
is returned if the specified str
only
* includes characters ('0' ~ '9', '.', '-', '+', 'e').
* false
is return if the specified String is null/empty, or contains empty chars.
*
* "0" => true
* " 0.1 " => false
* "abc" => false
* "1 a" => false
* "2e10" => true
* "2E-10" => true
*
* @param str
* @return true, if is ascii digtal number
*/
public static boolean isAsciiDigtalNumber(final String str) {
if (N.isNullOrEmpty(str)) {
return false;
}
int count = 0;
final int len = str.length();
char ch = str.charAt(0);
int i = 0;
if (ch == '+' || ch == '-') {
i++;
}
for (; i < len; i++) {
ch = str.charAt(i);
if (ch >= '0' && ch <= '9') {
count++;
} else {
break;
}
}
if (i < len && str.charAt(i) == '.') {
if (count == 0) {
return false;
} else {
count = 0;
}
i++;
}
for (; i < len; i++) {
ch = str.charAt(i);
if (ch >= '0' && ch <= '9') {
count++;
} else {
break;
}
}
if (count == 0) {
return false;
}
if (i == len) {
return true;
}
ch = str.charAt(i);
if (ch != 'e' && ch != 'E') {
return false;
} else {
i++;
}
count = 0;
if (i < len && (str.charAt(i) == '+' || str.charAt(i) == '-')) {
i++;
}
for (; i < len; i++) {
ch = str.charAt(i);
if (ch >= '0' && ch <= '9') {
count++;
} else {
break;
}
}
if (count == 0) {
return false;
} else if (i == len) {
return true;
} else {
return false;
}
}
/**
* true
is returned if the specified str
only
* includes characters ('0' ~ '9', '-', '+' ).
* false
is return if the specified String is null/empty, or contains empty chars.
*
* "-123" => true
* "+123" => true
* "123" => true
* "+0" => true
* "-0" => true
* "0" => true
* " 0.1 " => false
* "abc" => false
* "1 a" => false
* "2e10" => false
*
* @param str
* @return true, if is ascii digtal integer
*/
public static boolean isAsciiDigtalInteger(final String str) {
if (N.isNullOrEmpty(str)) {
return false;
}
int count = 0;
final int len = str.length();
char ch = str.charAt(0);
int i = 0;
if (ch == '+' || ch == '-') {
i++;
}
for (; i < len; i++) {
ch = str.charAt(i);
if (ch >= '0' && ch <= '9') {
count++;
} else {
break;
}
}
if (count == 0) {
return false;
}
return i == len;
}
/**
*
* @param str
* @param targetChar
* @return
*/
public static int indexOf(final String str, final int targetChar) {
if (N.isNullOrEmpty(str)) {
return N.INDEX_NOT_FOUND;
}
return str.indexOf(targetChar);
}
/**
*
* @param str
* @param fromIndex
* @param targetChar
* @return
*/
public static int indexOf(final String str, final int fromIndex, final int targetChar) {
if (N.isNullOrEmpty(str)) {
return N.INDEX_NOT_FOUND;
}
return str.indexOf(targetChar, fromIndex);
}
/**
*
* @param str
* @param substr
* @return
*/
public static int indexOf(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
return str.indexOf(substr);
}
/**
*
* @param str
* @param fromIndex
* @param substr
* @return
*/
public static int indexOf(final String str, final int fromIndex, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length() - fromIndex) {
return N.INDEX_NOT_FOUND;
}
return str.indexOf(substr, fromIndex);
}
/**
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static int indexOfAny(final String str, final char... chs) {
return indexOfAny(str, 0, chs);
}
/**
*
*
* @param str
* @param fromIndex
* @param chs
* @return
*/
@SafeVarargs
public static int indexOfAny(final String str, final int fromIndex, final char... chs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(chs)) {
return N.INDEX_NOT_FOUND;
}
final int strLen = str.length();
final int strLast = strLen - 1;
final int chsLen = chs.length;
final int chsLast = chsLen - 1;
char ch = 0;
for (int i = fromIndex < 0 ? 0 : fromIndex; i < strLen; i++) {
ch = str.charAt(i);
for (int j = 0; j < chsLen; j++) {
if (chs[j] == ch) {
if (i < strLast && j < chsLast && Character.isHighSurrogate(ch)) {
// ch is a supplementary character
if (chs[j + 1] == str.charAt(i + 1)) {
return i;
}
} else {
return i;
}
}
}
}
return N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param substrs
* @return
* @see #smallestIndexOfAll(String, String...)
*/
@SafeVarargs
public static int indexOfAny(final String str, final String... substrs) {
return indexOfAny(str, 0, substrs);
}
/**
*
*
* @param str
* @param fromIndex
* @param substrs
* @return
* @see #smallestIndexOfAll(String, int, String...)
*/
@SafeVarargs
public static int indexOfAny(final String str, final int fromIndex, final String... substrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substrs)) {
return N.INDEX_NOT_FOUND;
}
int idx = 0;
for (int i = 0, len = substrs.length; i < len; i++) {
if (N.isNullOrEmpty(substrs[i])) {
continue;
}
idx = indexOf(str, fromIndex, substrs[i]);
if (idx != N.INDEX_NOT_FOUND) {
return idx;
}
}
return N.INDEX_NOT_FOUND;
}
/**
* Find the first index of any of a set of potential substrings.
*
* @param str
* @param substrs
* @return
* @see #indexOfAny(String, String...)
*/
@SafeVarargs
public static int smallestIndexOfAll(final String str, final String... substrs) {
return smallestIndexOfAll(str, 0, substrs);
}
/**
* Find the first index of any of a set of potential substrings from {@code fromIndex}.
*
*
* @param str
* @param fromIndex
* @param substrs
* @return
* @see #indexOfAny(String, int, String...)
*/
@SafeVarargs
public static int smallestIndexOfAll(final String str, final int fromIndex, final String... substrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substrs)) {
return N.INDEX_NOT_FOUND;
}
String srcStr = str;
int result = N.INDEX_NOT_FOUND;
int idx = 0;
for (int i = 0, len = substrs.length; i < len; i++) {
if (N.isNullOrEmpty(substrs[i])) {
continue;
}
idx = indexOf(srcStr, fromIndex, substrs[i]);
if (idx != N.INDEX_NOT_FOUND && (result == N.INDEX_NOT_FOUND || idx < result)) {
result = idx;
if (len - i > 1) {
int max = 0;
for (int j = i + 1; j < len; j++) {
max = N.max(max, N.len(substrs[j]));
}
if (max > 0 && idx + max < srcStr.length() * 0.8) {
srcStr = srcStr.substring(0, idx + max - 1);
}
}
}
}
return result;
}
/**
* Index of any but.
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static int indexOfAnyBut(final String str, final char... chs) {
return indexOfAnyBut(str, 0, chs);
}
@SafeVarargs
public static int indexOfAnyBut(final String str, final int fromIndex, final char... chs) {
if (N.isNullOrEmpty(str)) {
return N.INDEX_NOT_FOUND;
}
if (N.isNullOrEmpty(chs)) {
return 0;
}
final int strLen = str.length();
final int strLast = strLen - 1;
final int chsLen = chs.length;
final int chsLast = chsLen - 1;
char ch = 0;
outer: for (int i = fromIndex < 0 ? 0 : fromIndex; i < strLen; i++) {
ch = str.charAt(i);
for (int j = 0; j < chsLen; j++) {
if (chs[j] == ch) {
if (i < strLast && j < chsLast && Character.isHighSurrogate(ch)) {
if (chs[j + 1] == str.charAt(i + 1)) {
continue outer;
}
} else {
continue outer;
}
}
}
return i;
}
return N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param substr
* @param delimiter
* @return
*/
public static int indexOf(final String str, final String substr, final String delimiter) {
return indexOf(str, 0, substr, delimiter);
}
/**
*
* @param str
* @param fromIndex the index from which to start the search.
* @param substr
* @param delimiter
* @return
*/
public static int indexOf(final String str, final int fromIndex, final String substr, final String delimiter) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return N.INDEX_NOT_FOUND;
}
int index = str.indexOf(substr, fromIndex);
if (index < 0) {
return N.INDEX_NOT_FOUND;
}
if (index + substr.length() == str.length()) {
return index;
} else if (str.length() >= index + substr.length() + delimiter.length()) {
for (int i = 0, j = index + substr.length(), seperatorLen = delimiter.length(); i < seperatorLen;) {
if (delimiter.charAt(i++) != str.charAt(j++)) {
return N.INDEX_NOT_FOUND;
}
}
return index;
}
return N.INDEX_NOT_FOUND;
}
/**
* Index of ignore case.
*
* @param str
* @param substr
* @return
*/
public static int indexOfIgnoreCase(final String str, final String substr) {
return indexOfIgnoreCase(str, 0, substr);
}
/**
* Index of ignore case.
*
* @param str
* @param fromIndex
* @param substr
* @return
*/
public static int indexOfIgnoreCase(final String str, final int fromIndex, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length() - fromIndex) {
return N.INDEX_NOT_FOUND;
}
for (int i = fromIndex, len = str.length(), substrLen = substr.length(), end = len - substrLen + 1; i < end; i++) {
if (str.regionMatches(true, i, substr, 0, substrLen)) {
return i;
}
}
return N.INDEX_NOT_FOUND;
}
/**
*
* Finds the n-th index within a String, handling {@code null}.
*
*
* @param str
* @param substr
* @param ordinal the n-th {@code searchStr} to find
* @return
* {@code N.INDEX_NOT_FOUND}) if no match or {@code null} or empty
* string input
*/
public static int ordinalIndexOf(final String str, final String substr, final int ordinal) {
return ordinalIndexOf(str, substr, ordinal, false);
}
/**
* Last index of.
*
* @param str
* @param targetChar
* @return
*/
public static int lastIndexOf(final String str, final int targetChar) {
if (N.isNullOrEmpty(str)) {
return N.INDEX_NOT_FOUND;
}
return str.lastIndexOf(targetChar);
}
/**
* Returns the index within this string of the last occurrence of the
* specified character, searching backward starting at the specified index.
* For values of ch
in the range from 0 to 0xFFFF (inclusive),
* the index returned is the largest value k such that:
*
*
* (this.charAt(k ) == ch) && (k <= fromIndex)
*
*
* is true. For other values of ch
, it is the
* largest value k such that:
*
*
* (this.codePointAt(k ) == ch) && (k <= fromIndex)
*
*
* is true. In either case, if no such character occurs in
* this string at or before position fromIndex
, then
* -1
is returned.
*
*
* All indices are specified in char
values (Unicode code
* units).
*
* @param str
* @param fromIndex the index to start the search from. There is no restriction on
* the value of fromIndex
. If it is greater than or
* equal to the length of this string, it has the same effect as
* if it were equal to one less than the length of this string:
* this entire string may be searched. If it is negative, it has
* the same effect as if it were -1: -1 is returned.
* @param targetChar a character (Unicode code point).
* @return
* character sequence represented by this object that is less than
* or equal to fromIndex
, or -1
if the
* character does not occur before that point.
*/
public static int lastIndexOf(final String str, final int fromIndex, final int targetChar) {
if (N.isNullOrEmpty(str)) {
return N.INDEX_NOT_FOUND;
}
return str.lastIndexOf(targetChar, fromIndex);
}
/**
* Last index of.
*
* @param str
* @param substr
* @return
*/
public static int lastIndexOf(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
return str.lastIndexOf(substr);
}
/**
* Returns the index within str
of the last occurrence of the
* specified substr
, searching backward starting at the
* specified index.
*
*
* The returned index is the largest value k for which:
*
*
* k <= fromIndex && str.startsWith(substr, k )
*
*
* If no such value of k exists, then {@code -1} is
* returned.
*
* @param str
* @param fromIndex
* @param substr
* @return
*/
public static int lastIndexOf(final String str, final int fromIndex, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
return str.lastIndexOf(substr, fromIndex);
}
/**
* Last index of.
*
* @param str
* @param substr
* @param delimiter
* @return
*/
public static int lastIndexOf(final String str, final String substr, final String delimiter) {
return lastIndexOf(str, str.length(), substr, delimiter);
}
/**
* Last index of.
*
* @param str
* @param fromIndex the start index to traverse backwards from
* @param substr
* @param delimiter
* @return
*/
public static int lastIndexOf(final String str, final int fromIndex, final String substr, final String delimiter) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return N.INDEX_NOT_FOUND;
}
// int index = str.lastIndexOf(substr, min(fromIndex, str.length() -
// 1)); // Refer to String.lastIndexOf(String, int). the result is same
// as below line.
int index = str.lastIndexOf(substr, N.min(fromIndex, str.length()));
if (index < 0) {
return N.INDEX_NOT_FOUND;
}
if (index + substr.length() == str.length()) {
return index;
} else if (str.length() >= index + substr.length() + delimiter.length()) {
for (int i = 0, j = index + substr.length(), len = delimiter.length(); i < len;) {
if (delimiter.charAt(i++) != str.charAt(j++)) {
return N.INDEX_NOT_FOUND;
}
}
return index;
}
return N.INDEX_NOT_FOUND;
}
/**
* Last index of ignore case.
*
* @param str
* @param substr
* @return
*/
public static int lastIndexOfIgnoreCase(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
return lastIndexOfIgnoreCase(str, str.length(), substr);
}
/**
* Last index of ignore case.
*
* @param str
* @param fromIndex
* @param substr
* @return
*/
public static int lastIndexOfIgnoreCase(final String str, final int fromIndex, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
for (int i = N.min(fromIndex, str.length() - substr.length()), substrLen = substr.length(); i >= 0; i--) {
if (str.regionMatches(true, i, substr, 0, substrLen)) {
return i;
}
}
return N.INDEX_NOT_FOUND;
}
/**
* Last index of any.
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static int lastIndexOfAny(final String str, final char... chs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(chs)) {
return N.INDEX_NOT_FOUND;
}
int idx = 0;
for (char ch : chs) {
idx = str.lastIndexOf(ch);
if (idx != N.INDEX_NOT_FOUND) {
return idx;
}
}
final int strLen = str.length();
final int chsLen = chs.length;
char ch = 0;
for (int i = strLen - 1; i >= 0; i--) {
ch = str.charAt(i);
for (int j = chsLen - 1; j >= 0; j--) {
if (chs[j] == ch) {
if (i > 0 && j > 0 && Character.isHighSurrogate(ch = str.charAt(i - 1))) {
// ch is a supplementary character
if (chs[j - 1] == ch) {
return i - 1;
}
} else {
return i;
}
}
}
}
return N.INDEX_NOT_FOUND;
}
/**
* Last index of any.
*
* @param str
* @param substrs
* @return
* @see #largestIndexOfAll(String, String...)
*/
@SafeVarargs
public static int lastIndexOfAny(final String str, final String... substrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substrs)) {
return N.INDEX_NOT_FOUND;
}
int idx = 0;
for (String substr : substrs) {
if (N.isNullOrEmpty(substr)) {
continue;
}
idx = str.lastIndexOf(substr);
if (idx != N.INDEX_NOT_FOUND) {
return idx;
}
}
return N.INDEX_NOT_FOUND;
}
/**
* Last index of any.
*
* @param str
* @param substrs
* @return
* @see #lastIndexOfAny(String, String...)
*/
@SafeVarargs
public static int largestIndexOfAll(final String str, final String... substrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substrs)) {
return N.INDEX_NOT_FOUND;
}
int result = N.INDEX_NOT_FOUND;
int tmp = 0;
for (String substr : substrs) {
if (N.isNullOrEmpty(substr)) {
continue;
}
tmp = str.lastIndexOf(substr);
if (tmp != N.INDEX_NOT_FOUND && (result == N.INDEX_NOT_FOUND || tmp > result)) {
result = tmp;
// TODO performance improvement: refer to smallestIndexOfAll
}
}
return result;
}
/**
*
* Finds the n-th last index within a String, handling {@code null}.
*
*
* @param str
* @param substr
* @param ordinal the n-th last {@code searchStr} to find
* @return
* {@code N.INDEX_NOT_FOUND}) if no match or {@code null} or empty
* string input
*/
public static int lastOrdinalIndexOf(final String str, final String substr, final int ordinal) {
return ordinalIndexOf(str, substr, ordinal, true);
}
// Shared code between ordinalIndexOf(String,String,int) and
/**
* Ordinal index of.
*
* @param str
* @param substr
* @param ordinal
* @param isLastIndex
* @return
*/
// lastOrdinalIndexOf(String,String,int)
private static int ordinalIndexOf(final String str, final String substr, final int ordinal, final boolean isLastIndex) {
if (ordinal < 1) {
throw new IllegalArgumentException("ordinal(" + ordinal + ") must be >= 1");
}
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr) || substr.length() > str.length()) {
return N.INDEX_NOT_FOUND;
}
int fromIndex = isLastIndex ? str.length() : 0;
for (int found = 0; fromIndex >= 0;) {
fromIndex = isLastIndex ? str.lastIndexOf(substr, fromIndex) : str.indexOf(substr, fromIndex);
if (fromIndex < 0) {
return N.INDEX_NOT_FOUND;
}
if (++found >= ordinal) {
break;
}
fromIndex = isLastIndex ? (fromIndex - substr.length()) : (fromIndex + substr.length());
}
return fromIndex;
}
/**
*
* @param str
* @param substr
* @return
* @see N#occurrencesOf(String, String)
*/
public static int occurrencesOf(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return 0;
}
int occurrences = 0;
for (int len = N.len(str), substrLen = N.len(substr), index = 0, fromIndex = 0, toIndex = len - substrLen; fromIndex <= toIndex;) {
index = str.indexOf(substr, fromIndex);
if (index < 0) {
break;
} else {
fromIndex = index + substrLen;
occurrences++;
}
}
return occurrences;
}
/**
*
* @param str
* @param targetChar
* @return
*/
public static boolean contains(final String str, final int targetChar) {
if (N.isNullOrEmpty(str)) {
return false;
}
return indexOf(str, targetChar) != N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param substr
* @return
*/
public static boolean contains(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return false;
}
return indexOf(str, substr) != N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param substr
* @param delimiter
* @return
*/
public static boolean contains(final String str, final String substr, final String delimiter) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return false;
}
return indexOf(str, substr, delimiter) != N.INDEX_NOT_FOUND;
}
/**
* Contains ignore case.
*
* @param str
* @param substr
* @return
*/
public static boolean containsIgnoreCase(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return false;
}
return indexOfIgnoreCase(str, substr) != N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static boolean containsAny(final String str, final char... chs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(chs)) {
return false;
}
return indexOfAny(str, chs) != N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param searchStrs
* @return
*/
@SafeVarargs
public static boolean containsAny(final String str, final String... searchStrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(searchStrs)) {
return false;
}
return indexOfAny(str, searchStrs) != N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param searchStrs
* @return
*/
@SafeVarargs
public static boolean containsAnyIgnoreCase(final String str, final String... searchStrs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(searchStrs)) {
return false;
} else if (searchStrs.length == 1) {
return containsIgnoreCase(str, searchStrs[0]);
} else if (searchStrs.length == 2) {
if (containsIgnoreCase(str, searchStrs[0])) {
return true;
}
return containsIgnoreCase(str, searchStrs[1]);
}
final String sourceText = str.toLowerCase();
for (String searchStr : searchStrs) {
if (N.notNullOrEmpty(searchStr) && indexOf(sourceText, searchStr.toLowerCase()) != N.INDEX_NOT_FOUND) {
return true;
}
}
return false;
}
/**
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static boolean containsOnly(final String str, final char... chs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(chs)) {
return false;
}
return indexOfAnyBut(str, chs) == N.INDEX_NOT_FOUND;
}
/**
*
* @param str
* @param chs
* @return
*/
@SafeVarargs
public static boolean containsNone(final String str, final char... chs) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(chs)) {
return true;
}
final int strLen = str.length();
final int strLast = strLen - 1;
final int chsLen = chs.length;
final int chsLast = chsLen - 1;
char ch = 0;
for (int i = 0; i < strLen; i++) {
ch = str.charAt(i);
for (int j = 0; j < chsLen; j++) {
if (chs[j] == ch) {
if (Character.isHighSurrogate(ch)) {
if ((j == chsLast) || (i < strLast && chs[j + 1] == str.charAt(i + 1))) {
return false;
}
} else {
// ch is in the Basic Multilingual Plane
return false;
}
}
}
}
return true;
}
/**
*
* @param str
* @return
*/
// From org.springframework.util.StringUtils, under Apache License 2.0
public static boolean containsWhitespace(final String str) {
if (N.isNullOrEmpty(str)) {
return false;
}
for (int i = 0, len = str.length(); i < len; i++) {
if (Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
/**
*
* @param str
* @param prefix
* @return
*/
public static boolean startsWith(final String str, final String prefix) {
return startsWith(str, prefix, false);
}
/**
* Starts with ignore case.
*
* @param str
* @param prefix
* @return
*/
public static boolean startsWithIgnoreCase(final String str, final String prefix) {
return startsWith(str, prefix, true);
}
/**
*
* @param str
* @param prefix
* @param ignoreCase
* @return
*/
private static boolean startsWith(final String str, final String prefix, final boolean ignoreCase) {
if (str == null || prefix == null || prefix.length() > str.length()) {
return false;
}
return ignoreCase ? str.regionMatches(true, 0, prefix, 0, prefix.length()) : str.startsWith(prefix);
}
/**
* Starts with any.
*
* @param str
* @param substrs
* @return
*/
@SafeVarargs
public static boolean startsWithAny(final String str, final String... substrs) {
if (str == null || N.isNullOrEmpty(substrs)) {
return false;
}
for (final String substr : substrs) {
if (startsWith(str, substr)) {
return true;
}
}
return false;
}
/**
*
* @param str
* @param suffix
* @return
*/
public static boolean endsWith(final String str, final String suffix) {
return endsWith(str, suffix, false);
}
/**
* Ends with ignore case.
*
* @param str
* @param suffix
* @return
*/
public static boolean endsWithIgnoreCase(final String str, final String suffix) {
return endsWith(str, suffix, true);
}
/**
*
* @param str
* @param suffix
* @param ignoreCase
* @return
*/
private static boolean endsWith(final String str, final String suffix, final boolean ignoreCase) {
if (str == null || suffix == null || suffix.length() > str.length()) {
return false;
}
final int strOffset = str.length() - suffix.length();
return ignoreCase ? str.regionMatches(true, strOffset, suffix, 0, suffix.length()) : str.endsWith(suffix);
}
/**
* Ends with any.
*
* @param str
* @param substrs
* @return
*/
@SafeVarargs
public static boolean endsWithAny(final String str, final String... substrs) {
if (str == null || N.isNullOrEmpty(substrs)) {
return false;
}
for (final String searchString : substrs) {
if (endsWith(str, searchString)) {
return true;
}
}
return false;
}
/**
*
* @param a
* @param b
* @return
*/
public static boolean equals(final String a, final String b) {
return (a == null) ? b == null : (b == null ? false : a.length() == b.length() && a.equals(b));
}
/**
* Equals with any.
*
* @param str
* @param searchStrings
* @return
*/
@SafeVarargs
public static boolean equalsAny(final String str, final String... searchStrings) {
if (N.isNullOrEmpty(searchStrings)) {
return false;
}
for (final String searchString : searchStrings) {
if (equals(str, searchString)) {
return true;
}
}
return false;
}
/**
* Equals with any.
*
* @param str
* @param searchStrs
* @return
*/
@SafeVarargs
public static boolean equalsAnyIgnoreCase(final String str, final String... searchStrs) {
if (N.isNullOrEmpty(searchStrs)) {
return false;
} else if (searchStrs.length == 1) {
return equalsIgnoreCase(str, searchStrs[0]);
} else if (searchStrs.length == 2) {
if (equalsIgnoreCase(str, searchStrs[0])) {
return true;
}
return equalsIgnoreCase(str, searchStrs[1]);
}
final String sourceText = str.toLowerCase();
for (String searchStr : searchStrs) {
if (equals(sourceText, searchStr.toLowerCase())) {
return true;
}
}
return false;
}
/**
* Equals ignore case.
*
* @param a
* @param b
* @return
*/
public static boolean equalsIgnoreCase(final String a, final String b) {
return (a == null) ? b == null : (b == null ? false : a.equalsIgnoreCase(b));
}
/**
*
* Compares two Strings, and returns the index at which the Stringss begin
* to differ.
*
*
*
* For example,
* {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
*
*
*
* N.indexOfDifference(null, null) = -1
* N.indexOfDifference("", "") = -1
* N.indexOfDifference("", "abc") = 0
* N.indexOfDifference("abc", "") = 0
* N.indexOfDifference("abc", "abc") = -1
* N.indexOfDifference("ab", "abxyz") = 2
* N.indexOfDifference("abcde", "abxyz") = 2
* N.indexOfDifference("abcde", "xyz") = 0
*
*
* @param a
* the first String, may be null
* @param b
* the second String, may be null
* @return
*/
public static int indexOfDifference(final String a, final String b) {
if (N.equals(a, b) || (N.isNullOrEmpty(a) && N.isNullOrEmpty(b))) {
return N.INDEX_NOT_FOUND;
}
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return 0;
}
int i = 0;
for (int len = N.min(a.length(), b.length()); i < len; i++) {
if (a.charAt(i) != b.charAt(i)) {
break;
}
}
if (i < b.length() || i < a.length()) {
return i;
}
return N.INDEX_NOT_FOUND;
}
/**
*
* Compares all Strings in an array and returns the index at which the
* Strings begin to differ.
*
*
*
* For example,
* indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7
*
*
*
* N.indexOfDifference(null) = -1
* N.indexOfDifference(new String[] {}) = -1
* N.indexOfDifference(new String[] {"abc"}) = -1
* N.indexOfDifference(new String[] {null, null}) = -1
* N.indexOfDifference(new String[] {"", ""}) = -1
* N.indexOfDifference(new String[] {"", null}) = -1
* N.indexOfDifference(new String[] {"abc", null, null}) = 0
* N.indexOfDifference(new String[] {null, null, "abc"}) = 0
* N.indexOfDifference(new String[] {"", "abc"}) = 0
* N.indexOfDifference(new String[] {"abc", ""}) = 0
* N.indexOfDifference(new String[] {"abc", "abc"}) = -1
* N.indexOfDifference(new String[] {"abc", "a"}) = 1
* N.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
* N.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
* N.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
* N.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
* N.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
*
*
* @param strs
* array of Strings, entries may be null
* @return
* equal or null/empty
*/
@SafeVarargs
public static int indexOfDifference(final String... strs) {
if (N.isNullOrEmpty(strs) || strs.length == 1) {
return N.INDEX_NOT_FOUND;
}
final int arrayLen = strs.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 (int i = 0; i < arrayLen; i++) {
if (strs[i] == null) {
shortestStrLen = 0;
} else {
shortestStrLen = Math.min(strs[i].length(), shortestStrLen);
longestStrLen = Math.max(strs[i].length(), longestStrLen);
}
}
// handle lists containing all nulls or all empty strings
if (longestStrLen == 0) {
return N.INDEX_NOT_FOUND;
}
if (shortestStrLen == 0) {
return 0;
}
// find the position with the first difference across all strings
int firstDiff = -1;
char comparisonChar = 0;
for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
comparisonChar = strs[0].charAt(stringPos);
for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
if (strs[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;
}
// --------- from Google Guava
/**
* Note: copy rights: Google Guava.
*
* Returns the longest string {@code prefix} such that
* {@code a.toString().startsWith(prefix) && b.toString().startsWith(prefix)}
* , taking care not to split surrogate pairs. If {@code a} and {@code b}
* have no common prefix, returns the empty string.
*
* @param a
* @param b
* @return
*/
public static String commonPrefix(final String a, final String b) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return N.EMPTY_STRING;
}
int maxPrefixLength = Math.min(a.length(), b.length());
int p = 0;
while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) {
p++;
}
if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
p--;
}
if (p == a.length()) {
return a;
} else if (p == b.length()) {
return b;
} else {
return a.subSequence(0, p).toString();
}
}
/**
*
* @param strs
* @return
*/
@SafeVarargs
public static String commonPrefix(final String... strs) {
if (N.isNullOrEmpty(strs)) {
return N.EMPTY_STRING;
}
if (strs.length == 1) {
return N.isNullOrEmpty(strs[0]) ? N.EMPTY_STRING : strs[0];
}
String commonPrefix = commonPrefix(strs[0], strs[1]);
if (N.isNullOrEmpty(commonPrefix)) {
return N.EMPTY_STRING;
}
for (int i = 2, len = strs.length; i < len; i++) {
commonPrefix = commonPrefix(commonPrefix, strs[i]);
if (N.isNullOrEmpty(commonPrefix)) {
return commonPrefix;
}
}
return commonPrefix;
}
/**
* Note: copy rights: Google Guava.
*
* Returns the longest string {@code suffix} such that
* {@code a.toString().endsWith(suffix) && b.toString().endsWith(suffix)},
* taking care not to split surrogate pairs. If {@code a} and {@code b} have
* no common suffix, returns the empty string.
*
* @param a
* @param b
* @return
*/
public static String commonSuffix(final String a, final String b) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return N.EMPTY_STRING;
}
final int aLength = a.length();
final int bLength = b.length();
int maxSuffixLength = Math.min(aLength, bLength);
int s = 0;
while (s < maxSuffixLength && a.charAt(aLength - s - 1) == b.charAt(bLength - s - 1)) {
s++;
}
if (validSurrogatePairAt(a, aLength - s - 1) || validSurrogatePairAt(b, bLength - s - 1)) {
s--;
}
if (s == aLength) {
return a;
} else if (s == bLength) {
return b;
} else {
return a.subSequence(aLength - s, aLength).toString();
}
}
/**
*
* @param strs
* @return
*/
@SafeVarargs
public static String commonSuffix(final String... strs) {
if (N.isNullOrEmpty(strs)) {
return N.EMPTY_STRING;
}
if (strs.length == 1) {
return N.isNullOrEmpty(strs[0]) ? N.EMPTY_STRING : strs[0];
}
String commonSuffix = commonSuffix(strs[0], strs[1]);
if (N.isNullOrEmpty(commonSuffix)) {
return N.EMPTY_STRING;
}
for (int i = 2, len = strs.length; i < len; i++) {
commonSuffix = commonSuffix(commonSuffix, strs[i]);
if (N.isNullOrEmpty(commonSuffix)) {
return commonSuffix;
}
}
return commonSuffix;
}
// --------- from Google Guava
/**
* Note: copy rights: Google Guava.
*
* True when a valid surrogate pair starts at the given {@code index} in the
* given {@code string}. Out-of-range indexes return false.
*
* @param str
* @param index
* @return
*/
static boolean validSurrogatePairAt(final String str, final int index) {
return index >= 0 && index <= (str.length() - 2) && Character.isHighSurrogate(str.charAt(index)) && Character.isLowSurrogate(str.charAt(index + 1));
}
/**
*
* @param a
* @param b
* @return an empty String {@code ""} is {@code a} or {@code b} is empty or {@code null}.
*/
public static String longestCommonSubstring(final String a, final String b) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return N.EMPTY_STRING;
}
final int lenA = N.len(a);
final int lenB = N.len(b);
final int[] dp = new int[lenB + 1];
int endIndex = 0;
int maxLen = 0;
if (lenA > 16 || lenB > 16) {
final char[] chsA = a.toCharArray();
final char[] chsB = b.toCharArray();
for (int i = 1; i <= lenA; i++) {
for (int j = lenB; j > 0; j--) {
if (chsA[i - 1] == chsB[j - 1]) {
dp[j] = 1 + dp[j - 1];
if (dp[j] > maxLen) {
maxLen = dp[j];
endIndex = i;
}
} else {
dp[j] = 0;
}
}
}
} else {
for (int i = 1; i <= lenA; i++) {
for (int j = lenB; j > 0; j--) {
if (a.charAt(i - 1) == b.charAt(j - 1)) {
dp[j] = 1 + dp[j - 1];
if (dp[j] > maxLen) {
maxLen = dp[j];
endIndex = i;
}
} else {
dp[j] = 0;
}
}
}
}
if (maxLen == 0) {
return N.EMPTY_STRING;
}
return a.substring(endIndex - maxLen, endIndex);
}
/**
*
* @param str
* @param ch
* @return
*/
public static int countMatches(final String str, final char ch) {
if (N.isNullOrEmpty(str)) {
return 0;
}
int count = 0;
for (int i = 0, len = str.length(); i < len; i++) {
if (str.charAt(i) == ch) {
count++;
}
}
return count;
}
/**
*
* @param str
* @param substr
* @return
*/
public static int countMatches(final String str, final String substr) {
if (N.isNullOrEmpty(str) || N.isNullOrEmpty(substr)) {
return 0;
}
int count = 0;
int index = 0;
while ((index = str.indexOf(substr, index)) != N.INDEX_NOT_FOUND) {
count++;
index += substr.length();
}
return count;
}
/**
* Returns {@code null} if {@code inclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || inclusiveBeginIndex > exclusiveEndIndex},
* otherwise the {@code substring} with String value: {@code str.substring(exclusiveBeginIndex, exclusiveEndIndex)} is returned.
*
* @param str
* @param inclusiveBeginIndex
* @param exclusiveEndIndex
* @return
*/
public static String substring(String str, int inclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || inclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || inclusiveBeginIndex > exclusiveEndIndex) {
return null;
}
return str.substring(inclusiveBeginIndex, exclusiveEndIndex);
}
/**
* Returns {@code null} if {@code inclusiveBeginIndex < 0},
* otherwise the {@code substring} with String value: {@code str.substring(inclusiveBeginIndex)} is returned.
*
* @param str
* @param inclusiveBeginIndex
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, int inclusiveBeginIndex) {
if (str == null || inclusiveBeginIndex < 0) {
return null;
}
return str.substring(inclusiveBeginIndex);
}
/**
* Returns {@code null} if {@code N.isNullOrEmpty(str) || str.indexOf(delimiterOfInclusiveBeginIndex) < 0},
* otherwise the {@code substring} with String value: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))} is returned.
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)}
* @return
* @see #substring(String, int)
*/
public static String substring(String str, char delimiterOfInclusiveBeginIndex) {
if (str == null || str.length() == 0) {
return null;
}
return substring(str, str.indexOf(delimiterOfInclusiveBeginIndex));
}
/**
* Returns {@code null} if {@code N.isNullOrEmpty(str) || str.indexOf(delimiterOfInclusiveBeginIndex) < 0},
* otherwise the {@code substring} with String value: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))} is returned.
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)}
* @return
* @see #substring(String, int)
*/
public static String substring(String str, String delimiterOfInclusiveBeginIndex) {
if (str == null || delimiterOfInclusiveBeginIndex == null) {
return null;
}
return substring(str, str.indexOf(delimiterOfInclusiveBeginIndex));
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) if inclusiveBeginIndex >= 0}
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, int inclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
if (str == null || str.length() == 0 || inclusiveBeginIndex < 0) {
return null;
}
return substring(str, inclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1));
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) if inclusiveBeginIndex >= 0}
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, int inclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
if (str == null || inclusiveBeginIndex < 0 || delimiterOfExclusiveEndIndex == null) {
return null;
}
if (delimiterOfExclusiveEndIndex.length() == 0) {
return str.substring(inclusiveBeginIndex, inclusiveBeginIndex);
} else {
return substring(str, inclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1));
}
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0}
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, int inclusiveBeginIndex, IntUnaryOperator funcOfExclusiveEndIndex) {
if (str == null || inclusiveBeginIndex < 0) {
return null;
}
return substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex));
}
/**
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, char delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveEndIndex <= 0) {
return null;
}
return substring(str, str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1), exclusiveEndIndex);
}
/**
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, String delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || delimiterOfInclusiveBeginIndex == null || exclusiveEndIndex < 0) {
return null;
}
if (delimiterOfInclusiveBeginIndex.length() == 0) {
return str.substring(exclusiveEndIndex, exclusiveEndIndex);
} else if (exclusiveEndIndex == 0) {
return null;
} else {
return substring(str, str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1), exclusiveEndIndex);
}
}
/**
*
* @param str
* @param funcOfInclusiveBeginIndex {@code inclusiveBeginIndex <- funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substring(String, int, int)
*/
public static String substring(String str, IntUnaryOperator funcOfInclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || exclusiveEndIndex < 0) {
return null;
}
return substring(str, funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex), exclusiveEndIndex);
}
/**
* Returns the substring after first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @return
*/
public static String substringAfter(String str, String delimiterOfExclusiveBeginIndex) {
if (str == null || delimiterOfExclusiveBeginIndex == null) {
return null;
}
int index = str.indexOf(delimiterOfExclusiveBeginIndex);
if (index < 0) {
return null;
}
return str.substring(index + delimiterOfExclusiveBeginIndex.length());
}
/**
* Returns the substring after last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @return
*/
public static String substringAfterLast(String str, String delimiterOfExclusiveBeginIndex) {
if (str == null || delimiterOfExclusiveBeginIndex == null) {
return null;
}
int index = str.lastIndexOf(delimiterOfExclusiveBeginIndex);
if (index < 0) {
return null;
}
return str.substring(index + delimiterOfExclusiveBeginIndex.length());
}
/**
* Returns the substring before first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveEndIndex
* @return
*/
public static String substringBefore(String str, String delimiterOfExclusiveEndIndex) {
if (str == null || delimiterOfExclusiveEndIndex == null) {
return null;
}
int index = str.indexOf(delimiterOfExclusiveEndIndex);
if (index < 0) {
return null;
}
return str.substring(0, index);
}
/**
* Returns the substring before last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveEndIndex
* @return
*/
public static String substringBeforeLast(String str, String delimiterOfExclusiveEndIndex) {
if (str == null || delimiterOfExclusiveEndIndex == null) {
return null;
}
int index = str.lastIndexOf(delimiterOfExclusiveEndIndex);
if (index < 0) {
return null;
}
return str.substring(0, index);
}
/**
* Returns {@code null} if {@code exclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || exclusiveBeginIndex >= exclusiveEndIndex},
* otherwise the {@code substring} with String value: {@code str.substring(exclusiveBeginIndex + 1, exclusiveEndIndex)} is returned.
*
* @param str
* @param exclusiveBeginIndex
* @param exclusiveEndIndex
* @return
*/
public static String substringBetween(String str, int exclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || exclusiveBeginIndex >= exclusiveEndIndex) {
return null;
}
return str.substring(exclusiveBeginIndex + 1, exclusiveEndIndex);
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, beginIndex + 1) if exclusiveBeginIndex >= 0}
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, int exclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveBeginIndex < 0) {
return null;
}
return substringBetween(str, exclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, exclusiveBeginIndex + 1));
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, beginIndex + 1) if exclusiveBeginIndex >= 0}
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, int exclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveBeginIndex < 0 || delimiterOfExclusiveEndIndex == null || delimiterOfExclusiveEndIndex.length() == 0) {
return null;
}
return substringBetween(str, exclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, exclusiveBeginIndex + 1));
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0}
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, int exclusiveBeginIndex, IntUnaryOperator funcOfExclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveBeginIndex < 0) {
return null;
}
return substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex.applyAsInt(exclusiveBeginIndex));
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex {@code exclusiveBeginIndex <- str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, char delimiterOfExclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveEndIndex <= 0) {
return null;
}
return substringBetween(str, str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1), exclusiveEndIndex);
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex {@code exclusiveBeginIndex <- str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1) + delimiterOfExclusiveBeginIndex.length() - 1 if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, String delimiterOfExclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || str.length() == 0 || delimiterOfExclusiveBeginIndex == null || delimiterOfExclusiveBeginIndex.length() == 0
|| exclusiveEndIndex <= 0) {
return null;
}
final int index = str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1);
final int exclusiveBeginIndex = index >= 0 ? index + delimiterOfExclusiveBeginIndex.length() - 1 : index;
return substringBetween(str, exclusiveBeginIndex, exclusiveEndIndex);
}
/**
*
* @param str
* @param funcOfExclusiveBeginIndex {@code exclusiveBeginIndex <- funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, IntUnaryOperator funcOfExclusiveBeginIndex, int exclusiveEndIndex) {
if (str == null || str.length() == 0 || exclusiveEndIndex <= 0) {
return null;
}
return substringBetween(str, funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex), exclusiveEndIndex);
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, char delimiterOfExclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
if (str == null || str.length() == 0) {
return null;
}
final int start = str.indexOf(delimiterOfExclusiveBeginIndex);
if (start < 0) {
return null;
}
final int end = str.indexOf(delimiterOfExclusiveEndIndex, start + 1);
if (end < 0) {
return null;
}
return substringBetween(str, start, end);
}
/**
*
* @param str
* @param tag
* @return
* @see #substringBetween(String, String, String)
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, String tag) {
return substringBetween(str, tag, tag);
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, String delimiterOfExclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
return substringBetween(str, 0, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex);
}
/**
*
* @param str
* @param fromIndex start index for {@code delimiterOfExclusive}. {@code str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex)}
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static String substringBetween(String str, int fromIndex, String delimiterOfExclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
if (str == null || str.length() == 0 || delimiterOfExclusiveBeginIndex == null || delimiterOfExclusiveBeginIndex.length() == 0
|| delimiterOfExclusiveEndIndex == null || delimiterOfExclusiveEndIndex.length() == 0) {
return null;
}
final int start = fromIndex == 0 ? str.indexOf(delimiterOfExclusiveBeginIndex) : str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex);
if (start < 0) {
return null;
}
final int end = str.indexOf(delimiterOfExclusiveEndIndex, start + delimiterOfExclusiveBeginIndex.length());
if (end < 0) {
return null;
}
return substringBetween(str, start + delimiterOfExclusiveBeginIndex.length() - 1, end);
}
/**
* findAllIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]
.
*
* @param str
* @param prefix
* @param postfix
* @return
*/
public static List findAllIndicesBetween(final String str, final char prefix, final char postfix) {
return N.isNullOrEmpty(str) ? new ArrayList<>() : findAllIndicesBetween(str, 0, str.length(), prefix, postfix);
}
/**
* findAllIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]
.
*
* @param str
* @param fromIndex
* @param toIndex
* @param prefix
* @param postfix
* @return
*/
public static List findAllIndicesBetween(final String str, final int fromIndex, final int toIndex, final char prefix, final char postfix) {
N.checkFromToIndex(fromIndex, toIndex, N.len(str));
final List res = new ArrayList<>();
if (N.isNullOrEmpty(str)) {
return res;
}
int idx = str.indexOf(prefix, fromIndex);
if (idx < 0) {
return res;
}
final Deque queue = new LinkedList<>();
char ch = 0;
for (int i = idx; i < toIndex; i++) {
ch = str.charAt(i);
if (ch == prefix) {
queue.push(i + 1);
} else if (ch == postfix && queue.size() > 0) {
final int startIndex = queue.pop();
if (res.size() > 0 && startIndex < res.get(res.size() - 1)._1) {
while (res.size() > 0 && startIndex < res.get(res.size() - 1)._1) {
res.remove(res.size() - 1);
}
}
res.add(IntPair.of(startIndex, i));
}
}
return res;
}
/**
* findAllIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]
.
*
* @param str
* @param prefix
* @param postfix
* @return
*/
public static List findAllIndicesBetween(final String str, final String prefix, final String postfix) {
return N.isNullOrEmpty(str) ? new ArrayList<>() : findAllIndicesBetween(str, 0, str.length(), prefix, postfix);
}
/**
* findAllIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]
.
*
* @param str
* @param fromIndex
* @param toIndex
* @param prefix
* @param postfix
* @return
*/
public static List findAllIndicesBetween(final String str, final int fromIndex, final int toIndex, final String prefix, final String postfix) {
N.checkFromToIndex(fromIndex, toIndex, N.len(str));
final List res = new ArrayList<>();
if (N.isNullOrEmpty(str)) {
return res;
}
int idx = str.indexOf(prefix, fromIndex);
if (idx < 0) {
return res;
}
final Deque queue = new LinkedList<>();
queue.add(idx + prefix.length());
int next = -1;
for (int i = idx + prefix.length(), len = toIndex; i < len;) {
if (queue.size() == 0) {
idx = next >= i ? next : str.indexOf(prefix, i);
if (idx < 0) {
break;
} else {
queue.add(idx + prefix.length());
i = idx + prefix.length();
}
}
idx = str.indexOf(postfix, i);
if (idx < 0) {
break;
} else {
final int endIndex = idx;
idx = res.size() > 0 ? Math.max(res.get(res.size() - 1)._2 + postfix.length(), queue.peekLast()) : queue.peekLast();
while ((idx = str.indexOf(prefix, idx)) >= 0 && idx < endIndex) {
queue.push(idx + prefix.length());
idx = idx + prefix.length();
}
if (idx > 0) {
next = idx;
}
final int startIndex = queue.pop();
if (res.size() > 0 && startIndex < res.get(res.size() - 1)._1) {
while (res.size() > 0 && startIndex < res.get(res.size() - 1)._1) {
res.remove(res.size() - 1);
}
}
res.add(IntPair.of(startIndex, endIndex));
i = endIndex + postfix.length();
}
}
return res;
}
/**
* findAllSubstringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]
.
*
* @param str
* @param prefix
* @param postfix
* @return
*/
public static List findAllSubstringsBetween(final String str, final char prefix, final char postfix) {
return N.isNullOrEmpty(str) ? new ArrayList<>() : findAllSubstringsBetween(str, 0, str.length(), prefix, postfix);
}
/**
* findAllSubstringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]
.
*
* @param str
* @param fromIndex
* @param toIndex
* @param prefix
* @param postfix
* @return
*/
public static List findAllSubstringsBetween(final String str, final int fromIndex, final int toIndex, final char prefix, final char postfix) {
final List points = findAllIndicesBetween(str, fromIndex, toIndex, prefix, postfix);
final List res = new ArrayList<>(points.size());
for (IntPair p : points) {
res.add(str.substring(p._1, p._2));
}
return res;
}
/**
* findAllSubstringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]
.
*
* @param str
* @param prefix
* @param postfix
* @return
*/
public static List findAllSubstringsBetween(final String str, final String prefix, final String postfix) {
return N.isNullOrEmpty(str) ? new ArrayList<>() : findAllSubstringsBetween(str, 0, str.length(), prefix, postfix);
}
/**
* findAllSubstringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]
.
*
* @param str
* @param fromIndex
* @param toIndex
* @param prefix
* @param postfix
* @return
*/
public static List findAllSubstringsBetween(final String str, final int fromIndex, final int toIndex, final String prefix, final String postfix) {
final List points = findAllIndicesBetween(str, fromIndex, toIndex, prefix, postfix);
final List res = new ArrayList<>(points.size());
for (IntPair p : points) {
res.add(str.substring(p._1, p._2));
}
return res;
}
/**
*
* @param str
* @return
*/
public static OptionalChar firstChar(final String str) {
if (str == null || str.length() == 0) {
return OptionalChar.empty();
}
return OptionalChar.of(str.charAt(0));
}
/**
*
* @param str
* @return
*/
public static OptionalChar lastChar(final String str) {
if (str == null || str.length() == 0) {
return OptionalChar.empty();
}
return OptionalChar.of(str.charAt(str.length() - 1));
}
/**
* Returns the first {@code n} chars of the specified {@code String} if its length is bigger than {@code n},
* or an empty String {@code ""} if {@code str} is empty or null, or itself it's length equal to or less than {@code n}.
*
* @param str
* @param n
* @return
*/
public static String firstChars(final String str, final int n) {
N.checkArgNotNegative(n, "n");
if (str == null || str.length() == 0 || n == 0) {
return N.EMPTY_STRING;
} else if (str.length() <= n) {
return str;
} else {
return str.substring(0, n);
}
}
/**
* Returns the last {@code n} chars of the specified {@code String} if its length is bigger than {@code n},
* or an empty String {@code ""} if {@code str} is empty or null, or itself it's length equal to or less than {@code n}.
*
* @param str
* @param n
* @return
*/
public static String lastChars(final String str, final int n) {
N.checkArgNotNegative(n, "n");
if (str == null || str.length() == 0 || n == 0) {
return N.EMPTY_STRING;
} else if (str.length() <= n) {
return str;
} else {
return str.substring(str.length() - n);
}
}
/**
*
* @param a
* @return
*/
public static String join(final boolean[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final boolean[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final boolean[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final boolean[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final boolean[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final char[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final char[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final char[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final char[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final char[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final byte[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final byte[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final byte[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final byte[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final byte[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final short[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final short[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final short[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final short[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final short[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final int[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final int[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final int[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final int[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final int[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final long[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final long[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final long[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final long[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final long[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final float[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final float[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final float[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final float[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final float[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final double[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final double[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final double[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final double[] a, final int fromIndex, final int toIndex, final char delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final double[] a, final int fromIndex, final int toIndex, final String delimiter) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(a[i]);
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(a[i]);
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
public static String join(final Object[] a) {
return join(a, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final Object[] a, final char delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
/**
*
* @param a
* @param delimiter
* @return
*/
public static String join(final Object[] a, final String delimiter) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
}
return join(a, 0, a.length, delimiter);
}
public static String join(final Object[] a, final String delimiter, final String prefix, final String suffix) {
return join(a, 0, N.len(a), delimiter, prefix, suffix, false);
}
public static String join(final Object[] a, final String delimiter, final String prefix, final String suffix, final boolean trim) {
return join(a, 0, N.len(a), delimiter, prefix, suffix, trim);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final Object[] a, final int fromIndex, final int toIndex, final char delimiter) {
return join(a, fromIndex, toIndex, delimiter, false);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @param trim
* @return
*/
public static String join(final Object[] a, final int fromIndex, final int toIndex, final char delimiter, final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
return N.EMPTY_STRING;
} else if (toIndex - fromIndex == 1) {
return trim ? N.toString(a[fromIndex]).trim() : N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(trim ? N.toString(a[i]).trim() : N.toString(a[i]));
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter) {
return join(a, fromIndex, toIndex, delimiter, false);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @param trim
* @return
*/
public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter, final boolean trim) {
return join(a, fromIndex, toIndex, delimiter, null, null, trim);
}
/**
*
* @param a
* @param fromIndex
* @param toIndex
* @param delimiter
* @param prefix
* @param suffix
* @param trim
* @return
*/
public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix,
final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.len(a));
if (N.isNullOrEmpty(a) || fromIndex == toIndex) {
if (N.isNullOrEmpty(prefix) && N.isNullOrEmpty(suffix)) {
return N.EMPTY_STRING;
} else if (N.isNullOrEmpty(prefix)) {
return suffix;
} else if (N.isNullOrEmpty(suffix)) {
return prefix;
} else {
return prefix + suffix;
}
} else if (toIndex - fromIndex == 1 && N.isNullOrEmpty(prefix) && N.isNullOrEmpty(suffix)) {
return trim ? N.toString(a[fromIndex]).trim() : N.toString(a[fromIndex]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.notNullOrEmpty(prefix)) {
sb.append(prefix);
}
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(trim ? N.toString(a[i]).trim() : N.toString(a[i]));
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(trim ? N.toString(a[i]).trim() : N.toString(a[i]));
}
}
if (N.notNullOrEmpty(suffix)) {
sb.append(suffix);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param c
* @return
*/
public static String join(final Iterable> c) {
return join(c, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param c
* @param delimiter
* @return
*/
public static String join(final Iterable> c, final char delimiter) {
return join(c == null ? null : c.iterator(), delimiter);
}
/**
*
* @param c
* @param delimiter
* @return
*/
public static String join(final Iterable> c, final String delimiter) {
return join(c == null ? null : c.iterator(), delimiter);
}
public static String join(final Iterable> c, final String delimiter, final String prefix, final String suffix) {
return join(c == null ? null : c.iterator(), delimiter, prefix, suffix);
}
public static String join(final Iterable> c, final String delimiter, final String prefix, final String suffix, final boolean trim) {
return join(c == null ? null : c.iterator(), delimiter, prefix, suffix, trim);
}
/**
*
* @param c
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final Collection> c, final int fromIndex, final int toIndex, final char delimiter) {
return join(c, fromIndex, toIndex, delimiter, false);
}
/**
*
* @param c
* @param fromIndex
* @param toIndex
* @param delimiter
* @param trim
* @return
*/
public static String join(final Collection> c, final int fromIndex, final int toIndex, final char delimiter, final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.size(c));
if (N.isNullOrEmpty(c) || fromIndex == toIndex) {
return N.EMPTY_STRING;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
int i = 0;
for (Object e : c) {
if (i++ > fromIndex) {
sb.append(delimiter);
}
if (i > fromIndex) {
sb.append(trim ? N.toString(e).trim() : N.toString(e));
}
if (i >= toIndex) {
break;
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param c
* @param fromIndex
* @param toIndex
* @param delimiter
* @return
*/
public static String join(final Collection> c, final int fromIndex, final int toIndex, final String delimiter) {
return join(c, fromIndex, toIndex, delimiter, false);
}
/**
*
* @param c
* @param fromIndex
* @param toIndex
* @param delimiter
* @param trim
* @return
*/
public static String join(final Collection> c, final int fromIndex, final int toIndex, final String delimiter, final boolean trim) {
return join(c, fromIndex, toIndex, delimiter, null, null, trim);
}
/**
*
* @param c
* @param fromIndex
* @param toIndex
* @param delimiter
* @param prefix
* @param suffix
* @param trim
* @return
*/
public static String join(final Collection> c, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix,
final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.size(c));
if (N.isNullOrEmpty(c) || fromIndex == toIndex) {
if (N.isNullOrEmpty(prefix) && N.isNullOrEmpty(suffix)) {
return N.EMPTY_STRING;
} else if (N.isNullOrEmpty(prefix)) {
return suffix;
} else if (N.isNullOrEmpty(suffix)) {
return prefix;
} else {
return prefix + suffix;
}
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.notNullOrEmpty(prefix)) {
sb.append(prefix);
}
if (c instanceof List && c instanceof RandomAccess) {
final List> list = (List>) c;
if (N.isNullOrEmpty(delimiter)) {
for (int i = fromIndex; i < toIndex; i++) {
sb.append(trim ? N.toString(list.get(i)).trim() : N.toString(list.get(i)));
}
} else {
for (int i = fromIndex; i < toIndex; i++) {
if (i > fromIndex) {
sb.append(delimiter);
}
sb.append(trim ? N.toString(list.get(i)).trim() : N.toString(list.get(i)));
}
}
} else {
int i = 0;
if (N.isNullOrEmpty(delimiter)) {
for (Object e : c) {
if (i++ >= fromIndex) {
sb.append(trim ? N.toString(e).trim() : N.toString(e));
}
if (i >= toIndex) {
break;
}
}
} else {
for (Object e : c) {
if (i++ > fromIndex) {
sb.append(delimiter);
}
if (i > fromIndex) {
sb.append(trim ? N.toString(e).trim() : N.toString(e));
}
if (i >= toIndex) {
break;
}
}
}
}
if (N.notNullOrEmpty(suffix)) {
sb.append(suffix);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
public static String join(final Iterator> iter) {
return join(iter, Strings.ELEMENT_SEPARATOR);
}
public static String join(final Iterator> iter, final char delimiter) {
if (iter == null) {
return N.EMPTY_STRING;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (iter.hasNext()) {
sb.append(N.toString(iter.next()));
}
while (iter.hasNext()) {
sb.append(delimiter);
sb.append(N.toString(iter.next()));
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
public static String join(final Iterator> iter, final String delimiter) {
return join(iter, delimiter, EMPTY, EMPTY, false);
}
public static String join(final Iterator> iter, final String delimiter, final String prefix, final String suffix) {
return join(iter, delimiter, prefix, suffix, false);
}
public static String join(final Iterator> iter, final String delimiter, final String prefix, final String suffix, final boolean trim) {
if (iter == null) {
return N.EMPTY_STRING;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.notNullOrEmpty(prefix)) {
sb.append(prefix);
}
if (N.isNullOrEmpty(delimiter)) {
while (iter.hasNext()) {
if (trim) {
sb.append(N.toString(iter.next()).trim());
} else {
sb.append(N.toString(iter.next()));
}
}
} else {
if (iter.hasNext()) {
sb.append(N.toString(iter.next()));
}
while (iter.hasNext()) {
sb.append(delimiter);
if (trim) {
sb.append(N.toString(iter.next()).trim());
} else {
sb.append(N.toString(iter.next()));
}
}
}
if (N.notNullOrEmpty(suffix)) {
sb.append(suffix);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param m
* @return
*/
public static String joinEntries(final Map, ?> m) {
return joinEntries(m, Strings.ELEMENT_SEPARATOR);
}
/**
*
* @param m
* @param entryDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final char entryDelimiter) {
if (N.isNullOrEmpty(m)) {
return N.EMPTY_STRING;
}
return joinEntries(m, 0, m.size(), entryDelimiter);
}
/**
*
* @param m
* @param entryDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final String entryDelimiter) {
if (N.isNullOrEmpty(m)) {
return N.EMPTY_STRING;
}
return joinEntries(m, 0, m.size(), entryDelimiter);
}
/**
*
* @param m
* @param entryDelimiter
* @param keyValueDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final char entryDelimiter, final char keyValueDelimiter) {
if (N.isNullOrEmpty(m)) {
return N.EMPTY_STRING;
}
return joinEntries(m, 0, m.size(), entryDelimiter, keyValueDelimiter);
}
/**
*
* @param m
* @param entryDelimiter
* @param keyValueDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final String entryDelimiter, final String keyValueDelimiter) {
if (N.isNullOrEmpty(m)) {
return N.EMPTY_STRING;
}
return joinEntries(m, 0, m.size(), entryDelimiter, keyValueDelimiter);
}
public static String joinEntries(final Map, ?> m, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix) {
return joinEntries(m, 0, N.size(m), entryDelimiter, keyValueDelimiter, prefix, suffix, false);
}
public static String joinEntries(final Map, ?> m, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix,
final boolean trim) {
return joinEntries(m, 0, N.size(m), entryDelimiter, keyValueDelimiter, prefix, suffix, trim);
}
public static String joinEntries(final Map m, final String entryDelimiter,
final String keyValueDelimiter, final String prefix, final String suffix, final boolean trim, final Throwables.Function super K, ?, E> keyMapper,
final Throwables.Function super V, ?, E2> valueMapper) throws E, E2 {
N.checkArgNotNull(keyMapper, "keyMapper");
N.checkArgNotNull(valueMapper, "valueMapper");
if (N.isNullOrEmpty(m)) {
if (N.isNullOrEmpty(prefix) && N.isNullOrEmpty(suffix)) {
return N.EMPTY_STRING;
} else if (N.isNullOrEmpty(prefix)) {
return suffix;
} else if (N.isNullOrEmpty(suffix)) {
return prefix;
} else {
return prefix + suffix;
}
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.notNullOrEmpty(prefix)) {
sb.append(prefix);
}
int i = 0;
for (Map.Entry entry : m.entrySet()) {
if (i++ > 0) {
sb.append(entryDelimiter);
}
if (trim) {
sb.append(N.toString(keyMapper.apply(entry.getKey())).trim());
sb.append(keyValueDelimiter);
sb.append(N.toString(valueMapper.apply(entry.getValue())).trim());
} else {
sb.append(N.toString(keyMapper.apply(entry.getKey())));
sb.append(keyValueDelimiter);
sb.append(N.toString(valueMapper.apply(entry.getValue())));
}
}
if (N.notNullOrEmpty(suffix)) {
sb.append(suffix);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final char entryDelimiter) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, false);
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @param trim
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final char entryDelimiter, final boolean trim) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, WD._EQUAL, trim);
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final String entryDelimiter) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, false);
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @param trim
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final String entryDelimiter, final boolean trim) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, WD.EQUAL, null, null, trim);
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @param keyValueDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final char entryDelimiter, final char keyValueDelimiter) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, keyValueDelimiter, false);
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @param keyValueDelimiter
* @param trim
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final char entryDelimiter, final char keyValueDelimiter,
final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.size(m));
if (N.isNullOrEmpty(m) || fromIndex == toIndex) {
return N.EMPTY_STRING;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
int i = 0;
for (Map.Entry, ?> entry : m.entrySet()) {
if (i++ > fromIndex) {
sb.append(entryDelimiter);
}
if (i > fromIndex) {
sb.append(trim ? N.toString(entry.getKey()).trim() : N.toString(entry.getKey()));
sb.append(keyValueDelimiter);
sb.append(trim ? N.toString(entry.getValue()).trim() : N.toString(entry.getValue()));
}
if (i >= toIndex) {
break;
}
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param m
* @param fromIndex
* @param toIndex
* @param entryDelimiter
* @param keyValueDelimiter
* @return
*/
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final String entryDelimiter, final String keyValueDelimiter) {
return joinEntries(m, fromIndex, toIndex, entryDelimiter, keyValueDelimiter, null, null, false);
}
public static String joinEntries(final Map, ?> m, final int fromIndex, final int toIndex, final String entryDelimiter, final String keyValueDelimiter,
final String prefix, final String suffix, final boolean trim) {
N.checkFromToIndex(fromIndex, toIndex, N.size(m));
if (N.isNullOrEmpty(m) || fromIndex == toIndex) {
if (N.isNullOrEmpty(prefix) && N.isNullOrEmpty(suffix)) {
return N.EMPTY_STRING;
} else if (N.isNullOrEmpty(prefix)) {
return suffix;
} else if (N.isNullOrEmpty(suffix)) {
return prefix;
} else {
return prefix + suffix;
}
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
if (N.notNullOrEmpty(prefix)) {
sb.append(prefix);
}
int i = 0;
for (Map.Entry, ?> entry : m.entrySet()) {
if (i++ > fromIndex) {
sb.append(entryDelimiter);
}
if (i > fromIndex) {
if (trim) {
sb.append(N.toString(entry.getKey()).trim());
sb.append(keyValueDelimiter);
sb.append(N.toString(entry.getValue()).trim());
} else {
sb.append(N.toString(entry.getKey()));
sb.append(keyValueDelimiter);
sb.append(N.toString(entry.getValue()));
}
}
if (i >= toIndex) {
break;
}
}
if (N.notNullOrEmpty(suffix)) {
sb.append(suffix);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
* Returns a + b
.
*
* @param a
* @param b
* @return
*/
public static String concat(final String a, final String b) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @return
*/
public static String concat(final String a, final String b, final String c) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @return
*/
public static String concat(final String a, final String b, final String c, final String d) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @return
*/
public static String concat(final String a, final String b, final String c, final String d, final String e) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).append(e).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @return
*/
public static String concat(final String a, final String b, final String c, final String d, final String e, final String f) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).append(e).append(f).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @return
*/
public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).append(e).append(f).append(g).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @param h
* @return
*/
public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g,
final String h) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).append(e).append(f).append(g).append(h).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @param h
* @param i
* @return
*/
public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g, final String h,
final String i) {
final StringBuilder sb = Objectory.createStringBuilder();
try {
return sb.append(a).append(b).append(c).append(d).append(e).append(f).append(g).append(h).append(i).toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* @param a
* @return
*/
@SafeVarargs
public static String concat(final String... a) {
if (N.isNullOrEmpty(a)) {
return N.EMPTY_STRING;
} else if (a.length == 1) {
return N.toString(a[0]);
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
for (String e : a) {
sb.append(e);
}
return sb.toString();
} finally {
Objectory.recycle(sb);
}
}
/**
* Returns {@code N.toString(a) + N.toString(b)}.
*
* @param a
* @param b
* @return
*/
public static String concat(final Object a, final Object b) {
return Strings.concat(N.toString(a), N.toString(b));
}
/**
*
* @param a
* @param b
* @param c
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c));
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d));
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e));
}
/**
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f));
}
/**
* Returns {@code N.toString(a) + N.toString(b) + N.toString(c) + N.toString(d) + N.toString(e) + N.toString(f) + N.toString(g)}.
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g));
}
/**
* Returns {@code N.toString(a) + N.toString(b) + N.toString(c) + N.toString(d) + N.toString(e) + N.toString(f) + N.toString(g) + N.toString(h)}.
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @param h
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g,
final Object h) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g), N.toString(h));
}
/**
* Returns {@code N.toString(a) + N.toString(b) + N.toString(c) + N.toString(d) + N.toString(e) + N.toString(f) + N.toString(g) + N.toString(h) + N.toString(i)}.
*
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
* @param h
* @param i
* @return
* @see #concat(Object, Object)
*/
public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g, final Object h,
final Object i) {
return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g), N.toString(h),
N.toString(i));
}
// /**
// *
// * @param a
// * @return
// * @see #concat(Object, Object)
// * @deprecated
// */
// @Deprecated
// @SafeVarargs
// public static String concat(final Object... a) {
// if (N.isNullOrEmpty(a)) {
// return N.EMPTY_STRING;
// } else if (a.getClass().equals(String[].class)) {
// return StringUtil.concat((String[]) a);
// }
//
// final StringBuilder sb = ObjectFactory.createStringBuilder();
//
// try {
// for (Object e : a) {
// sb.append(N.toString(e));
// }
// return sb.toString();
// } finally {
// ObjectFactory.recycle(sb);
// }
// }
//
// /**
// *
// * @param c
// * @return
// * @deprecated
// */
// @Deprecated
// public static String concat(final Collection> c) {
// if (N.isNullOrEmpty(c)) {
// return N.EMPTY_STRING;
// }
//
// final StringBuilder sb = ObjectFactory.createStringBuilder();
//
// try {
// for (Object e : c) {
// sb.append(N.toString(e));
// }
// return sb.toString();
// } finally {
// ObjectFactory.recycle(sb);
// }
// }
/**
* Copied from Google Guava
*
*
*
* Returns the given {@code template} string with each occurrence of {@code "%s"} replaced by
* the corresponding argument value from {@code args}; or, if the placeholder and argument counts
* do not match, returns a best-effort form of that string. Will not throw an exception under
* normal conditions.
*
* Note: For most string-formatting needs, use {@link String#format String.format},
* {@link java.io.PrintWriter#format PrintWriter.format}, and related methods. These support the
* full range of format
* specifiers , and alert you to usage errors by throwing {@link
* java.util.IllegalFormatException}.
*
*
In certain cases, such as outputting debugging information or constructing a message to be
* used for another unchecked exception, an exception during string formatting would serve little
* purpose except to supplant the real information you were trying to provide. These are the cases
* this method is made for; it instead generates a best-effort string with all supplied argument
* values present. This method is also useful in environments such as GWT where {@code
* String.format} is not available. As an example, method implementations of the {@code Preconditions} class use this formatter, for both of the reasons just discussed.
*
*
Warning: Only the exact two-character placeholder sequence {@code "%s"} is
* recognized.
*
* @param template a string containing zero or more {@code "%s"} placeholder sequences. {@code
* null} is treated as the four-character string {@code "null"}.
* @param args the arguments to be substituted into the message template. The first argument
* specified is substituted for the first occurrence of {@code "%s"} in the template, and so
* forth. A {@code null} argument is converted to the four-character string {@code "null"};
* non-null values are converted to strings using {@link Object#toString()}.
* @return
* @since 25.1
*/
// TODO(diamondm) consider using Arrays.toString() for array parameters
public static String lenientFormat(String template, Object... args) {
template = String.valueOf(template); // null -> "null"
if (args == null) {
args = new Object[] { "(Object[])null" };
} else {
for (int i = 0; i < args.length; i++) {
args[i] = lenientToString(args[i]);
}
}
// start substituting the arguments into the '%s' placeholders
final StringBuilder sb = Objectory.createStringBuilder(template.length() + 16 * args.length);
int templateStart = 0;
int i = 0;
while (i < args.length) {
int placeholderStart = template.indexOf("%s", templateStart);
if (placeholderStart == -1) {
break;
}
sb.append(template, templateStart, placeholderStart);
sb.append(args[i++]);
templateStart = placeholderStart + 2;
}
sb.append(template, templateStart, template.length());
// if we run out of placeholders, append the extra args in square braces
if (i < args.length) {
sb.append(" [");
sb.append(args[i++]);
while (i < args.length) {
sb.append(", ");
sb.append(args[i++]);
}
sb.append(']');
}
final String result = sb.toString();
Objectory.recycle(sb);
return result;
}
/**
* Lenient to string.
*
* @param obj
* @return
*/
private static String lenientToString(Object obj) {
try {
return String.valueOf(obj);
} catch (Exception e) {
// Default toString() behavior - see Object.toString()
String objectToString = obj.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(obj));
// Logger is created inline with fixed name to avoid forcing Proguard to create another class.
Logger.getLogger("com.google.common.base.Strings").log(WARNING, "Exception during lenientFormat for " + objectToString, e);
return "<" + objectToString + " threw " + e.getClass().getName() + ">";
}
}
/**
*
* @param str
* @return
*/
public static String reverse(final String str) {
if (N.len(str) <= 1) {
return str;
}
final StringBuilder sb = Objectory.createStringBuilder();
try {
sb.append(str);
return sb.reverse().toString();
} finally {
Objectory.recycle(sb);
}
}
/**
*
* Reverses a String that is delimited by a specific character.
*
*
*
* The Strings between the delimiters are not reversed. Thus
* java.lang.String becomes String.lang.java (if the delimiter is
* {@code '.'}).
*
*
*
* N.reverseDelimited(null, *) = null
* N.reverseDelimited("", *) = ""
* N.reverseDelimited("a.b.c", 'x') = "a.b.c"
* N.reverseDelimited("a.b.c", ".") = "c.b.a"
*
*
* @param str
* the String to reverse, may be null
* @param delimiter
* the delimiter character to use
* @return
* @since 2.0
*/
public static String reverseDelimited(final String str, final char delimiter) {
if (N.len(str) <= 1) {
return str;
}
// could implement manually, but simple way is to reuse other,
// probably slower, methods.
final String[] strs = split(str, delimiter);
N.reverse(strs);
return join(strs, delimiter);
}
/**
*
* @param str
* @param delimiter
* @return
*/
public static String reverseDelimited(final String str, final String delimiter) {
if (N.len(str) <= 1) {
return str;
}
// could implement manually, but simple way is to reuse other,
// probably slower, methods.
final String[] strs = split(str, delimiter);
N.reverse(strs);
return Joiner.with(delimiter).reuseCachedBuffer().appendAll(strs).toString();
}
/**
* Returns a new sorted String if the specified {@code str} is not null or empty, otherwise the specified {@code str} is returned.
*
* @param str
* @return
*/
@SuppressWarnings("deprecation")
public static String sort(String str) {
if (N.len(str) <= 1) {
return str;
}
final char[] chs = str.toCharArray();
N.sort(chs);
return InternalUtil.newString(chs, true);
}
// Rotating (circular shift)
//-----------------------------------------------------------------------
/**
* Rotate (circular shift) a String of {@code shift} characters.
*
* If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)
* If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)
*
*
*
* StringUtil.rotate(null, *) = null
* StringUtil.rotate("", *) = ""
* StringUtil.rotate("abcdefg", 0) = "abcdefg"
* StringUtil.rotate("abcdefg", 2) = "fgabcde"
* StringUtil.rotate("abcdefg", -2) = "cdefgab"
* StringUtil.rotate("abcdefg", 7) = "abcdefg"
* StringUtil.rotate("abcdefg", -7) = "abcdefg"
* StringUtil.rotate("abcdefg", 9) = "fgabcde"
* StringUtil.rotate("abcdefg", -9) = "cdefgab"
*
*
* @param str the String to rotate, may be null
* @param shift number of time to shift (positive : right shift, negative : left shift)
* @return the rotated String,
* or the original String if {@code shift == 0},
* or {@code null} if null String input
* @since 3.5
*/
public static String rotate(final String str, final int shift) {
final int strLen = N.len(str);
if (strLen <= 1 || shift == 0 || shift % strLen == 0) {
return str;
}
int offset = -(shift % strLen);
if (offset < 0) {
offset = str.length() + offset;
}
if (offset < 0) {
offset = 0;
}
return Strings.substring(str, offset) + Strings.substring(str, 0, offset);
}
public static String shuffle(final String str) {
return shuffle(str, N.RAND);
}
public static String shuffle(final String str, final Random rnd) {
final int strLen = N.len(str);
if (strLen <= 1) {
return str;
}
final char[] chars = str.toCharArray();
N.shuffle(chars, rnd);
return String.valueOf(chars);
}
// Overlay
//-----------------------------------------------------------------------
/**
* Overlays part of a String with another String.
*
*
* StringUtil.overlay(null, "abc", 0, 0) = "abc"
* StringUtil.overlay("", "abc", 0, 0) = "abc"
* StringUtil.overlay("abcdef", null, 2, 4) = "abef"
* StringUtil.overlay("abcdef", "", 2, 4) = "abef"
* StringUtil.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
*
*
* @param str the String to do overlaying in, may be null
* @param overlay the String to overlay, may be null
* @param start the position to start overlaying at
* @param end the position to stop overlaying before
* @return overlayed String, {@code ""} if null String input
* @since 2.0
*/
public static String overlay(String str, String overlay, int start, int end) {
N.checkFromToIndex(start, end, N.len(str));
if (overlay == null) {
overlay = N.EMPTY_STRING;
}
if (N.isNullOrEmpty(str)) {
return overlay;
}
// final int len = str.length();
//
// if (start < 0) {
// start = 0;
// }
//
// if (start > len) {
// start = len;
// }
//
// if (end < 0) {
// end = 0;
// }
//
// if (end > len) {
// end = len;
// }
//
// if (start > end) {
// final int temp = start;
// start = end;
// end = temp;
// }
return str.substring(0, start) + overlay + str.substring(end);
}
public static final class StringUtil extends Strings {
private StringUtil() {
// Utility class.
}
}
public static final class MoreStringUtil {
private MoreStringUtil() {
// Utility class.
}
/**
* Returns an empty Optional
if {@code inclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || inclusiveBeginIndex > exclusiveEndIndex},
* otherwise an {@code Optional} with String value: {@code str.substring(exclusiveBeginIndex, exclusiveEndIndex)} is returned.
*
* @param str
* @param inclusiveBeginIndex
* @param exclusiveEndIndex
* @return
* @see Strings#substring(String, int, int)
*/
public static Optional substring(String str, int inclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, exclusiveEndIndex));
}
/**
* Returns an empty Optional
if {@code inclusiveBeginIndex < 0},
* otherwise an {@code Optional} with String value: {@code str.substring(inclusiveBeginIndex)} is returned.
*
* @param str
* @param inclusiveBeginIndex
* @return
* @see Strings#substring(String, int)
*/
public static Optional substring(String str, int inclusiveBeginIndex) {
return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex));
}
/**
* Returns an empty Optional
if {@code N.isNullOrEmpty(str) || str.indexOf(delimiterOfInclusiveBeginIndex) < 0},
* otherwise an {@code Optional} with String value: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))} is returned.
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)}
* @return
* @see Strings#substring(String, char)
*/
public static Optional substring(String str, char delimiterOfInclusiveBeginIndex) {
return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex));
}
/**
* Returns an empty Optional
if {@code N.isNullOrEmpty(str) || str.indexOf(delimiterOfInclusiveBeginIndex) < 0},
* otherwise an {@code Optional} with String value: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))} is returned.
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)}
* @return
* @see Strings#substring(String, String)
*/
public static Optional substring(String str, String delimiterOfInclusiveBeginIndex) {
return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex));
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) if inclusiveBeginIndex >= 0}
* @return
* @see Strings#substring(String, int, char)
*/
public static Optional substring(String str, int inclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) if inclusiveBeginIndex >= 0}
* @return
* @see Strings#substring(String, int, String)
*/
public static Optional substring(String str, int inclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param inclusiveBeginIndex
* @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0}
* @return
* @see Strings#substring(String, int, IntUnaryOperator)
*/
public static Optional substring(String str, int inclusiveBeginIndex, IntUnaryOperator funcOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex));
}
/**
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substring(String, char, int)
*/
public static Optional substring(String str, char delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substring(String, String, int)
*/
public static Optional substring(String str, String delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param funcOfInclusiveBeginIndex {@code inclusiveBeginIndex <- funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substring(String, IntUnaryOperator, int)
*/
public static Optional substring(String str, IntUnaryOperator funcOfInclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substring(str, funcOfInclusiveBeginIndex, exclusiveEndIndex));
}
/**
* Returns the substring after first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @return
* @see Strings#substringAfter(String, String)
*/
public static Optional substringAfter(String str, String delimiterOfExclusiveBeginIndex) {
return Optional.ofNullable(Strings.substringAfter(str, delimiterOfExclusiveBeginIndex));
}
/**
* Returns the substring after last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @return
* @see Strings#substringAfterLast(String, String)
*/
public static Optional substringAfterLast(String str, String delimiterOfExclusiveBeginIndex) {
return Optional.ofNullable(Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex));
}
/**
* Returns the substring before first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveEndIndex
* @return
* @see Strings#substringBefore(String, String)
*/
public static Optional substringBefore(String str, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBefore(str, delimiterOfExclusiveEndIndex));
}
/**
* Returns the substring last first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String.
*
* @param str
* @param delimiterOfExclusiveEndIndex
* @return
* @see Strings#substringBeforeLast(String, String)
*/
public static Optional substringBeforeLast(String str, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex));
}
/**
* Returns an empty Optional
if {@code exclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || exclusiveBeginIndex >= exclusiveEndIndex},
* otherwise an {@code Optional} with String value: {@code str.substring(exclusiveBeginIndex + 1, exclusiveEndIndex)} is returned.
*
* @param str
* @param exclusiveBeginIndex
* @param exclusiveEndIndex
* @return
* @see Strings#substringBetween(String, int, int)
*/
public static Optional substringBetween(String str, int exclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, beginIndex + 1) if exclusiveBeginIndex >= 0}
* @return
* @see Strings#substringBetween(String, int, char)
*/
public static Optional substringBetween(String str, int exclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, beginIndex + 1) if exclusiveBeginIndex >= 0}
* @return
* @see Strings#substringBetween(String, int, String)
*/
public static Optional substringBetween(String str, int exclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param exclusiveBeginIndex
* @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0}
* @return
* @see Strings#substringBetween(String, int, IntUnaryOperator)
*/
public static Optional substringBetween(String str, int exclusiveBeginIndex, IntUnaryOperator funcOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex));
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex {@code exclusiveBeginIndex <- str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substringBetween(String, char, int)
*/
public static Optional substringBetween(String str, char delimiterOfExclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex {@code exclusiveBeginIndex <- str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - 1) + delimiterOfExclusiveBeginIndex.length() - 1 if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substringBetween(String, String, int)
*/
public static Optional substringBetween(String str, String delimiterOfExclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param funcOfExclusiveBeginIndex {@code exclusiveBeginIndex <- funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex > 0}
* @param exclusiveEndIndex
* @return
* @see Strings#substringBetween(String, IntUnaryOperator, int)
*/
public static Optional substringBetween(String str, IntUnaryOperator funcOfExclusiveBeginIndex, int exclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, funcOfExclusiveBeginIndex, exclusiveEndIndex));
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see Strings#substringBetween(String, char, char)
*/
public static Optional substringBetween(String str, char delimiterOfExclusiveBeginIndex, char delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param tag
* @return
* @see #substringBetween(String, String, String)
* @see #substringBetween(String, int, int)
*/
public static Optional substringBetween(String str, String tag) {
return substringBetween(str, tag, tag);
}
/**
*
* @param str
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see Strings#substringBetween(String, String, String)
*/
public static Optional substringBetween(String str, String delimiterOfExclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param str
* @param fromIndex start index for {@code delimiterOfExclusive}. {@code str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex)}
* @param delimiterOfExclusiveBeginIndex
* @param delimiterOfExclusiveBeginIndex
* @return
* @see #substringBetween(String, int, int)
*/
public static Optional substringBetween(String str, int fromIndex, String delimiterOfExclusiveBeginIndex, String delimiterOfExclusiveEndIndex) {
return Optional.ofNullable(Strings.substringBetween(str, fromIndex, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex));
}
/**
*
* @param strs
* @return
* @see N#copyThenApply(Object[], com.landawn.abacus.util.Throwables.Function)
* @see Fn#trim()
* @see Fn#trimToEmpty()
* @see Fn#trimToNull()
*/
@Beta
public static String[] copyThenTrim(final String[] strs) {
return N.copyThenApply(strs, Fn.trim());
}
/**
*
* @param strs
* @return
* @see N#copyThenApply(Object[], com.landawn.abacus.util.Throwables.Function)
* @see Fn#strip()
* @see Fn#stripToEmpty()
* @see Fn#stripToNull()
*/
@Beta
public static String[] copyThenStrip(final String[] strs) {
return N.copyThenApply(strs, Fn.strip());
}
}
}