/** * OpenAtlasForAndroid Project * The MIT License (MIT) Copyright (OpenAtlasForAndroid) 2015 Bunny Blue,achellies * <p> * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following conditions: * <p> * The above copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * <p> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * @author BunnyBlue **/ package com.openatlas.util; import java.util.ArrayList; import java.util.List; public class StringUtils { public static final String EMPTY = ""; public static String[] EMPTY_STRING_ARRAY = new String[0]; /** * Represents a failed index search. * @since 2.1 */ public static final int INDEX_NOT_FOUND = -1; public static boolean isEmpty(String str) { return str == null || str.length() == 0; } public static boolean isNotEmpty(String str) { return str != null && str.length() > 0; } /** <p>Checks if a CharSequence is whitespace, empty ("") or null.</p> * * <pre> * StringUtils.isBlank(null) = true * StringUtils.isBlank("") = true * StringUtils.isBlank(" ") = true * StringUtils.isBlank("bob") = false * StringUtils.isBlank(" bob ") = false * </pre> * * @param str the CharSequence to check, may be null * @return {@code true} if the CharSequence is null, empty or whitespace * @since 2.0 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) */ public static boolean isBlank(String str) { if (str != null) { int length = str.length(); if (length != 0) { for (int i = 0; i < length; i++) { if (!Character.isWhitespace(str.charAt(i))) { return false; } } return true; } } return true; } public static boolean startWith(final String str, final String prefix) { if (str == null || prefix == null) { return false; } return str.startsWith(prefix); } public static String trim(String str) { return str == null ? null : str.trim(); } public static boolean equals(String str, String str2) { if (str == null) { return false; } return str.equals(str2); } public static boolean contains(String[] strArr, String str) { if (strArr == null || str == null) { return false; } for (Object equals : strArr) { if (str.equals(equals)) { return true; } } return false; } /** * <p>Gets the substring before the last occurrence of a separator. * The separator is not returned.</p> * * <p>A {@code null} string input will return {@code null}. * An empty ("") string input will return the empty string. * An empty or {@code null} separator will return the input string.</p> * * <p>If nothing is found, the string input is returned.</p> * * <pre> * StringUtils.substringBeforeLast(null, *) = null * StringUtils.substringBeforeLast("", *) = "" * StringUtils.substringBeforeLast("abcba", "b") = "abc" * StringUtils.substringBeforeLast("abc", "c") = "ab" * StringUtils.substringBeforeLast("a", "a") = "" * StringUtils.substringBeforeLast("a", "z") = "a" * StringUtils.substringBeforeLast("a", null) = "a" * StringUtils.substringBeforeLast("a", "") = "a" * </pre> * * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring before the last occurrence of the separator, * {@code null} if null String input * @since 2.0 */ public static String substringBeforeLast(final String str, final String separator) { if (isEmpty(str) || isEmpty(separator)) { return str; } final int pos = str.lastIndexOf(separator); if (pos == INDEX_NOT_FOUND) { return str; } return str.substring(0, pos); } /** * <p>Gets the substring after the first occurrence of a separator. * The separator is not returned.</p> * * <p>A {@code null} string input will return {@code null}. * An empty ("") string input will return the empty string. * A {@code null} separator will return the empty string if the * input string is not {@code null}.</p> * * <p>If nothing is found, the empty string is returned.</p> * * <pre> * StringUtils.substringAfter(null, *) = null * StringUtils.substringAfter("", *) = "" * StringUtils.substringAfter(*, null) = "" * StringUtils.substringAfter("abc", "a") = "bc" * StringUtils.substringAfter("abcba", "b") = "cba" * StringUtils.substringAfter("abc", "c") = "" * StringUtils.substringAfter("abc", "d") = "" * StringUtils.substringAfter("abc", "") = "abc" * </pre> * * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring after the first occurrence of the separator, * {@code null} if null String input * @since 2.0 */ public static String substringAfter(final String str, final String separator) { if (isEmpty(str)) { return str; } if (separator == null) { return EMPTY; } final int pos = str.indexOf(separator); if (pos == INDEX_NOT_FOUND) { return EMPTY; } return str.substring(pos + separator.length()); } /** * <p>Gets the substring after the last occurrence of a separator. * The separator is not returned.</p> * * <p>A {@code null} string input will return {@code null}. * An empty ("") string input will return the empty string. * An empty or {@code null} separator will return the empty string if * the input string is not {@code null}.</p> * * <p>If nothing is found, the empty string is returned.</p> * * <pre> * StringUtils.substringAfterLast(null, *) = null * StringUtils.substringAfterLast("", *) = "" * StringUtils.substringAfterLast(*, "") = "" * StringUtils.substringAfterLast(*, null) = "" * StringUtils.substringAfterLast("abc", "a") = "bc" * StringUtils.substringAfterLast("abcba", "b") = "a" * StringUtils.substringAfterLast("abc", "c") = "" * StringUtils.substringAfterLast("a", "a") = "" * StringUtils.substringAfterLast("a", "z") = "" * </pre> * * @param str the String to get a substring from, may be null * @param separator the String to search for, may be null * @return the substring after the last occurrence of the separator, * {@code null} if null String input * @since 2.0 */ public static String substringAfterLast(final String str, final String separator) { if (isEmpty(str)) { return str; } if (isEmpty(separator)) { return EMPTY; } final int pos = str.lastIndexOf(separator); if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { return EMPTY; } return str.substring(pos + separator.length()); } /** * <p>Gets the String that is nested in between two Strings. * Only the first match is returned.</p> * * <p>A {@code null} input String returns {@code null}. * A {@code null} open/close returns {@code null} (no match). * An empty ("") open and close returns an empty string.</p> * * <pre> * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" * StringUtils.substringBetween(null, *, *) = null * StringUtils.substringBetween(*, null, *) = null * StringUtils.substringBetween(*, *, null) = null * StringUtils.substringBetween("", "", "") = "" * StringUtils.substringBetween("", "", "]") = null * StringUtils.substringBetween("", "[", "]") = null * StringUtils.substringBetween("yabcz", "", "") = "" * StringUtils.substringBetween("yabcz", "y", "z") = "abc" * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" * </pre> * * @param str the String containing the substring, may be null * @param open the String before the substring, may be null * @param close the String after the substring, may be null * @return the substring, {@code null} if no match * @since 2.0 */ public static String substringBetween(final String str, final String open, final String close) { if (str == null || open == null || close == null) { return null; } final int start = str.indexOf(open); if (start != INDEX_NOT_FOUND) { final int end = str.indexOf(close, start + open.length()); if (end != INDEX_NOT_FOUND) { return str.substring(start + open.length(), end); } } return null; } /** * <p>Replaces a String with another String inside a larger String, once.</p> * * <p>A {@code null} reference passed to this method is a no-op.</p> * * <pre> * StringUtils.replaceOnce(null, *, *) = null * StringUtils.replaceOnce("", *, *) = "" * StringUtils.replaceOnce("any", null, *) = "any" * StringUtils.replaceOnce("any", *, null) = "any" * StringUtils.replaceOnce("any", "", *) = "any" * StringUtils.replaceOnce("aba", "a", null) = "aba" * StringUtils.replaceOnce("aba", "a", "") = "ba" * StringUtils.replaceOnce("aba", "a", "z") = "zba" * </pre> * * @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 text, final String searchString, final String replacement) { return replace(text, searchString, replacement, -1); } /** * <p>Replaces a String with another String inside a larger String, * for the first {@code max} values of the search String.</p> * * <p>A {@code null} reference passed to this method is a no-op.</p> * * <pre> * StringUtils.replace(null, *, *, *) = null * StringUtils.replace("", *, *, *) = "" * StringUtils.replace("any", null, *, *) = "any" * StringUtils.replace("any", *, null, *) = "any" * StringUtils.replace("any", "", *, *) = "any" * StringUtils.replace("any", *, *, 0) = "any" * StringUtils.replace("abaa", "a", null, -1) = "abaa" * StringUtils.replace("abaa", "a", "", -1) = "b" * StringUtils.replace("abaa", "a", "z", 0) = "abaa" * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" * StringUtils.replace("abaa", "a", "z", 2) = "zbza" * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" * </pre> * * @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 it with, may be null * @param max maximum number of values to replace, or {@code -1} if no maximum * @return the text with any replacements processed, * {@code null} if null String input */ public static String replace(final String text, final String searchString, final String replacement, int max) { if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { return text; } int start = 0; int end = text.indexOf(searchString, start); if (end == INDEX_NOT_FOUND) { return text; } final int replLength = searchString.length(); int increase = replacement.length() - replLength; increase = increase < 0 ? 0 : increase; increase *= max < 0 ? 16 : max > 64 ? 64 : max; final StringBuilder buf = new StringBuilder(text.length() + increase); while (end != INDEX_NOT_FOUND) { buf.append(text.substring(start, end)).append(replacement); start = end + replLength; if (--max == 0) { break; } end = text.indexOf(searchString, start); } buf.append(text.substring(start)); return buf.toString(); } public static String getPackageNameFromEntryName(String str) { return str.substring(str.indexOf("libcom_") + "lib".length(), str.indexOf(".so")).replace("_", "."); } /** * <p>Check if a CharSequence ends with a specified suffix.</p> * * <p>{@code null}s are handled without exceptions. Two {@code null} * references are considered to be equal. The comparison is case sensitive.</p> * * <pre> * StringUtils.endsWith(null, null) = true * StringUtils.endsWith(null, "def") = false * StringUtils.endsWith("abcdef", null) = false * StringUtils.endsWith("abcdef", "def") = true * StringUtils.endsWith("ABCDEF", "def") = false * StringUtils.endsWith("ABCDEF", "cde") = false * </pre> * * @see String#endsWith(String) * @param str the CharSequence to check, may be null * @param suffix the suffix to find, may be null * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or * both {@code null} * @since 2.4 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) */ public static boolean endsWith(final String str, final String suffix) { return endsWith(str, suffix, false); } /** * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> * * @see String#endsWith(String) * @param str the CharSequence to check, may be null * @param suffix the suffix to find, may be null * @param ignoreCase indicates whether the compare should ignore case * (case insensitive) or not. * @return {@code true} if the CharSequence starts with the prefix or * both {@code null} */ private static boolean endsWith(final String str, final String suffix, final boolean ignoreCase) { if (str == null || suffix == null) { return str == null && suffix == null; } if (suffix.length() > str.length()) { return false; } final int strOffset = str.length() - suffix.length(); return regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); } /** * Green implementation of regionMatches. * * @param cs the {@code CharSequence} to be processed * @param ignoreCase whether or not to be case insensitive * @param thisStart the index to start on the {@code cs} CharSequence * @param substring the {@code CharSequence} to be looked for * @param start the index to start on the {@code substring} CharSequence * @param length character length of the region * @return whether the region matched */ static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, final CharSequence substring, final int start, final int length) { if (cs instanceof String && substring instanceof String) { return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); } int index1 = thisStart; int index2 = start; int tmpLen = length; while (tmpLen-- > 0) { final char c1 = cs.charAt(index1++); final char c2 = substring.charAt(index2++); if (c1 == c2) { continue; } if (!ignoreCase) { return false; } // The same check as in String.regionMatches(): if (Character.toUpperCase(c1) != Character.toUpperCase(c2) && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { return false; } } return true; } /** * <p>Splits the provided text into an array, separator specified. * This is an alternative to using StringTokenizer.</p> * * <p>The separator is not included in the returned String array. * Adjacent separators are treated as one separator. * For more control over the split use the StrTokenizer class.</p> * * <p>A {@code null} input String returns {@code null}.</p> * * <pre> * StringUtils.split(null, *) = null * StringUtils.split("", *) = [] * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] * StringUtils.split("a:b:c", '.') = ["a:b:c"] * StringUtils.split("a b c", ' ') = ["a", "b", "c"] * </pre> * * @param str the String to parse, may be null * @param separatorChar the character used as the delimiter * @return an array of parsed Strings, {@code null} if null String input * @since 2.0 */ public static String[] split(final String str, final String separatorChar) { return splitWorker(str, separatorChar, -1, false); } /** * Performs the logic for the {@code split} and * {@code splitPreserveAllTokens} methods that return a maximum array * length. * * @param str the String to parse, may be {@code null} * @param separatorChars the separate character * @param max the maximum number of elements to include in the * array. A zero or negative value implies no limit. * @param preserveAllTokens if {@code true}, adjacent separators are * treated as empty token separators; if {@code false}, adjacent * separators are treated as one separator. * @return an array of parsed Strings, {@code null} if null String input */ private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { // Performance tuned for 2.0 (JDK1.4) // Direct code is quicker than StringTokenizer. // Also, StringTokenizer uses isSpace() not isWhitespace() if (str == null) { return null; } final int len = str.length(); if (len == 0) { return EMPTY_STRING_ARRAY; } final List<String> list = new ArrayList<String>(); int sizePlus1 = 1; int i = 0, start = 0; boolean match = false; boolean lastMatch = false; if (separatorChars == null) { // Null separator means use whitespace while (i < len) { if (Character.isWhitespace(str.charAt(i))) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } else if (separatorChars.length() == 1) { // Optimise 1 character case final char sep = separatorChars.charAt(0); while (i < len) { if (str.charAt(i) == sep) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } else { // standard case while (i < len) { if (separatorChars.indexOf(str.charAt(i)) >= 0) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } list.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } if (match || preserveAllTokens && lastMatch) { list.add(str.substring(start, i)); } return list.toArray(new String[list.size()]); } /** * <p>Joins the elements of the provided array into a single String * containing the provided list of elements.</p> * * <p>No delimiter is added before or after the list. * A {@code null} separator is the same as an empty String (""). * Null objects or empty strings within the array are represented by * empty strings.</p> * * <pre> * StringUtils.join(null, *) = null * StringUtils.join([], *) = "" * StringUtils.join([null], *) = "" * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" * StringUtils.join(["a", "b", "c"], null) = "abc" * StringUtils.join(["a", "b", "c"], "") = "abc" * StringUtils.join([null, "", "a"], ',') = ",,a" * </pre> * * @param array the array of values to join together, may be null * @param separator the separator character to use, null treated as "" * @return the joined String, {@code null} if null array input */ public static String join(final Object[] array, final String separator) { if (array == null) { return null; } return join(array, separator, 0, array.length); } /** * <p>Joins the elements of the provided array into a single String * containing the provided list of elements.</p> * * <p>No delimiter is added before or after the list. * A {@code null} separator is the same as an empty String (""). * Null objects or empty strings within the array are represented by * empty strings.</p> * * <pre> * StringUtils.join(null, *, *, *) = null * StringUtils.join([], *, *, *) = "" * StringUtils.join([null], *, *, *) = "" * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" * </pre> * * @param array the array of values to join together, may be null * @param separator the separator character to use, null treated as "" * @param startIndex the first index to start joining from. * @param endIndex the index to stop joining from (exclusive). * @return the joined String, {@code null} if null array input; or the empty string * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by * {@code endIndex - startIndex} * @throws ArrayIndexOutOfBoundsException ife<br> * {@code startIndex < 0} or <br> * {@code startIndex >= array.length()} or <br> * {@code endIndex < 0} or <br> * {@code endIndex > array.length()} */ public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { if (array == null) { return null; } if (separator == null) { separator = EMPTY; } // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) // (Assuming that all Strings are roughly equally long) final int noOfItems = endIndex - startIndex; if (noOfItems <= 0) { return EMPTY; } final StringBuilder buf = new StringBuilder(noOfItems * 16); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); } if (array[i] != null) { buf.append(array[i]); } } return buf.toString(); } }