All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jodd.util.StringUtil Maven / Gradle / Ivy

There is a newer version: 6.3.0
Show newest version
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.util;

import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Function;

import static jodd.util.StringPool.EMPTY;

/**
 * String utilities.
 */
public class StringUtil {

	// ---------------------------------------------------------------- replace

	/**
	 * Replaces all occurrences of a certain pattern in a string with a
	 * replacement string. This is the fastest replace function known to author.
	 *
	 * @param s      string to be inspected
	 * @param sub    string pattern to be replaced
	 * @param with   string that should go where the pattern was
	 */
	public static String replace(final String s, final String sub, final String with) {
		if (sub.isEmpty()) {
			return s;
		}
		int c = 0;
		int i = s.indexOf(sub, c);
		if (i == -1) {
			return s;
		}
		final int length = s.length();
		final StringBuilder sb = new StringBuilder(length + with.length());
		do {
			sb.append(s, c, i);
			sb.append(with);
			c = i + sub.length();
		} while ((i = s.indexOf(sub, c)) != -1);
		if (c < length) {
			sb.append(s, c, length);
		}
		return sb.toString();
	}

	/**
	 * Replaces all occurrences of a character in a string.
	 *
	 * @param s      input string
	 * @param sub    character to replace
	 * @param with   character to replace with
	 */
	public static String replaceChar(final String s, final char sub, final char with) {
		final int startIndex = s.indexOf(sub);
		if (startIndex == -1) {
			return s;
		}
		final char[] str = s.toCharArray();
		for (int i = startIndex; i < str.length; i++) {
			if (str[i] == sub) {
				str[i] = with;
			}
		}
		return new String(str);
	}

	/**
	 * Replaces all occurrences of a characters in a string.
	 *
	 * @param s      input string
	 * @param sub    characters to replace
	 * @param with   characters to replace with
	 */
	public static String replaceChars(final String s, final char[] sub, final char[] with) {
		final char[] str = s.toCharArray();
		for (int i = 0; i < str.length; i++) {
			final char c = str[i];
			for (int j = 0; j < sub.length; j++) {
			    if (c == sub[j]) {
					str[i] = with[j];
					break;
				}
			}
		}
		return new String(str);
	}

	/**
	 * Replaces the very first occurrence of a substring with supplied string.
	 *
	 * @param s      source string
	 * @param sub    substring to replace
	 * @param with   substring to replace with
	 */
	public static String replaceFirst(final String s, final String sub, final String with) {
		final int i = s.indexOf(sub);
		if (i == -1) {
			return s;
		}
		return s.substring(0, i) + with + s.substring(i + sub.length());
	}

	/**
	 * Replaces the very first occurrence of a character in a string.
	 *
	 * @param s      string
	 * @param sub    char to replace
	 * @param with   char to replace with
	 */
	public static String replaceFirst(final String s, final char sub, final char with) {
		final int index = s.indexOf(sub);
		if (index == -1) {
			return s;
		}
		final char[] str = s.toCharArray();
		str[index] = with;
		return new String(str);
	}

	/**
	 * Replaces the very last occurrence of a substring with supplied string.
	 *
	 * @param s      source string
	 * @param sub    substring to replace
	 * @param with   substring to replace with
	 */
	public static String replaceLast(final String s, final String sub, final String with) {
		final int i = s.lastIndexOf(sub);
		if (i == -1) {
			return s;
		}
		return s.substring(0, i) + with + s.substring(i + sub.length());
	}

	/**
	 * Replaces the very last occurrence of a character in a string.
	 *
	 * @param s      string
	 * @param sub    char to replace
	 * @param with   char to replace with
	 */
	public static String replaceLast(final String s, final char sub, final char with) {
		final int index = s.lastIndexOf(sub);
		if (index == -1) {
			return s;
		}
		final char[] str = s.toCharArray();
		str[index] = with;
		return new String(str);
	}

	// ---------------------------------------------------------------- remove

	/**
	 * Removes all substring occurrences from the string.
	 *
	 * @param s      source string
	 * @param sub    substring to remove
	 */
	public static String remove(final String s, final String sub) {
		int c = 0;
		final int sublen = sub.length();
		if (sublen == 0) {
			return s;
		}
		int i = s.indexOf(sub, c);
		if (i == -1) {
			return s;
		}
		final StringBuilder sb = new StringBuilder(s.length());
		do {
			 sb.append(s, c, i);
			 c = i + sublen;
		 } while ((i = s.indexOf(sub, c)) != -1);
		 if (c < s.length()) {
			 sb.append(s, c, s.length());
		 }
		 return sb.toString();
	}

	/**
	 * Removes all characters contained in provided string.
	 *
	 * @param src    source string
	 * @param chars  string containing characters to remove
	 */
	public static String removeChars(final String src, final String chars) {
		final int i = src.length();
		final StringBuilder sb = new StringBuilder(i);
		for (int j = 0; j < i; j++) {
			final char c = src.charAt(j);
			if (chars.indexOf(c) == -1) {
				sb.append(c);
			}
		}
		return sb.toString();
	}


	/**
	 * Removes set of characters from string.
	 *
	 * @param src    string
	 * @param chars  characters to remove
	 */
	public static String removeChars(final String src, final char... chars) {
		final int i = src.length();
		final StringBuilder sb = new StringBuilder(i);
		mainloop:
		for (int j = 0; j < i; j++) {
			final char c = src.charAt(j);
			for (final char aChar : chars) {
				if (c == aChar) {
					continue mainloop;
				}
			}
			sb.append(c);
		}
		return sb.toString();
	}

	/**
	 * Removes a single character from string.
	 *
	 * @param string    source string
	 * @param ch  character to remove
	 */
	public static String remove(final String string, final char ch) {
		final int stringLen = string.length();
		final char[] result = new char[stringLen];
		int offset = 0;

		for (int i = 0; i < stringLen; i++) {
			final char c = string.charAt(i);

			if (c == ch) {
				continue;
			}

			result[offset] = c;
			offset++;
		}

		if (offset == stringLen) {
			return string;	// no changes
		}

		return new String(result, 0, offset);
	}

	// ---------------------------------------------------------------- miscellaneous

	/**
	 * Compares 2 strings. If one of the strings is null, false is returned. if
	 * both string are null, true is returned.
	 *
	 * @param s1     first string to compare
	 * @param s2     second string
	 *
	 * @return true if strings are equal, otherwise false
	 */
	public static boolean equals(final String s1, final String s2) {
		return Objects.equals(s1, s2);
	}

	/**
	 * Determines if a string is empty (null or zero-length).
	 */
	public static boolean isEmpty(final CharSequence string) {
		return ((string == null) || (string.length() == 0));
	}

	/**
	 * Determines if string array contains empty strings.
	 * @see #isEmpty(CharSequence)
	 */
	public static boolean isAllEmpty(final String... strings) {
		for (final String string : strings) {
			if (!isEmpty(string)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Determines if a string is blank (null or {@link #containsOnlyWhitespaces(CharSequence)}).
	 */
	public static boolean isBlank(final CharSequence string) {
		return ((string == null) || containsOnlyWhitespaces(string));
	}

	/**
	 * Determines if string is not blank.
	 */
	public static boolean isNotBlank(final CharSequence string) {
		return ((string != null) && !containsOnlyWhitespaces(string));
	}

	/**
	 * Determines if string array contains just blank strings.
	 */
	public static boolean isAllBlank(final String... strings) {
		for (final String string : strings) {
			if (!isBlank(string)) {
				return false;
			}
		}
		return true;
	}


	/**
	 * Returns true if string contains only white spaces.
	 */
	public static boolean containsOnlyWhitespaces(final CharSequence string) {
		final int size = string.length();
		for (int i = 0; i < size; i++) {
			final char c = string.charAt(i);
			if (!CharUtil.isWhitespace(c)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Returns true if string contains only digits.
	 */
	public static boolean containsOnlyDigits(final CharSequence string) {
		final int size = string.length();
		for (int i = 0; i < size; i++) {
			final char c = string.charAt(i);
			if (!CharUtil.isDigit(c)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Returns true if string {@link #containsOnlyDigits(CharSequence) contains only digits}
	 * or signs plus or minus.
	 */
	public static boolean containsOnlyDigitsAndSigns(final CharSequence string) {
		final int size = string.length();
		for (int i = 0; i < size; i++) {
			final char c = string.charAt(i);
			if ((!CharUtil.isDigit(c)) && (c != '-') && (c != '+')) {
				return false;
			}
		}
		return true;
	}


	/**
	 * Determines if a string is not empty.
	 */
	public static boolean isNotEmpty(final CharSequence string) {
		return string != null && string.length() > 0;
	}

	/**
	 * Converts safely an object to a string.
	 */
	public static String toString(final Object value) {
		if (value == null) {
			return null;
		}
		return value.toString();
	}

	/**
	 * Converts safely an object to a string. If object is null an empty
	 * string is returned.
	 */
	public static String toSafeString(final Object value) {
		if (value == null) {
			return EMPTY;
		}

		return value.toString();
	}

	/**
	 * Converts an array object to array of strings, where every element
	 * of input array is converted to a string. If input is not an array,
	 * the result will still be an array with one element.
	 */
	public static String[] toStringArray(final Object value) {
		if (value == null) {
			return new String[0];
		}
		final Class type = value.getClass();

		if (!type.isArray()) {
			return new String[] {value.toString()};
		}

		final Class componentType = type.getComponentType();

		if (componentType.isPrimitive()) {
			if (componentType == int.class) {
				return ArraysUtil.toStringArray((int[]) value);
			}
			else if (componentType == long.class) {
				return ArraysUtil.toStringArray((long[]) value);
			}
			else if (componentType == double.class) {
				return ArraysUtil.toStringArray((double[]) value);
			}
			else if (componentType == float.class) {
				return ArraysUtil.toStringArray((float[]) value);
			}
			else if (componentType == boolean.class) {
				return ArraysUtil.toStringArray((boolean[]) value);
			}
			else if (componentType == short.class) {
				return ArraysUtil.toStringArray((short[]) value);
			}
			else if (componentType == byte.class) {
				return ArraysUtil.toStringArray((byte[]) value);
			}
			else {
				throw new IllegalArgumentException();
			}
		}
		else {
			return ArraysUtil.toStringArray((Object[]) value);
		}
	}

	// ---------------------------------------------------------------- capitalize

	/**
	 * Capitalizes a string, changing the first letter to
	 * upper case. No other letters are changed.
	 *
	 * @param str   string to capitalize, may be null
	 * @see #uncapitalize(String)
	 */
	public static String capitalize(final String str) {
		return changeFirstCharacterCase(true, str);
	}

	/**
	 * Uncapitalizes a String, changing the first letter to
	 * lower case. No other letters are changed.
	 *
	 * @param str the String to uncapitalize, may be null
	 * @return the uncapitalized String, null if null
	 * @see #capitalize(String) 
	 */
	public static String uncapitalize(final String str) {
		return changeFirstCharacterCase(false, str);
	}

	/**
	 * Internal method for changing the first character case.
	 */
	private static String changeFirstCharacterCase(final boolean capitalize, final String string) {
		final int strLen = string.length();
		if (strLen == 0) {
			return string;
		}

		final char ch = string.charAt(0);
		final char modifiedCh;
		if (capitalize) {
			modifiedCh = Character.toUpperCase(ch);
		} else {
			modifiedCh = Character.toLowerCase(ch);
		}

		if (modifiedCh == ch) {
			// no change, return unchanged string
			return string;

		}

		final char[] chars = string.toCharArray();
		chars[0] = modifiedCh;
		return new String(chars);
	}


	/**
	 * Utility method to take a string and convert it to normal Java variable
	 * name capitalization.  This normally means converting the first
	 * character from upper case to lower case, but in the (unusual) special
	 * case when there is more than one character and both the first and
	 * second characters are upper case, we leave it alone.
	 * 

* Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays * as "URL". * * @param name The string to be decapitalized. * @return The decapitalized version of the string. */ public static String decapitalize(final String name) { if (name.isEmpty()) { return name; } if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) { return name; } final char[] chars = name.toCharArray(); final char c = chars[0]; final char modifiedChar = Character.toLowerCase(c); if (modifiedChar == c) { return name; } chars[0] = modifiedChar; return new String(chars); } /** * Makes a title-cased string from given input. */ public static String title(final String string) { final char[] chars = string.toCharArray(); boolean wasWhitespace = true; for (int i = 0; i < chars.length; i++) { final char c = chars[i]; if (CharUtil.isWhitespace(c)) { wasWhitespace = true; } else { if (wasWhitespace) { chars[i] = Character.toUpperCase(c); } else { chars[i] = Character.toLowerCase(c); } wasWhitespace = false; } } return new String(chars); } // ---------------------------------------------------------------- truncate /** * Sets the maximum length of the string. Longer strings will be simply truncated. */ public static String truncate(String string, final int length) { if (string.length() > length) { string = string.substring(0, length); } return string; } // ---------------------------------------------------------------- substring /** * Returns a new string that is a substring of this string. The substring * begins at the specified fromIndex and extends to the character * at index toIndex - 1. However, index values can be negative, * and then the real index will be calculated from the strings end. This * allows to specify, e.g. substring(1,-1) to cut one character * from both ends of the string. If fromIndex is negative * and toIndex is 0, it will return last characters of the string. * Also, this method will never throw an exception if index is out of range. */ public static String substring(final String string, int fromIndex, int toIndex) { final int len = string.length(); if (fromIndex < 0) { fromIndex = len + fromIndex; if (toIndex == 0) { toIndex = len; } } if (toIndex < 0) { toIndex = len + toIndex; } // safe net if (fromIndex < 0) { fromIndex = 0; } if (toIndex > len) { toIndex = len; } if (fromIndex >= toIndex) { return StringPool.EMPTY; } return string.substring(fromIndex, toIndex); } /** * Returns true if substring exist at given offset in a string. */ public static boolean isSubstringAt(final String string, final String substring, final int offset) { final int len = substring.length(); final int max = offset + len; if (max > string.length()) { return false; } int ndx = 0; for (int i = offset; i < max; i++, ndx++) { if (string.charAt(i) != substring.charAt(ndx)) { return false; } } return true; } // ---------------------------------------------------------------- split /** * Splits a string in several parts (tokens) that are separated by delimiter. * Delimiter is always surrounded by two strings! If there is no * content between two delimiters, empty string will be returned for that * token. Therefore, the length of the returned array will always be: * #delimiters + 1. *

* Method is much, much faster then regexp String.split(), * and a bit faster then StringTokenizer. * * @param src string to split * @param delimiter split delimiter * * @return array of split strings */ public static String[] split(final String src, final String delimiter) { final int maxparts = (src.length() / delimiter.length()) + 2; // one more for the last final int[] positions = new int[maxparts]; final int dellen = delimiter.length(); int i, j = 0; int count = 0; positions[0] = - dellen; while ((i = src.indexOf(delimiter, j)) != -1) { count++; positions[count] = i; j = i + dellen; } count++; positions[count] = src.length(); final String[] result = new String[count]; for (i = 0; i < count; i++) { result[i] = src.substring(positions[i] + dellen, positions[i + 1]); } return result; } /** * Splits a string in several parts (tokens) that are separated by delimiter * characters. Delimiter may contains any number of character and it is * always surrounded by two strings. * * @param src source to examine * @param d string with delimiter characters * * @return array of tokens */ public static String[] splitc(final String src, final String d) { if ((d.isEmpty()) || (src.isEmpty())) { return new String[] {src}; } return splitc(src, d.toCharArray()); } /** * Splits a string in several parts (tokens) that are separated by delimiter * characters. Delimiter may contains any number of character and it is * always surrounded by two strings. * * @param src source to examine * @param delimiters char array with delimiter characters * * @return array of tokens */ public static String[] splitc(final String src, final char[] delimiters) { if ((delimiters.length == 0) || (src.isEmpty()) ) { return new String[] {src}; } final char[] srcc = src.toCharArray(); final int maxparts = srcc.length + 1; final int[] start = new int[maxparts]; final int[] end = new int[maxparts]; int count = 0; start[0] = 0; int s = 0, e; if (CharUtil.equalsOne(srcc[0], delimiters)) { // string starts with delimiter end[0] = 0; count++; s = CharUtil.findFirstDiff(srcc, 1, delimiters); if (s == -1) { // nothing after delimiters return new String[] {EMPTY, EMPTY}; } start[1] = s; // new start } while (true) { // find new end e = CharUtil.findFirstEqual(srcc, s, delimiters); if (e == -1) { end[count] = srcc.length; break; } end[count] = e; // find new start count++; s = CharUtil.findFirstDiff(srcc, e, delimiters); if (s == -1) { start[count] = end[count] = srcc.length; break; } start[count] = s; } count++; final String[] result = new String[count]; for (int i = 0; i < count; i++) { result[i] = src.substring(start[i], end[i]); } return result; } /** * Splits a string in several parts (tokens) that are separated by single delimiter * characters. Delimiter is always surrounded by two strings. * * @param src source to examine * @param delimiter delimiter character * * @return array of tokens */ public static String[] splitc(final String src, final char delimiter) { if (src.isEmpty()) { return new String[] {EMPTY}; } final char[] srcc = src.toCharArray(); final int maxparts = srcc.length + 1; final int[] start = new int[maxparts]; final int[] end = new int[maxparts]; int count = 0; start[0] = 0; int s = 0, e; if (srcc[0] == delimiter) { // string starts with delimiter end[0] = 0; count++; s = CharUtil.findFirstDiff(srcc, 1, delimiter); if (s == -1) { // nothing after delimiters return new String[] {EMPTY, EMPTY}; } start[1] = s; // new start } while (true) { // find new end e = CharUtil.findFirstEqual(srcc, s, delimiter); if (e == -1) { end[count] = srcc.length; break; } end[count] = e; // find new start count++; s = CharUtil.findFirstDiff(srcc, e, delimiter); if (s == -1) { start[count] = end[count] = srcc.length; break; } start[count] = s; } count++; final String[] result = new String[count]; for (int i = 0; i < count; i++) { result[i] = src.substring(start[i], end[i]); } return result; } /** * Compress multiple occurrences of given char into one appearance. */ public static String compressChars(final String s, final char c) { final int len = s.length(); final StringBuilder sb = new StringBuilder(len); boolean wasChar = false; for (int i = 0; i < len; i++) { final char c1 = s.charAt(i); if (c1 == c) { if (wasChar) { continue; } wasChar = true; } else { wasChar = false; } sb.append(c1); } if (sb.length() == len) { return s; } return sb.toString(); } // ---------------------------------------------------------------- indexof and ignore cases /** * Finds first occurrence of a substring in the given source but within limited range [start, end). * It is fastest possible code, but still original String.indexOf(String, int) * is much faster (since it uses char[] value directly) and should be used when no range is needed. * * @param src source string for examination * @param sub substring to find * @param startIndex starting index * @param endIndex ending index * @return index of founded substring or -1 if substring not found */ public static int indexOf(final String src, final String sub, int startIndex, int endIndex) { if (startIndex < 0) { startIndex = 0; } final int srclen = src.length(); if (endIndex > srclen) { endIndex = srclen; } final int sublen = sub.length(); if (sublen == 0) { return startIndex > srclen ? srclen : startIndex; } final int total = endIndex - sublen + 1; final char c = sub.charAt(0); mainloop: for (int i = startIndex; i < total; i++) { if (src.charAt(i) != c) { continue; } int j = 1; int k = i + 1; while (j < sublen) { if (sub.charAt(j) != src.charAt(k)) { continue mainloop; } j++; k++; } return i; } return -1; } /** * Finds the first occurrence of a character in the given source but within limited range (start, end]. */ public static int indexOf(final String src, final char c, int startIndex, int endIndex) { if (startIndex < 0) { startIndex = 0; } final int srclen = src.length(); if (endIndex > srclen) { endIndex = srclen; } for (int i = startIndex; i < endIndex; i++) { if (src.charAt(i) == c) { return i; } } return -1; } /** * Finds the first occurrence of a character in the given source but within limited range (start, end]. */ public static int indexOfIgnoreCase(final String src, char c, int startIndex, int endIndex) { if (startIndex < 0) { startIndex = 0; } final int srclen = src.length(); if (endIndex > srclen) { endIndex = srclen; } c = Character.toLowerCase(c); for (int i = startIndex; i < endIndex; i++) { if (Character.toLowerCase(src.charAt(i)) == c) { return i; } } return -1; } /** * Finds first index of a substring in the given source string with ignored case. * * @param src source string for examination * @param subS substring to find * * @return index of founded substring or -1 if substring is not found * @see #indexOfIgnoreCase(String, String, int) */ public static int indexOfIgnoreCase(final String src, final String subS) { return indexOfIgnoreCase(src, subS, 0, src.length()); } /** * Finds first index of a substring in the given source string with ignored * case. This seems to be the fastest way doing this, with common string * length and content (of course, with no use of Boyer-Mayer type of * algorithms). Other implementations are slower: getting char array first, * lower casing the source string, using String.regionMatch etc. * * @param src source string for examination * @param subS substring to find * @param startIndex starting index from where search begins * * @return index of founded substring or -1 if substring is not found */ public static int indexOfIgnoreCase(final String src, final String subS, final int startIndex) { return indexOfIgnoreCase(src, subS, startIndex, src.length()); } /** * Finds first index of a substring in the given source string and range with * ignored case. * * @param src source string for examination * @param sub substring to find * @param startIndex starting index from where search begins * @param endIndex endint index * @return index of founded substring or -1 if substring is not found * @see #indexOfIgnoreCase(String, String, int) */ public static int indexOfIgnoreCase(final String src, String sub, int startIndex, int endIndex) { if (startIndex < 0) { startIndex = 0; } final int srclen = src.length(); if (endIndex > srclen) { endIndex = srclen; } final int sublen = sub.length(); if (sublen == 0) { return startIndex > srclen ? srclen : startIndex; } sub = sub.toLowerCase(); final int total = endIndex - sublen + 1; final char c = sub.charAt(0); mainloop: for (int i = startIndex; i < total; i++) { if (Character.toLowerCase(src.charAt(i)) != c) { continue; } int j = 1; int k = i + 1; while (j < sublen) { final char source = Character.toLowerCase(src.charAt(k)); if (sub.charAt(j) != source) { continue mainloop; } j++; k++; } return i; } return -1; } /** * Finds last index of a substring in the given source string with ignored * case. * * @param s source string * @param subS substring to find * * @return last index of founded substring or -1 if substring is not found * @see #indexOfIgnoreCase(String, String, int) * @see #lastIndexOfIgnoreCase(String, String, int) */ public static int lastIndexOfIgnoreCase(final String s, final String subS) { return lastIndexOfIgnoreCase(s, subS, s.length(), 0); } /** * Finds last index of a substring in the given source string with ignored * case. * * @param src source string for examination * @param subS substring to find * @param startIndex starting index from where search begins * * @return last index of founded substring or -1 if substring is not found * @see #indexOfIgnoreCase(String, String, int) */ public static int lastIndexOfIgnoreCase(final String src, final String subS, final int startIndex) { return lastIndexOfIgnoreCase(src, subS, startIndex, 0); } /** * Finds last index of a substring in the given source string with ignored * case in specified range. * * @param src source to examine * @param sub substring to find * @param startIndex starting index * @param endIndex end index * @return last index of founded substring or -1 if substring is not found */ public static int lastIndexOfIgnoreCase(final String src, String sub, int startIndex, int endIndex) { final int sublen = sub.length(); final int srclen = src.length(); if (sublen == 0) { return startIndex > srclen ? srclen : (startIndex < -1 ? -1 : startIndex); } sub = sub.toLowerCase(); final int total = srclen - sublen; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } final char c = sub.charAt(0); mainloop: for (int i = startIndex; i >= endIndex; i--) { if (Character.toLowerCase(src.charAt(i)) != c) { continue; } int j = 1; int k = i + 1; while (j < sublen) { final char source = Character.toLowerCase(src.charAt(k)); if (sub.charAt(j) != source) { continue mainloop; } j++; k++; } return i; } return -1; } /** * Finds last index of a substring in the given source string in specified range [end, start] * See {@link #indexOf(String, String, int, int)} for details about the speed. * * @param src source to examine * @param sub substring to find * @param startIndex starting index * @param endIndex end index * @return last index of founded substring or -1 if substring is not found */ public static int lastIndexOf(final String src, final String sub, int startIndex, int endIndex) { final int sublen = sub.length(); final int srclen = src.length(); if (sublen == 0) { return startIndex > srclen ? srclen : (startIndex < -1 ? -1 : startIndex); } final int total = srclen - sublen; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } final char c = sub.charAt(0); mainloop: for (int i = startIndex; i >= endIndex; i--) { if (src.charAt(i) != c) { continue; } int j = 1; int k = i + 1; while (j < sublen) { if (sub.charAt(j) != src.charAt(k)) { continue mainloop; } j++; k++; } return i; } return -1; } /** * Finds last index of a character in the given source string in specified range [end, start] */ public static int lastIndexOf(final String src, final char c, int startIndex, int endIndex) { final int total = src.length() - 1; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } for (int i = startIndex; i >= endIndex; i--) { if (src.charAt(i) == c) { return i; } } return -1; } /** * Finds last index of a character in the given source string in specified range [end, start] */ public static int lastIndexOfIgnoreCase(final String src, char c, int startIndex, int endIndex) { final int total = src.length() - 1; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } c = Character.toLowerCase(c); for (int i = startIndex; i >= endIndex; i--) { if (Character.toLowerCase(src.charAt(i)) == c) { return i; } } return -1; } public static int lastIndexOfWhitespace(final String src) { return lastIndexOfWhitespace(src, src.length(), 0); } /** * Returns last index of a whitespace. */ public static int lastIndexOfWhitespace(final String src, final int startIndex) { return lastIndexOfWhitespace(src, startIndex, 0); } /** * Returns last index of a whitespace. */ public static int lastIndexOfWhitespace(final String src, int startIndex, int endIndex) { final int total = src.length() - 1; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } for (int i = startIndex; i >= endIndex; i--) { if (Character.isWhitespace(src.charAt(i))) { return i; } } return -1; } public static int lastIndexOfNonWhitespace(final String src) { return lastIndexOfNonWhitespace(src, src.length(), 0); } public static int lastIndexOfNonWhitespace(final String src, final int startIndex) { return lastIndexOfNonWhitespace(src, startIndex, 0); } public static int lastIndexOfNonWhitespace(final String src, int startIndex, int endIndex) { final int total = src.length() - 1; if (total < 0) { return -1; } if (startIndex >= total) { startIndex = total; } if (endIndex < 0) { endIndex = 0; } for (int i = startIndex; i >= endIndex; i--) { if (!Character.isWhitespace(src.charAt(i))) { return i; } } return -1; } // ---------------------------------------------------------------- starts and ends /** * Tests if this string starts with the specified prefix with ignored case. * * @param src source string to test * @param subS starting substring * * @return true if the character sequence represented by the argument is * a prefix of the character sequence represented by this string; * false otherwise. */ public static boolean startsWithIgnoreCase(final String src, final String subS) { return startsWithIgnoreCase(src, subS, 0); } /** * Tests if this string starts with the specified prefix with ignored case * and with the specified prefix beginning a specified index. * * @param src source string to test * @param subS starting substring * @param startIndex index from where to test * * @return true if the character sequence represented by the argument is * a prefix of the character sequence represented by this string; * false otherwise. */ public static boolean startsWithIgnoreCase(final String src, final String subS, final int startIndex) { final String sub = subS.toLowerCase(); final int sublen = sub.length(); if (startIndex + sublen > src.length()) { return false; } int j = 0; int i = startIndex; while (j < sublen) { final char source = Character.toLowerCase(src.charAt(i)); if (sub.charAt(j) != source) { return false; } j++; i++; } return true; } /** * Tests if this string ends with the specified suffix. * * @param src String to test * @param subS suffix * * @return true if the character sequence represented by the argument is * a suffix of the character sequence represented by this object; * false otherwise. */ public static boolean endsWithIgnoreCase(final String src, final String subS) { final String sub = subS.toLowerCase(); final int sublen = sub.length(); int j = 0; int i = src.length() - sublen; if (i < 0) { return false; } while (j < sublen) { final char source = Character.toLowerCase(src.charAt(i)); if (sub.charAt(j) != source) { return false; } j++; i++; } return true; } /** * Returns if string starts with given character. */ public static boolean startsWithChar(final String s, final char c) { if (s.isEmpty()) { return false; } return s.charAt(0) == c; } /** * Returns if string ends with provided character. */ public static boolean endsWithChar(final String s, final char c) { if (s.isEmpty()) { return false; } return s.charAt(s.length() - 1) == c; } // ---------------------------------------------------------------- count substrings /** * Counts substring occurrences in a source string. * * @param source source string * @param sub substring to count * @return number of substring occurrences */ public static int count(final String source, final String sub) { return count(source, sub, 0); } public static int count(final String source, final String sub, final int start) { int count = 0; int j = start; final int sublen = sub.length(); if (sublen == 0) { return 0; } while (true) { final int i = source.indexOf(sub, j); if (i == -1) { break; } count++; j = i + sublen; } return count; } public static int count(final String source, final char c) { return count(source, c, 0); } public static int count(final String source, final char c, final int start) { int count = 0; int j = start; while (true) { final int i = source.indexOf(c, j); if (i == -1) { break; } count++; j = i + 1; } return count; } /** * Count substring occurrences in a source string, ignoring case. * * @param source source string * @param sub substring to count * @return number of substring occurrences */ public static int countIgnoreCase(final String source, final String sub) { int count = 0; int j = 0; final int sublen = sub.length(); if (sublen == 0) { return 0; } while (true) { final int i = indexOfIgnoreCase(source, sub, j); if (i == -1) { break; } count++; j = i + sublen; } return count; } // ---------------------------------------------------------------- string arrays /** * Finds the very first index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null if * noting found. * * @param s source string * @param arr string array */ public static int[] indexOf(final String s, final String... arr) { return indexOf(s, arr, 0); } /** * Finds the very first index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array * @param offset starting position */ public static int[] indexOf(final String s, final String[] arr, final int offset) { final int arrLen = arr.length; int index = Integer.MAX_VALUE; int last = -1; for (int j = 0; j < arrLen; j++) { final int i = s.indexOf(arr[j], offset); if (i != -1) { if (i < index) { index = i; last = j; } } } return last == -1 ? null : new int[] {last, index}; } /** * Finds the very first index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array */ public static int[] indexOfIgnoreCase(final String s, final String... arr) { return indexOfIgnoreCase(s, arr, 0); } /** * Finds the very first index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array * @param start starting position */ public static int[] indexOfIgnoreCase(final String s, final String[] arr, final int start) { final int arrLen = arr.length; int index = Integer.MAX_VALUE; int last = -1; for (int j = 0; j < arrLen; j++) { final int i = indexOfIgnoreCase(s, arr[j], start); if (i != -1) { if (i < index) { index = i; last = j; } } } return last == -1 ? null : new int[] {last, index}; } /** * Finds the very last index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array */ public static int[] lastIndexOf(final String s, final String... arr) { return lastIndexOf(s, arr, s.length()); } /** * Finds the very last index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array * @param fromIndex starting position */ public static int[] lastIndexOf(final String s, final String[] arr, final int fromIndex) { final int arrLen = arr.length; int index = -1; int last = -1; for (int j = 0; j < arrLen; j++) { final int i = s.lastIndexOf(arr[j], fromIndex); if (i != -1) { if (i > index) { index = i; last = j; } } } return last == -1 ? null : new int[] {last, index}; } /** * Finds the very last index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array * * @return int[2] */ public static int[] lastIndexOfIgnoreCase(final String s, final String... arr) { return lastIndexOfIgnoreCase(s, arr, s.length()); } /** * Finds the very last index of a substring from the specified array. It * returns an int[2] where int[0] represents the substring index and int[1] * represents position where substring was found. Returns null * if noting found. * * @param s source string * @param arr string array * @param fromIndex starting position */ public static int[] lastIndexOfIgnoreCase(final String s, final String[] arr, final int fromIndex) { final int arrLen = arr.length; int index = -1; int last = -1; for (int j = 0; j < arrLen; j++) { final int i = lastIndexOfIgnoreCase(s, arr[j], fromIndex); if (i != -1) { if (i > index) { index = i; last = j; } } } return last == -1 ? null : new int[] {last, index}; } /** * Compares two string arrays. * * @param as first string array * @param as1 second string array * * @return true if all array elements matches */ public static boolean equals(final String[] as, final String[] as1) { if (as.length != as1.length) { return false; } for (int i = 0; i < as.length; i++) { if (!as[i].equals(as1[i])) { return false; } } return true; } /** * Compares two string arrays. * * @param as first string array * @param as1 second string array * * @return true if all array elements matches */ public static boolean equalsIgnoreCase(final String[] as, final String[] as1) { if (as.length != as1.length) { return false; } for (int i = 0; i < as.length; i++) { if (!as[i].equalsIgnoreCase(as1[i])) { return false; } } return true; } /** * Replaces many substring at once. Order of string array is important. * * @param s source string * @param sub substrings array * @param with replace with array * * @return string with all occurrences of substrings replaced */ public static String replace(final String s, final String[] sub, final String[] with) { if ((sub.length != with.length) || (sub.length == 0)) { return s; } int start = 0; final StringBuilder buf = new StringBuilder(s.length()); while (true) { final int[] res = indexOf(s, sub, start); if (res == null) { break; } final int end = res[1]; buf.append(s, start, end); buf.append(with[res[0]]); start = end + sub[res[0]].length(); } buf.append(s.substring(start)); return buf.toString(); } /** * Replaces many substring at once. Order of string array is important. * * @param s source string * @param sub substrings array * @param with replace with array * * @return string with all occurrences of substrings replaced */ public static String replaceIgnoreCase(final String s, final String[] sub, final String[] with) { if ((sub.length != with.length) || (sub.length == 0)) { return s; } int start = 0; final StringBuilder buf = new StringBuilder(s.length()); while (true) { final int[] res = indexOfIgnoreCase(s, sub, start); if (res == null) { break; } final int end = res[1]; buf.append(s, start, end); buf.append(with[res[0]]); start = end + sub[0].length(); } buf.append(s.substring(start)); return buf.toString(); } // ---------------------------------------------------------------- the one /** * Compares string with at least one from the provided array. * If at least one equal string is found, returns its index. * Otherwise, -1 is returned. */ public static int equalsOne(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { if (src.equals(dest[i])) { return i; } } return -1; } /** * Compares string with at least one from the provided array, ignoring case. * If at least one equal string is found, it returns its index. * Otherwise, -1 is returned. */ public static int equalsOneIgnoreCase(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { if (src.equalsIgnoreCase(dest[i])) { return i; } } return -1; } /** * Checks if string starts with at least one string from the provided array. * If at least one string is matched, it returns its index. * Otherwise, -1 is returned. */ public static int startsWithOne(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { final String m = dest[i]; if (m == null) { continue; } if (src.startsWith(m)) { return i; } } return -1; } /** * Checks if string starts with at least one string from the provided array. * If at least one string is matched, it returns its index. * Otherwise, -1 is returned. */ public static int startsWithOneIgnoreCase(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { final String m = dest[i]; if (m == null) { continue; } if (startsWithIgnoreCase(src, m)) { return i; } } return -1; } /** * Checks if string ends with at least one string from the provided array. * If at least one string is matched, it returns its index. * Otherwise, -1 is returned. */ public static int endsWithOne(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { final String m = dest[i]; if (m == null) { continue; } if (src.endsWith(m)) { return i; } } return -1; } /** * Checks if string ends with at least one string from the provided array. * If at least one string is matched, it returns its index. * Otherwise, -1 is returned. */ public static int endsWithOneIgnoreCase(final String src, final String... dest) { for (int i = 0; i < dest.length; i++) { final String m = dest[i]; if (m == null) { continue; } if (endsWithIgnoreCase(src, m)) { return i; } } return -1; } // ---------------------------------------------------------------- char based /** * @see #indexOfChars(String, String, int) */ public static int indexOfChars(final String string, final String chars) { return indexOfChars(string, chars, 0); } /** * Returns the very first index of any char from provided string, starting from specified index offset. * Returns index of founded char, or -1 if nothing found. */ public static int indexOfChars(final String string, final String chars, int startindex) { final int stringLen = string.length(); final int charsLen = chars.length(); if (startindex < 0) { startindex = 0; } for (int i = startindex; i < stringLen; i++) { final char c = string.charAt(i); for (int j = 0; j < charsLen; j++) { if (c == chars.charAt(j)) { return i; } } } return -1; } public static int indexOfChars(final String string, final char[] chars) { return indexOfChars(string, chars, 0); } /** * Returns the very first index of any char from provided string, starting from specified index offset. * Returns index of founded char, or -1 if nothing found. */ public static int indexOfChars(final String string, final char[] chars, final int startindex) { final int stringLen = string.length(); final int charsLen = chars.length; for (int i = startindex; i < stringLen; i++) { final char c = string.charAt(i); for (int j = 0; j < charsLen; j++) { if (c == chars[j]) { return i; } } } return -1; } /** * Returns first index of a whitespace character. */ public static int indexOfWhitespace(final String string) { return indexOfWhitespace(string, 0, string.length()); } public static int indexOfWhitespace(final String string, final int startindex) { return indexOfWhitespace(string, startindex, string.length()); } /** * Returns first index of a whitespace character, starting from specified index offset. */ public static int indexOfWhitespace(final String string, final int startindex, final int endindex) { for (int i = startindex; i < endindex; i++) { if (CharUtil.isWhitespace(string.charAt(i))) { return i; } } return -1; } public static int indexOfNonWhitespace(final String string) { return indexOfNonWhitespace(string, 0, string.length()); } public static int indexOfNonWhitespace(final String string, final int startindex) { return indexOfNonWhitespace(string, startindex, string.length()); } public static int indexOfNonWhitespace(final String string, final int startindex, final int endindex) { for (int i = startindex; i < endindex; i++) { if (!CharUtil.isWhitespace(string.charAt(i))) { return i; } } return -1; } // ---------------------------------------------------------------- strip, trim /** * Strips leading char if string starts with one. */ public static String stripLeadingChar(final String string, final char c) { if (string.length() > 0) { if (string.charAt(0) == c) { return string.substring(1); } } return string; } /** * Strips trailing char if string ends with one. */ public static String stripTrailingChar(final String string, final char c) { if (string.length() > 0) { if (string.charAt(string.length() - 1) == c) { return string.substring(0, string.length() - 1); } } return string; } /** * Strips leading and trailing char from given string. */ public static String stripChar(final String string, final char c) { if (string.isEmpty()) { return string; } if (string.length() == 1) { if (string.charAt(0) == c) { return StringPool.EMPTY; } return string; } int left = 0; int right = string.length(); if (string.charAt(left) == c) { left++; } if (string.charAt(right - 1) == c) { right--; } return string.substring(left, right); } /** * Strips everything up to the first appearance of given char. * Character IS included in the returned string. */ public static String stripToChar(final String string, final char c) { final int ndx = string.indexOf(c); if (ndx == -1) { return string; } return string.substring(ndx); } /** * Strips everything from the first appearance of given char. * Character IS NOT included in the returned string. */ public static String stripFromChar(final String string, final char c) { final int ndx = string.indexOf(c); if (ndx == -1) { return string; } return string.substring(0, ndx); } /** * Trims array of strings. null array elements are ignored. */ public static void trimAll(final String... strings) { for (int i = 0; i < strings.length; i++) { final String string = strings[i]; if (string != null) { strings[i] = string.trim(); } } } /** * Trims array of strings where empty strings are set to null. * null elements of the array are ignored. * @see #trimDown(String) */ public static void trimDownAll(final String... strings) { for (int i = 0; i < strings.length; i++) { final String string = strings[i]; if (string != null) { strings[i] = trimDown(string); } } } /** * Trims string and sets to null if trimmed string is empty. */ public static String trimDown(String string) { string = string.trim(); if (string.isEmpty()) { string = null; } return string; } /** * Crops string by setting empty strings to null. */ public static String crop(final String string) { if (string.isEmpty()) { return null; } return string; } /** * Crops all elements of string array. */ public static void cropAll(final String... strings) { for (int i = 0; i < strings.length; i++) { String string = strings[i]; if (string != null) { string = crop(strings[i]); } strings[i] = string; } } /** * Trim whitespaces from the left. */ public static String trimLeft(final String src) { final int len = src.length(); int st = 0; while ((st < len) && (CharUtil.isWhitespace(src.charAt(st)))) { st++; } return st > 0 ? src.substring(st) : src; } /** * Trim whitespaces from the right. */ public static String trimRight(final String src) { int len = src.length(); final int count = len; while ((len > 0) && (CharUtil.isWhitespace(src.charAt(len - 1)))) { len--; } return (len < count) ? src.substring(0, len) : src; } // ---------------------------------------------------------------- regions /** * @see #indexOfRegion(String, String, String, int) */ public static int[] indexOfRegion(final String string, final String leftBoundary, final String rightBoundary) { return indexOfRegion(string, leftBoundary, rightBoundary, 0); } /** * Returns indexes of the first region without escaping character. * @see #indexOfRegion(String, String, String, char, int) */ public static int[] indexOfRegion(final String string, final String leftBoundary, final String rightBoundary, final int offset) { int ndx = offset; final int[] res = new int[4]; ndx = string.indexOf(leftBoundary, ndx); if (ndx == -1) { return null; } res[0] = ndx; ndx += leftBoundary.length(); res[1] = ndx; ndx = string.indexOf(rightBoundary, ndx); if (ndx == -1) { return null; } res[2] = ndx; res[3] = ndx + rightBoundary.length(); return res; } /** * @see #indexOfRegion(String, String, String, char, int) */ public static int[] indexOfRegion(final String string, final String leftBoundary, final String rightBoundary, final char escape) { return indexOfRegion(string, leftBoundary, rightBoundary, escape, 0); } /** * Returns indexes of the first string region. Region is defined by its left and right boundary. * Return value is an array of the following indexes: *

    *
  • start of left boundary index
  • *
  • region start index, i.e. end of left boundary
  • *
  • region end index, i.e. start of right boundary
  • *
  • end of right boundary index
  • *
*

* Escape character may be used to prefix boundaries so they can be ignored. * Double escaped region will be found, and first index of the result will be * decreased to include one escape character. * If region is not founded, null is returned. */ public static int[] indexOfRegion(final String string, final String leftBoundary, final String rightBoundary, final char escape, final int offset) { int ndx = offset; final int[] res = new int[4]; while (true) { ndx = string.indexOf(leftBoundary, ndx); if (ndx == -1) { return null; } int leftBoundaryLen = leftBoundary.length(); if (ndx > 0) { if (string.charAt(ndx - 1) == escape) { // check previous char boolean cont = true; if (ndx > 1) { if (string.charAt(ndx - 2) == escape) { // check double escapes ndx--; leftBoundaryLen++; cont = false; } } if (cont) { ndx += leftBoundaryLen; continue; } } } res[0] = ndx; ndx += leftBoundaryLen; res[1] = ndx; while (true) { // find right boundary ndx = string.indexOf(rightBoundary, ndx); if (ndx == -1) { return null; } if (ndx > 0) { if (string.charAt(ndx - 1) == escape) { ndx += rightBoundary.length(); continue; } } res[2] = ndx; res[3] = ndx + rightBoundary.length(); return res; } } } // ---------------------------------------------------------------- join /** * Joins an array of objects into one string without separators. */ public static String join(final Object[] array) { if (array == null) { return null; } if (array.length == 0) { return StringPool.EMPTY; } if (array.length == 1) { return String.valueOf(array[0]); } final StringBuilder sb = new StringBuilder(array.length * 16); for (int i = 0; i < array.length; i++) { sb.append(array[i]); } return sb.toString(); } /** * Joins an array of objects into one string with separator. */ public static String join(final Object[] array, final char separator) { if (array == null) { return null; } if (array.length == 0) { return StringPool.EMPTY; } if (array.length == 1) { return String.valueOf(array[0]); } final StringBuilder sb = new StringBuilder(array.length * 16); for (int i = 0; i < array.length; i++) { if (i > 0) { sb.append(separator); } sb.append(array[i]); } return sb.toString(); } /** * Joins an collection of objects into one string with separator. */ public static String join(final Collection collection, final char separator) { if (collection == null) { return null; } if (collection.size() == 0) { return StringPool.EMPTY; } final StringBuilder sb = new StringBuilder(collection.size() * 16); final Iterator it = collection.iterator(); for (int i = 0; i < collection.size(); i++) { if (i > 0) { sb.append(separator); } sb.append(it.next()); } return sb.toString(); } public static String join(final Collection collection, final String separator) { if (collection == null) { return null; } if (collection.size() == 0) { return StringPool.EMPTY; } final StringBuilder sb = new StringBuilder(collection.size() * 16); final Iterator it = collection.iterator(); for (int i = 0; i < collection.size(); i++) { if (i > 0) { sb.append(separator); } sb.append(it.next()); } return sb.toString(); } /** * Joins an array of objects into one string with separator. */ public static String join(final Object[] array, final String separator) { if (array == null) { return null; } if (array.length == 0) { return StringPool.EMPTY; } if (array.length == 1) { return String.valueOf(array[0]); } final StringBuilder sb = new StringBuilder(array.length * 16); for (int i = 0; i < array.length; i++) { if (i > 0) { sb.append(separator); } sb.append(array[i]); } return sb.toString(); } // ---------------------------------------------------------------- charset /** * Converts string charset. If charsets are the same, the same string is returned. */ public static String convertCharset(final String source, final Charset sourceCharset, final Charset newCharset) { if (sourceCharset.equals(newCharset)) { return source; } return new String(source.getBytes(sourceCharset), newCharset); } // ---------------------------------------------------------------- chars /** * Safely compares provided char with char on given location. */ public static boolean isCharAtEqual(final String string, final int index, final char charToCompare) { if ((index < 0) || (index >= string.length())) { return false; } return string.charAt(index) == charToCompare; } // ---------------------------------------------------------------- surround /** * @see #surround(String, String, String) */ public static String surround(final String string, final String fix) { return surround(string, fix, fix); } /** * Surrounds the string with provided prefix and suffix if such missing from string. */ public static String surround(String string, final String prefix, final String suffix) { if (!string.startsWith(prefix)) { string = prefix + string; } if (!string.endsWith(suffix)) { string += suffix; } return string; } /** * Inserts prefix if doesn't exist. */ public static String prefix(String string, final String prefix) { if (!string.startsWith(prefix)) { string = prefix + string; } return string; } /** * Appends suffix if doesn't exist. */ public static String suffix(String string, final String suffix) { if (!string.endsWith(suffix)) { string += suffix; } return string; } // ---------------------------------------------------------------- cut /** * Cuts the string from beginning to the first index of provided substring. */ public static String cutToIndexOf(String string, final String substring) { final int i = string.indexOf(substring); if (i != -1) { string = string.substring(0, i); } return string; } /** * Cuts the string from beginning to the first index of provided char. */ public static String cutToIndexOf(String string, final char c) { final int i = string.indexOf(c); if (i != -1) { string = string.substring(0, i); } return string; } /** * Cuts the string from the first index of provided substring to the end. */ public static String cutFromIndexOf(String string, final String substring) { final int i = string.indexOf(substring); if (i != -1) { string = string.substring(i); } return string; } /** * Cuts the string from the first index of provided char to the end. */ public static String cutFromIndexOf(String string, final char c) { final int i = string.indexOf(c); if (i != -1) { string = string.substring(i); } return string; } /** * Cuts prefix if exists. */ public static String cutPrefix(String string, final String prefix) { if (string.startsWith(prefix)) { string = string.substring(prefix.length()); } return string; } /** * Cuts sufix if exists. */ public static String cutSuffix(String string, final String suffix) { if (string.endsWith(suffix)) { string = string.substring(0, string.length() - suffix.length()); } return string; } /** * @see #cutSurrounding(String, String, String) */ public static String cutSurrounding(final String string, final String fix) { return cutSurrounding(string, fix, fix); } /** * Removes surrounding prefix and suffixes. */ public static String cutSurrounding(final String string, final String prefix, final String suffix) { int start = 0; int end = string.length(); if (string.startsWith(prefix)) { start = prefix.length(); } if (string.endsWith(suffix)) { end -= suffix.length(); } if (end <= start) { return StringPool.EMPTY; } return string.substring(start, end); } /** * Cuts a string between two other strings. If either of left and right * is missing, nothing will be cut and null is returned. * If indexes of left or right strings are wrong, empty string is returned. */ public static String cutBetween(final String string, final String left, final String right) { int leftNdx = string.indexOf(left); if (leftNdx == -1) { return null; } final int rightNdx = string.indexOf(right); if (rightNdx == -1) { return null; } leftNdx += left.length(); if (leftNdx >= rightNdx) { return StringPool.EMPTY; } return string.substring(leftNdx, rightNdx); } // ---------------------------------------------------------------- escaped /** * Returns true if character at provided index position is escaped * by escape character. */ public static boolean isCharAtEscaped(final String src, int ndx, final char escapeChar) { if (ndx == 0) { return false; } ndx--; return src.charAt(ndx) == escapeChar; } public static int indexOfUnescapedChar(final String src, final char sub, final char escapeChar) { return indexOfUnescapedChar(src, sub, escapeChar, 0); } public static int indexOfUnescapedChar(final String src, final char sub, final char escapeChar, int startIndex) { if (startIndex < 0) { startIndex = 0; } final int srclen = src.length(); char previous; char c = 0; for (int i = startIndex; i < srclen; i++) { previous = c; c = src.charAt(i); if (c == sub) { if (i > startIndex) { if (previous == escapeChar) { continue; } } return i; } } return -1; } // ---------------------------------------------------------------- insert public static String insert(final String src, final String insert) { return insert(src, insert, 0); } /** * Inserts a string on provided offset. */ public static String insert(final String src, final String insert, int offset) { if (offset < 0) { offset = 0; } if (offset > src.length()) { offset = src.length(); } final StringBuilder sb = new StringBuilder(src); sb.insert(offset, insert); return sb.toString(); } // ---------------------------------------------------------------- misc /** * Creates a new string that contains the provided string a number of times. */ public static String repeat(final String source, int count) { final StringBuilder result = new StringBuilder(source.length() * count); while (count > 0) { result.append(source); count--; } return result.toString(); } public static String repeat(final char c, final int count) { final char[] result = new char[count]; for (int i = 0; i < count; i++) { result[i] = c; } return new String(result); } /** * Reverse a string. */ public static String reverse(final String s) { final StringBuilder result = new StringBuilder(s.length()); for (int i = s.length() -1; i >= 0; i--) { result.append(s.charAt(i)); } return result.toString(); } /** * Returns max common prefix of two strings. */ public static String maxCommonPrefix(final String one, final String two) { final int minLength = Math.min(one.length(), two.length()); final StringBuilder sb = new StringBuilder(minLength); for (int pos = 0; pos < minLength; pos++) { final char currentChar = one.charAt(pos); if (currentChar != two.charAt(pos)) { break; } sb.append(currentChar); } return sb.toString(); } // ---------------------------------------------------------------- prefixes /** * Finds common prefix for several strings. Returns an empty string if * arguments do not have a common prefix. */ public static String findCommonPrefix(final String... strings) { final StringBuilder prefix = new StringBuilder(); int index = 0; char c = 0; loop: while (true) { for (int i = 0; i < strings.length; i++) { final String s = strings[i]; if (index == s.length()) { break loop; } if (i == 0) { c = s.charAt(index); } else { if (s.charAt(index) != c) { break loop; } } } index++; prefix.append(c); } return prefix.length() == 0 ? StringPool.EMPTY : prefix.toString(); } // ---------------------------------------------------------------- shorten /** * Shorten string to given length. */ public static String shorten(String s, int length, final String suffix) { length -= suffix.length(); if (s.length() > length) { for (int j = length; j >= 0; j--) { if (CharUtil.isWhitespace(s.charAt(j))) { length = j; break; } } final String temp = s.substring(0, length); s = temp.concat(suffix); } return s; } // ---------------------------------------------------------------- case change /** * Converts all of the characters in the string to lower case, based on the * portal instance's default locale. * * @param s the string to convert * @return the string, converted to lower case, or null if the * string is null */ public static String toLowerCase(final String s) { return toLowerCase(s, null); } /** * Converts all of the characters in the string to lower case, based on the * locale. More efficient than String.toLowerCase. * * @param s the string to convert * @param locale apply this locale's rules, if null default locale is used * @return the string, converted to lower case, or null if the * string is null */ public static String toLowerCase(final String s, Locale locale) { if (s == null) { return null; } StringBuilder sb = null; for (int i = 0; i < s.length(); i++) { final char c = s.charAt(i); if (c > 127) { // found non-ascii char, fallback to the slow unicode detection if (locale == null) { locale = Locale.getDefault(); } return s.toLowerCase(locale); } if ((c >= 'A') && (c <= 'Z')) { if (sb == null) { sb = new StringBuilder(s); } sb.setCharAt(i, (char)(c + 32)); } } if (sb == null) { return s; } return sb.toString(); } /** * Converts all of the characters in the string to upper case, based on the * portal instance's default locale. * * @param s the string to convert * @return the string, converted to upper case, or null if the * string is null */ public static String toUpperCase(final String s) { return toUpperCase(s, null); } /** * Converts all of the characters in the string to upper case, based on the * locale. * * @param s the string to convert * @param locale apply this locale's rules * @return the string, converted to upper case, or null if the * string is null */ public static String toUpperCase(final String s, Locale locale) { if (s == null) { return null; } StringBuilder sb = null; for (int i = 0; i < s.length(); i++) { final char c = s.charAt(i); if (c > 127) { // found non-ascii char, fallback to the slow unicode detection if (locale == null) { locale = Locale.getDefault(); } return s.toUpperCase(locale); } if ((c >= 'a') && (c <= 'z')) { if (sb == null) { sb = new StringBuilder(s); } sb.setCharAt(i, (char)(c - 32)); } } if (sb == null) { return s; } return sb.toString(); } // ---------------------------------------------------------------- text /** * Removes starting and ending single or double quotes. */ public static String removeQuotes(final String string) { if ( (startsWithChar(string, '\'') && endsWithChar(string, '\'')) || (startsWithChar(string, '"') && endsWithChar(string, '"')) || (startsWithChar(string, '`') && endsWithChar(string, '`')) ) { return substring(string, 1, -1); } return string; } // ---------------------------------------------------------------- hex /** * Converts bytes to hex string. */ public static String toHexString(final byte[] bytes) { final char[] chars = new char[bytes.length * 2]; int i = 0; for (final byte b : bytes) { chars[i++] = CharUtil.int2hex((b & 0xF0) >> 4); chars[i++] = CharUtil.int2hex(b & 0x0F); } return new String(chars); } // ---------------------------------------------------------------- functional /** * Executes function on a string if not {@code null}. Otherwise returns an empty string. */ public static String ifNotNull(final String input, final Function stringFunction) { if (input == null) { return StringPool.EMPTY; } return stringFunction.apply(input); } // ---------------------------------------------------------------- detectors /** * Detects quote character or return 0. */ public static char detectQuoteChar(final String str) { if (str.length() < 2) { return 0; } final char c = str.charAt(0); if (c != str.charAt(str.length() - 1)) { return 0; } if (c == '\'' || c == '"' || c == '`') { return c; } return 0; } /** * Changes CamelCase string to lower case words separated by provided * separator character. The following translations are applied: *

    *
  • Every upper case letter in the CamelCase name is translated into * two characters, a separator and the lower case equivalent of the target character, * with three exceptions. *
    1. For contiguous sequences of upper case letters, characters after the first * character are replaced only by their lower case equivalent, and are not * preceded by a separator (theFOO to the_foo). *
    2. An upper case character in the first position of the CamelCase name * is not preceded by a separator character, and is translated only to its * lower case equivalent. (Foo to foo and not _foo) *
    3. An upper case character in the CamelCase name that is already preceded * by a separator character is translated only to its lower case equivalent, * and is not preceded by an additional separator. (user_Name * to user_name and not user__name. *
    *
  • If the CamelCase name starts with a separator, then that * separator is not included in the translated name, unless the CamelCase * name is just one character in length, i.e., it is the separator character. * This applies only to the first character of the CamelCase name. *
*/ public static String fromCamelCase(final String input, final char separator) { final int length = input.length(); final StringBuilder result = new StringBuilder(length * 2); int resultLength = 0; boolean prevTranslated = false; for (int i = 0; i < length; i++) { char c = input.charAt(i); if (i > 0 || c != separator) {// skip first starting separator if (Character.isUpperCase(c)) { if (!prevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != separator) { result.append(separator); resultLength++; } c = Character.toLowerCase(c); prevTranslated = true; } else { prevTranslated = false; } result.append(c); resultLength++; } } return resultLength > 0 ? result.toString() : input; } /** * Converts separated string value to CamelCase. */ public static String toCamelCase(final String input, final boolean firstCharUppercase, final char separator) { final int length = input.length(); final StringBuilder sb = new StringBuilder(length); boolean upperCase = firstCharUppercase; for (int i = 0; i < length; i++) { final char ch = input.charAt(i); if (ch == separator) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(ch)); upperCase = false; } else { sb.append(ch); } } return sb.toString(); } /** * Converts all tabs on a line to spaces according to the provided tab width. * This is not a simple tab to spaces replacement, since the resulting * indentation remains the same. */ public static String convertTabsToSpaces(final String line, final int tabWidth) { int tab_index, tab_size; int last_tab_index = 0; int added_chars = 0; if (tabWidth == 0) { return remove(line, '\t'); } final StringBuilder result = new StringBuilder(); while ((tab_index = line.indexOf('\t', last_tab_index)) != -1) { tab_size = tabWidth - ((tab_index + added_chars) % tabWidth); if (tab_size == 0) { tab_size = tabWidth; } added_chars += tab_size - 1; result.append(line, last_tab_index, tab_index); result.append(repeat(' ', tab_size)); last_tab_index = tab_index+1; } if (last_tab_index == 0) { return line; } result.append(line.substring(last_tab_index)); return result.toString(); } /** * Escapes a string using java rules. */ public static String escapeJava(final String string) { final int strLen = string.length(); final StringBuilder sb = new StringBuilder(strLen); for (int i = 0; i < strLen; i++) { final char c = string.charAt(i); switch (c) { case '\b' : sb.append("\\b"); break; case '\t' : sb.append("\\t"); break; case '\n' : sb.append("\\n"); break; case '\f' : sb.append("\\f"); break; case '\r' : sb.append("\\r"); break; case '\"' : sb.append("\\\""); break; case '\\' : sb.append("\\\\"); break; default: if ((c < 32) || (c > 127)) { final String hex = Integer.toHexString(c); sb.append("\\u"); for (int k = hex.length(); k < 4; k++) { sb.append('0'); } sb.append(hex); } else { sb.append(c); } } } return sb.toString(); } /** * Unescapes a string using java rules. */ public static String unescapeJava(final String str) { final char[] chars = str.toCharArray(); final StringBuilder sb = new StringBuilder(str.length()); for (int i = 0; i < chars.length; i++) { char c = chars[i]; if (c != '\\') { sb.append(c); continue; } i++; c = chars[i]; switch (c) { case 'b': sb.append('\b'); break; case 't': sb.append('\t'); break; case 'n': sb.append('\n'); break; case 'f': sb.append('\f'); break; case 'r': sb.append('\r'); break; case '"': sb.append('\"'); break; case '\\': sb.append('\\'); break; case 'u' : final char hex = (char) Integer.parseInt(new String(chars, i + 1, 4), 16); sb.append(hex); i += 4; break; default: throw new IllegalArgumentException("Invalid escaping character: " + c); } } return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy