Java tutorial
// ///////////////////////////////////////////////////////// // This file is part of Propel. // // Propel is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Propel is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Propel. If not, see <http://www.gnu.org/licenses/>. // ///////////////////////////////////////////////////////// // Authored by: Nikolaos Tountas -> salam.kaser-at-gmail.com // ///////////////////////////////////////////////////////// package propel.core.utils; import static propel.core.functional.predicates.Strings.isNotNullOrEmpty; import static propel.core.functional.predicates.Strings.lengthEquals; import static propel.core.functional.projections.Strings.charAt; import java.math.BigDecimal; import java.net.Inet4Address; import java.net.InetAddress; import java.text.Collator; import java.text.DateFormat; import java.text.DecimalFormatSymbols; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.UUID; import lombok.Validate; import lombok.Validate.NotNull; import lombok.val; import org.joda.time.Duration; import org.joda.time.LocalDateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.joda.time.format.DateTimeParser; import org.joda.time.format.ISODateTimeFormat; import propel.core.TryResult; import propel.core.collections.lists.ReifiedArrayList; import propel.core.collections.lists.ReifiedList; import propel.core.common.CONSTANT; import propel.core.userTypes.Int128; import propel.core.userTypes.UnsignedByte; import propel.core.userTypes.UnsignedInteger; import propel.core.userTypes.UnsignedLong; import propel.core.userTypes.UnsignedShort; /** * Provides helper functionality for Strings and char arrays. */ public final class StringUtils { /** * The current locale of the JVM */ public static final Locale CURRENT_LOCALE = Locale.getDefault(); /** * An invariant locale across JVMs */ public static final Locale INVARIANT_LOCALE = Locale.US; /** * The current locale's collator */ public static final Collator CURRENT_LOCALE_COLLATOR = Collator.getInstance(CURRENT_LOCALE); /** * The invariant locale's collator */ public static final Collator INVARIANT_LOCALE_COLLATOR = Collator.getInstance(INVARIANT_LOCALE); private static final DecimalFormatSymbols CURRENT_DECIMAL_SYMBOLS = new DecimalFormatSymbols(CURRENT_LOCALE); /** * Current locale decimal separator symbol */ public static final char DECIMAL_SEPARATOR = CURRENT_DECIMAL_SYMBOLS.getDecimalSeparator(); /** * Current locale decimal grouping symbol */ public static final char GROUPING_SEPARATOR = CURRENT_DECIMAL_SYMBOLS.getGroupingSeparator(); private static final Duration MIN_DURATION = new Duration(Long.MIN_VALUE); private static final Duration MAX_DURATION = new Duration(Long.MAX_VALUE); private static final LocalDateTime MIN_DATETIME = new LocalDateTime(1, 1, 1, 0, 0, 0); // 1/1/0001 00:00:00 private static final LocalDateTime MAX_DATETIME = new LocalDateTime(9999, 12, 31, 23, 59, 59); // 31/12/9999 23:59:59 /** * ISO standard date/time formatters (composite class) */ public static final DateTimeFormatter STANDARD_FORMATTERS = (new DateTimeFormatterBuilder()) .append(null, createCommonDateTimeParsers()).toFormatter(); /** * Returns a character range from start (inclusive) to end (exclusive). * * @throws IllegalArgumentException When the end is before start */ public static char[] charRange(char start, char end) { int length = (int) end - (int) start; if (length < 0) throw new IllegalArgumentException("start=" + (int) start + " end=" + (int) end); char[] result = new char[length]; int index = 0; for (char ch = start; ch < end; ch++) result[index++] = ch; return result; } /** * Returns a character range from start (inclusive) to end (exclusive). * * @throws IllegalArgumentException When the end is before start */ public static char[] charRange(int start, int end) { return charRange((char) start, (char) end); } /** * Compares two Strings using a CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static int compare(String a, String b) { return compare(a, b, StringComparison.CurrentLocale); } /** * Compares two Strings using the specified string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static int compare(@NotNull final String a, @NotNull final String b, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: return compareLocaleSensitive(a, b, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, true); case CurrentLocaleIgnoreCase: return compareLocaleSensitive(a, b, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, false); case InvariantLocale: return compareLocaleSensitive(a, b, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, true); case InvariantLocaleIgnoreCase: return compareLocaleSensitive(a, b, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, false); case Ordinal: return compareOrdinal(a, b, true); case OrdinalIgnoreCase: return compareOrdinal(a, b, false); default: throw new IllegalArgumentException( "stringComparison has an unexpected value: " + stringComparison.toString()); } } /** * Comparison function, uses higher performance locale-aware comparison, uses existing collator to avoid creating one every time. * * @throws NullPointerException An argument is null. */ @Validate public static int compare(@NotNull final String a, @NotNull final String b, Locale locale, Collator collator, boolean caseSensitive) { return compareLocaleSensitive(a, b, locale, collator, caseSensitive); } /** * Locale-aware comparison. * * @throws NullPointerException An argument is null */ @Validate private static int compareLocaleSensitive(String a, String b, @NotNull final Locale locale, @NotNull final Collator collator, boolean caseSensitive) { if (!caseSensitive) { a = a.toLowerCase(locale); b = b.toLowerCase(locale); } return collator.compare(a, b); } /** * Compares two strings lexicographically * * @throws NullPointerException An argument is null */ private static int compareOrdinal(String a, String b, boolean caseSensitive) { if (caseSensitive) return a.compareTo(b); else { // ordinal ignore case int len1 = a.length(); int len2 = b.length(); int lim = len1 < len2 ? len1 : len2; char v1[] = a.toCharArray(); char v2[] = b.toCharArray(); int i = 0; while (i < lim) { char c1 = v1[i]; char c2 = v2[i]; // letters if ((c1 >= 65 && c1 <= 90) || (c1 >= 97 && c1 <= 122)) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); } if (c1 != c2) return c1 - c2; i++; } return len1 - len2; } } /** * Concatenates a collection of strings into a single string. Ignores null items. * * @throws NullPointerException An argument is null. */ public static String concat(Iterable<String> values) { return delimit(values, CONSTANT.EMPTY_STRING, null); } /** * Concatenates a collection of strings into a single string. Substitutes null items with the null-replacement value provided, if not * null. * * @throws NullPointerException The values argument is null. */ public static String concat(Iterable<String> values, String nullReplacementValue) { return delimit(values, CONSTANT.EMPTY_STRING, nullReplacementValue); } /** * Concatenates a collection of strings into a single string. Ignores null items. * * @throws NullPointerException An argument is null. */ public static String concat(String[] values) { return delimit(values, CONSTANT.EMPTY_STRING, null); } /** * Concatenates a collection of strings into a single string. Substitutes null items with the null-replacement value provided, if not * null. * * @throws NullPointerException The values argument is null. */ public static String concat(String[] values, String nullReplacementValue) { return delimit(values, CONSTANT.EMPTY_STRING, nullReplacementValue); } /** * Concatenates the given chars. Returns String.Empty if an empty collection was provided. * * @throws NullPointerException An argument is null. */ @Validate public static String concat(@NotNull final char[] values) { return new String(values); } /** * Concatenates the given chars. Returns an empty array if no chars are found. * * @throws NullPointerException When the values or one of its arguments is null. */ @Validate public static char[] concat(@NotNull final char[]... values) { int count = 0; for (char[] arr : values) { if (arr == null) throw new NullPointerException("Item of values"); count += arr.length; } char[] result = new char[count]; int index = 0; for (char[] arr : values) { System.arraycopy(arr, 0, result, index, arr.length); index += arr.length; } return result; } /** * Returns true if a char sequence contains a character * * @throws NullPointerException When the sequence is null. */ @Validate public static boolean contains(@NotNull final char[] sequence, char ch) { for (char c : sequence) if (c == ch) return true; return false; } /** * Returns true if a string contains a character * * @throws NullPointerException When the sequence is null. */ @Validate public static boolean contains(@NotNull final String value, char ch) { for (char c : value.toCharArray()) if (c == ch) return true; return false; } /** * Returns true if the part is contained in the value. Uses CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static boolean contains(String value, String part) { return contains(value, part, StringComparison.CurrentLocale); } /** * Returns true if the part is contained in the value. Uses the specified string comparison. * * @throws NullPointerException An argument is null. */ public static boolean contains(String value, String part, StringComparison stringComparison) { return indexOf(value, part, 0, value.length(), stringComparison) >= 0; } /** * Returns true if the part is contained in the value. Uses culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ public static boolean contains(String value, String part, Locale locale, Collator collator, boolean caseSensitive) { return indexOf(value, part, 0, value.length(), locale, collator, caseSensitive) >= 0; } /** * Returns true if the value is contained in the collection of values. Uses the specified string comparison mode. * * @throws NullPointerException An argument is null. */ @Validate public static boolean contains(@NotNull final Iterable<String> values, String value, StringComparison stringComparison) { if (value == null) return Linq.contains(values, null); else for (String val : values) if (equal(value, val, stringComparison)) return true; return false; } /** * Returns true if the value is contained in the collection of values. Uses culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean contains(@NotNull final Iterable<String> values, String value, Locale locale, Collator collator, boolean caseSensitive) { if (value == null) return Linq.contains(values, null); else for (String val : values) if (equal(value, val, locale, collator, caseSensitive)) return true; return false; } /** * Returns true if the value is contained in the collection of values. Uses the specified string comparison mode. * * @throws NullPointerException An argument is null. */ @Validate public static boolean contains(@NotNull final String[] values, String value, StringComparison stringComparison) { if (value == null) return Linq.contains(values, null); else for (String val : values) if (equal(value, val, stringComparison)) return true; return false; } /** * Returns true if the value is contained in the collection of values. Uses culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean contains(@NotNull final String[] values, String value, Locale locale, Collator collator, boolean caseSensitive) { if (value == null) return Linq.contains(values, null); else for (String val : values) if (equal(value, val, locale, collator, caseSensitive)) return true; return false; } /** * Returns true if all characters are contained in a string. Order is not taken into consideration. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAll(@NotNull final String value, @NotNull final char[] characters) { for (char ch : characters) if (value.indexOf(ch) < 0) return false; return true; } /** * Returns true if all strings specified are contained in the value string. Order is not taken into consideration. Uses the CurrentLocale * StringComparison. * * @throws NullPointerException An argument is null. */ public static boolean containsAll(String value, Iterable<String> parts) { return containsAll(value, parts, StringComparison.CurrentLocale); } /** * Returns true if all strings specified are contained in the value string. Order is not taken into consideration. If a part is null then * false is returned. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAll(@NotNull final String value, @NotNull final Iterable<String> parts, StringComparison stringComparison) { // check that all exist for (String part : parts) if (part == null) return false; else if (indexOf(value, part, 0, value.length(), stringComparison) < 0) return false; return true; } /** * Returns true if all strings specified are contained in the value string. Order is not taken into consideration. If a part is null then * false is returned. Uses culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAll(@NotNull final String value, @NotNull final Iterable<String> parts, Locale locale, Collator collator, boolean caseSensitive) { // check that all exist for (String part : parts) if (part == null) return false; else if (indexOf(value, part, 0, value.length(), locale, collator, caseSensitive) < 0) return false; return true; } /** * Returns true if all items are contained in the values string collection. Order is not taken into consideration. You may use null * elements for both values and items. Uses CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static boolean containsAll(Iterable<String> values, Iterable<String> items) { return containsAll(values, items, StringComparison.CurrentLocale); } /** * Returns true if all items are contained in the values string collection. Order is not taken into consideration. You may use null * elements for both values and items. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAll(@NotNull final Iterable<String> values, @NotNull final Iterable<String> items, StringComparison stringComparison) { for (String item : items) { boolean found = false; for (String value : values) { if (item == null && value == null) continue; if (item == null || value == null) return false; if (equal(item, value, stringComparison)) found = true; } if (!found) return false; } return true; } /** * Returns true if all items in items are contained in the values string collection. Order is not taken into consideration. You may use * null elements for values and items. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAll(@NotNull final Iterable<String> values, @NotNull final Iterable<String> items, Locale locale, Collator collator, boolean caseSensitive) { for (String item : items) { boolean found = false; for (String value : values) { if (item == null && value == null) continue; if (item == null || value == null) return false; if (equal(item, value, locale, collator, caseSensitive)) found = true; } if (!found) return false; } return true; } /** * Returns true if all characters are contained in a string. Order is not taken into consideration. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAny(@NotNull final String value, @NotNull final char[] characters) { for (char ch : characters) if (value.indexOf(ch) >= 0) return true; return false; } /** * Returns true if any of the strings are contained in a string. Order is not taken into consideration. Uses the CurrentLocale * StringComparison. * * @throws NullPointerException An argument is null. */ public static boolean containsAny(String value, Iterable<String> parts) { return containsAny(value, parts, StringComparison.CurrentLocale); } /** * Returns true if any of the strings are contained in a string. Order is not taken into consideration. If a part is null then it is * ignored. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAny(@NotNull final String value, @NotNull final Iterable<String> parts, StringComparison stringComparison) { // check if parts contained for (String part : parts) if (part != null) if (contains(value, part, stringComparison)) return true; return false; } /** * Returns true if any of the strings are contained in a string. Order is not taken into consideration. If a part is null then it is * ignored. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAny(@NotNull final String value, @NotNull final Iterable<String> parts, Locale locale, Collator collator, boolean caseSensitive) { // check if parts contained for (String part : parts) if (part != null) if (contains(value, part, locale, collator, caseSensitive)) return true; return false; } /** * Returns true if any item in items is contained in the values string collection. Order is not taken into consideration. You may use null * elements for values and items. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAny(@NotNull final Iterable<String> values, @NotNull final Iterable<String> items, StringComparison stringComparison) { for (String item : items) for (String value : values) { if (item == null && value == null) return true; if (item == null || value == null) continue; if (equal(item, value, stringComparison)) return true; } return false; } /** * Returns true if any item in items is contained in the values string collection. Order is not taken into consideration. You may use null * elements for values and items. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean containsAny(@NotNull final Iterable<String> values, @NotNull final Iterable<String> items, Locale locale, Collator collator, boolean caseSensitive) { for (String item : items) for (String value : values) { if (item == null && value == null) return true; if (item == null || value == null) continue; if (equal(item, value, locale, collator, caseSensitive)) return true; } return false; } /** * Similar to String.Substring * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds. */ @Validate public static String copy(@NotNull final String value, int startIndex, int endIndex) { if (startIndex < 0 || startIndex > endIndex) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " endIndex=" + endIndex); if (endIndex > value.length()) throw new IndexOutOfBoundsException("endIndex=" + endIndex + " length=" + value.length()); return value.substring(startIndex, endIndex); } /** * Returns the number of occurences of a character in a character array. * * @throws NullPointerException An argument is null. */ @Validate public static int count(@NotNull final char[] array, char ch) { int count = 0; for (char c : array) if (c == ch) count++; return count; } /** * Returns the number of occurences of a character in a string value. * * @throws NullPointerException An argument is null. */ @Validate public static int count(@NotNull final String value, char character) { int result = 0; for (char s : value.toCharArray()) if (s == character) result++; return result; } /** * Returns the number of occurences of a string element in a string value, using the CurrentLocale StringComparison. * * @throws NullPointerException An argument is null. */ public static int count(String value, String element) { return count(value, element, StringComparison.CurrentLocale); } /** * Returns the number of occurences of a string element in a string value, using the specified string comparison type. * * @throws NullPointerException An argument is null. */ @Validate public static int count(@NotNull final String value, @NotNull final String element, StringComparison stringComparison) { int valLen = value.length(); if (valLen <= 0 || element.length() <= 0) return 0; int result = 0; int index = 0; while ((index = indexOf(value, element, index, valLen - index, stringComparison)) >= 0) { index++; result++; } return result; } /** * Returns the number of occurences of a string element in a string value, using the specified string comparison type. Uses a * culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static int count(@NotNull final String value, @NotNull final String element, Locale locale, Collator collator, boolean caseSensitive) { int valLen = value.length(); if (valLen <= 0 || element.length() <= 0) return 0; int result = 0; int index = 0; while ((index = indexOf(value, element, index, valLen - index, locale, collator, caseSensitive)) >= 0) { index++; result++; } return result; } /** * Performs a cropStart and cropEnd, returning the result * * @throws NullPointerException An argument is null */ public static String crop(String value, char except) { return cropStart(cropEnd(value, except), except); } /** * Performs a cropStart and cropEnd, returning the result * * @throws NullPointerException An argument is null */ public static String crop(String value, char[] except) { return cropStart(cropEnd(value, except), except); } /** * Crops all characters from the start of the given string, until the except character is encountered * * @throws NullPointerException An argument is null */ public static String cropStart(String value, char except) { return cropStart(value, new char[] { except }); } /** * Crops all characters from the start of the given string, until a character is encountered which exists in the given exception array * * @throws NullPointerException An argument is null */ @Validate public static String cropStart(@NotNull final String value, @NotNull final char[] except) { int startIndex = 0; while (startIndex <= value.length() - 1 && !contains(except, value.charAt(startIndex))) startIndex++; return value.substring(startIndex); } /** * Crops all characters from the end of the given string, until the except character is encountered * * @throws NullPointerException An argument is null */ public static String cropEnd(String value, char except) { return cropEnd(value, new char[] { except }); } /** * Crops all characters from the end of the given string, until a character is encountered which exists in the given exception array * * @throws NullPointerException An argument is null */ @Validate public static String cropEnd(@NotNull final String value, @NotNull final char[] except) { int endIndex = value.length() - 1; while (endIndex > 0 && !contains(except, value.charAt(endIndex))) endIndex--; return value.substring(0, endIndex + 1); } /** * Returns CR, LF or CRLF, depending on the frequency of line separators found in the given text data. * * @throws NullPointerException An argument is null. */ public static String detectLineSeparator(String text) { return detectLineSeparator(text, 2.0f); } /** * Returns CR, LF or CRLF, depending on the frequency of line separators found in the given text data. Accepts a ratio, to ensure the * decision is not swayed by CRs or LFs appearing randomly in the code. For example a value of 2.0f for a CR End-Of-Line (EOL) terminated * file would return CR if the file contains twice the number of CRs than the number of LFs. * * @throws NullPointerException An argument is null. */ @Validate public static String detectLineSeparator(@NotNull final String text, float ratio) { int crs = count(text, CONSTANT.CR_CHAR); int lfs = count(text, CONSTANT.LF_CHAR); // multiply to ensure random CR/LFs used in source do not affect the outcome if (crs > lfs * ratio) return CONSTANT.CR; else if (lfs > crs * ratio) return CONSTANT.LF; else return CONSTANT.CRLF; } /** * Deletes the specified range of characters from the string. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds. */ @Validate public static String delete(@NotNull final String value, int startIndex, int endIndex) { if (startIndex < 0 || startIndex > endIndex) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " endIndex=" + endIndex); if (endIndex > value.length()) throw new IndexOutOfBoundsException("endIndex=" + endIndex + " length=" + value.length()); return value.substring(0, startIndex) + value.substring(endIndex); } /** * Concatenates the given values using their toString() method and appending the given delimiter between all values. Returns String.Empty * if an empty or null collection was provided. Ignores null collection items. * * @throws NullPointerException An argument is null. */ public static String delimit(Iterable<String> values, String delimiter) { return delimit(values, delimiter, null); } /** * Concatenates the given values using their toString() method and appending the given delimiter between all values. Returns String.Empty * if an empty or null collection was provided. Substitutes null items with a null-replacement value, if provided and is not null. * * @throws NullPointerException An argument is null. */ @Validate public static String delimit(@NotNull final Iterable<String> values, @NotNull final String delimiter, String nullReplacementValue) { val sb = new StringBuilder(256); for (String value : values) if (value != null) { sb.append(value.toString()); sb.append(delimiter); } else // append null replacement if (nullReplacementValue != null) { sb.append(nullReplacementValue); sb.append(delimiter); } if (sb.length() > 0) return sb.subSequence(0, sb.length() - delimiter.length()).toString(); return CONSTANT.EMPTY_STRING; } /** * Concatenates the given values using their toString() method and appending the given delimiter between all values. Returns String.Empty * if an empty or null collection was provided. Ignores null collection items. * * @throws NullPointerException An argument is null. */ public static String delimit(String[] values, String delimiter) { return delimit(values, delimiter, null); } /** * Concatenates the given values using their toString() method and appending the given delimiter between all values. Returns String.Empty * if an empty or null collection was provided. Substitutes null items with a null-replacement value, if provided and is not null. * * @throws NullPointerException An argument is null. */ @Validate public static String delimit(@NotNull final String[] values, @NotNull final String delimiter, String nullReplacementValue) { val sb = new StringBuilder(256); for (String value : values) if (value != null) { sb.append(value.toString()); sb.append(delimiter); } else // append null replacement if (nullReplacementValue != null) { sb.append(nullReplacementValue); sb.append(delimiter); } if (sb.length() > 0) return sb.subSequence(0, sb.length() - delimiter.length()).toString(); return CONSTANT.EMPTY_STRING; } /** * Concatenates the given chars with the given delimiter between all values. Returns String.Empty if an empty or null collection was * provided. * * @throws NullPointerException An argument is null. */ @Validate public static String delimit(@NotNull final char[] values, @NotNull final String delimiter) { val sb = new StringBuilder(256); for (char value : values) { sb.append(value); sb.append(delimiter); } if (sb.length() > 0) return sb.subSequence(0, sb.length() - delimiter.length()).toString(); return CONSTANT.EMPTY_STRING; } /** * Returns true if the value ends with a suffix. * * @throws NullPointerException An argument is null. */ @Validate public static boolean endsWith(@NotNull final String value, char suffix) { if (value.length() == 0) return false; return value.charAt(value.length() - 1) == suffix; } /** * Returns true if a value ends with a suffix. Uses the CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static boolean endsWith(String value, String suffix) { return endsWith(value, suffix, StringComparison.CurrentLocale); } /** * Returns true if a value ends with a suffix. Uses the specified string comparison. * * @throws NullPointerException An argument is null. */ public static boolean endsWith(String value, String suffix, StringComparison stringComparison) { return lastIndexOf(value, suffix, value.length() - 1, 1, stringComparison) >= 0; } /** * Returns true if a value ends with a suffix. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ public static boolean endsWith(String value, String suffix, Locale locale, Collator collator, boolean caseSensitive) { return lastIndexOf(value, suffix, value.length() - 1, 1, locale, collator, caseSensitive) >= 0; } /** * Returns true if a value equals with another. Uses the CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static boolean equal(String a, String b) { return equal(a, b, StringComparison.CurrentLocale); } /** * Returns true if a value equals with another. Uses the specified string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean equal(@NotNull final String a, @NotNull final String b, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: return equalLocaleSensitive(a, b, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, true); case CurrentLocaleIgnoreCase: return equalLocaleSensitive(a, b, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, false); case InvariantLocale: return equalLocaleSensitive(a, b, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, true); case InvariantLocaleIgnoreCase: return equalLocaleSensitive(a, b, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, false); case Ordinal: return equalOrdinal(a, b, true); case OrdinalIgnoreCase: return equalOrdinal(a, b, false); default: throw new IllegalArgumentException( "stringComparison has an unexpected value: " + stringComparison.toString()); } } /** * Returns true if a value equals with another. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean equal(@NotNull final String a, @NotNull final String b, Locale locale, Collator collator, boolean caseSensitive) { return equalLocaleSensitive(a, b, locale, collator, caseSensitive); } /** * Locale-aware string equality comparison. */ @Validate private static boolean equalLocaleSensitive(String a, String b, @NotNull final Locale locale, @NotNull final Collator collator, boolean caseSensitive) { if (!caseSensitive) { a = a.toLowerCase(locale); b = b.toLowerCase(locale); } return collator.equals(a, b); } /** * Compares two strings for equality */ private static boolean equalOrdinal(String a, String b, boolean caseSensitive) { if (a.length() != b.length()) return false; return indexOfOrdinal(a, b, 0, 1, caseSensitive) == 0; } /** * Finds the first index encountered of a particular character. Returns -1 if not found. * * @throws NullPointerException An argument is null. */ @Validate public static int indexOf(@NotNull final char[] array, char ch) { for (int i = 0; i < array.length; i++) if (array[i] == ch) return i; return -1; } /** * Returns the first index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses the * CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static int indexOf(String value, String part) { return indexOf(value, part, 0, value.length(), StringComparison.CurrentLocale); } /** * Returns the first index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses the * specified string comparison. * * @throws NullPointerException An argument is null. */ public static int indexOf(String value, String part, StringComparison stringComparison) { return indexOf(value, part, 0, value.length(), stringComparison); } /** * Returns the first index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses a * culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static int indexOf(@NotNull final String value, @NotNull final String part, Locale locale, Collator collator, boolean caseSensitive) { return indexOfLocaleSensitive(value, part, 0, value.length(), locale, collator, caseSensitive); } /** * Returns the first, second, third, etc. index where a part is encountered within a string value, starting at the specified index and * moving to the right of the string. If the part is not existent, -1 is returned. Uses the specified string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static int indexOf(@NotNull final String value, @NotNull final String part, int startIndex, int count, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: return indexOfLocaleSensitive(value, part, startIndex, count, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, true); case CurrentLocaleIgnoreCase: return indexOfLocaleSensitive(value, part, startIndex, count, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, false); case InvariantLocale: return indexOfLocaleSensitive(value, part, startIndex, count, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, true); case InvariantLocaleIgnoreCase: return indexOfLocaleSensitive(value, part, startIndex, count, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, false); case Ordinal: return indexOfOrdinal(value, part, startIndex, count, true); case OrdinalIgnoreCase: return indexOfOrdinal(value, part, startIndex, count, false); default: throw new IllegalArgumentException( "stringComparison has an unexpected value: " + stringComparison.toString()); } } /** * Returns the first, second, third, etc. index where a part is encountered within a string value, starting at the specified index and * moving to the right of the string. If the part is not existent, -1 is returned. Uses a culture-aware higher performance string * comparison. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ @Validate public static int indexOf(@NotNull final String value, @NotNull final String part, int startIndex, int count, Locale locale, Collator collator, boolean caseSensitive) { return indexOfLocaleSensitive(value, part, startIndex, count, locale, collator, caseSensitive); } /** * Performs a locale-sensitive string comparison * * @param value The source value * @param part The value we're looking for * @param startIndex The index in source where we start looking * @param count Up to how many positions to look forward * @param locale The locale to use for toLowercase conversions, if a case sensitive comparison * @param collator The collator to use to compare locale-sensitive strings * @param caseSensitive Whether case sensitive or not * * @return The index where the part was found in value, or -1 if not found. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ @Validate private static int indexOfLocaleSensitive(String value, String part, int startIndex, int count, @NotNull final Locale locale, @NotNull final Collator collator, boolean caseSensitive) { int valueLen = value.length(); int partLen = part.length(); int endIndex = startIndex + count; if (startIndex > valueLen) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " valueLen=" + valueLen); if (valueLen == 0) if (partLen == 0) return 0; else return -1; if (startIndex < 0) throw new IndexOutOfBoundsException("startIndex=" + startIndex); if (count < 0 || endIndex > valueLen) throw new IllegalArgumentException( "count=" + count + " endIndex=" + endIndex + " valueLen=" + valueLen); // select comparison type if (caseSensitive) // case-sensitive comparison from start position to end position for (int i = startIndex; i < endIndex; i++) // some Strings have different lengths but are equal // e.g. for US: "\u00C4" "LATIN CAPITAL LETTER A WITH DIAERESIS" () and "\u0041\u0308" "LATIN CAPITAL LETTER A" (A) - // "COMBINING DIAERESIS" () // therefore we have to examine whether the part is equal to ANY portion of the length of the string for (int j = 1; j < valueLen - i + 1; j++) { String val = value.substring(i, i + j); if (collator.equals(val, part)) return i; } else { String lowerPart = part.toLowerCase(locale); // case-insensitive comparison from start position to end position for (int i = startIndex; i < endIndex; i++) // some Strings have different lengths but are equal such as the diaeresis example above, // additionally (for this case) in some instances the string lengths of the toLowercase conversion will differ // e.g. for LT: "\u00cc" () becomes 3 characters (i) for (int j = 1; j < valueLen - i + 1; j++) { String val = value.substring(i, i + j); if (collator.equals(val.toLowerCase(locale), lowerPart)) return i; } } return -1; } /** * Performs an ordinal string comparison. * * @param value The source value * @param part The value we're looking for * @param startIndex The index in source where we start looking * @param count Up to how many positions to look forward * @param caseSensitive Whether case sensitive or not * * @return The index where the part was found in value, or -1 if not found. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ private static int indexOfOrdinal(String value, String part, int startIndex, int count, boolean caseSensitive) { int valueLen = value.length(); int partLen = part.length(); if (startIndex > valueLen) throw new IndexOutOfBoundsException("startIndex=" + startIndex); if (valueLen == 0) if (partLen == 0) return 0; else return -1; if (startIndex < 0) throw new IndexOutOfBoundsException("startIndex=" + startIndex); if ((count < 0) || startIndex + count > valueLen || startIndex + count < 0) throw new IllegalArgumentException( "count=" + count + " startIndex=" + startIndex + " partLen=" + partLen); // calculate the least amount of time we have to iterate through string characters int minCount = valueLen - partLen + 1; if (count + startIndex < minCount) minCount = count + startIndex; char[] vArr = value.toCharArray(); char[] pArr = part.toCharArray(); if (caseSensitive) for (int i = startIndex; i < minCount; i++) { boolean found = true; for (int j = 0; j < partLen; j++) { char vCh = vArr[i + j]; char pCh = pArr[j]; // compare chars if (vCh != pCh) { found = false; break; } } if (found) return i; } else // case insensitive for (int i = startIndex; i < minCount; i++) { boolean found = true; for (int j = 0; j < partLen; j++) { char vCh = vArr[i + j]; char pCh = pArr[j]; // ASCII letters are converted to lowercase if ((vCh >= 65 && vCh <= 90) || (vCh >= 97 && vCh <= 122)) { vCh = Character.toLowerCase(vCh); pCh = Character.toLowerCase(pCh); } // compare chars if (vCh != pCh) { found = false; break; } } if (found) return i; } return -1; } /** * Returns the index of the first/second/third/etc. occurrence of an element in a value, starting from the left and moving forward. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Occurrence is out of range. */ @Validate public static int indexOf(@NotNull final String value, @NotNull final String part, int occurrence, StringComparison stringComparison) { if (value.length() <= 0 || part.length() <= 0) return 0; if (occurrence <= 0) throw new IllegalArgumentException("occurrence" + occurrence); int result = 0; int index = 0; while ((index = indexOf(value, part, index, value.length() - index, stringComparison)) >= 0) { result++; // check if occurrence reached, if so we found our result if (result == occurrence) return index; index++; } return -1; } /** * Returns the index of the first/second/third/etc. occurrence of an element in a value, starting from the left and moving forward. Uses a * culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Occurrence is out of range. */ @Validate public static int indexOf(@NotNull final String value, @NotNull final String part, int occurrence, Locale locale, Collator collator, boolean caseSensitive) { if (value.length() <= 0 || part.length() <= 0) return 0; if (occurrence <= 0) throw new IllegalArgumentException("occurrence=" + occurrence); int result = 0; int index = 0; while ((index = indexOf(value, part, index, value.length() - index, locale, collator, caseSensitive)) >= 0) { result++; // check if occurrence reached, if so we found our result if (result == occurrence) return index; index++; } return -1; } /** * Inserts a string in a position in the given string. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException Index is out of range. */ @Validate public static String insert(@NotNull final String value, int index, @NotNull final String insertedValue) { if (index < 0 || index > value.length()) throw new IndexOutOfBoundsException("index=" + index + " length=" + value.length()); return value.substring(0, index) + insertedValue + value.substring(index); } /** * Returns true if the given string is null or empty. */ public static boolean isNullOrEmpty(String value) { return value == null || value.length() == 0; } /** * Returns true if the given string is null or contains only whitespace chars (' ', '\t', '\r' and '\n'). * * @author Marcin Lamparski */ public static boolean isNullOrBlank(String value) { return value == null || trim(value).length() == 0; } /** * Finds the last index encountered of a particular character. Returns -1 if not found. * * @throws NullPointerException An argument is null. */ @Validate public static int lastIndexOf(@NotNull final char[] array, char ch) { for (int i = array.length - 1; i >= 0; i--) if (array[i] == ch) return i; return -1; } /** * Returns the last index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses the * CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static int lastIndexOf(String value, String part) { return lastIndexOf(value, part, StringComparison.CurrentLocale); } /** * Returns the last index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses the * specified string comparison. * * @throws NullPointerException An argument is null. */ public static int lastIndexOf(String value, String part, StringComparison stringComparison) { return lastIndexOf(value, part, value.length() - 1, value.length(), stringComparison); } /** * Returns the last index where a part is encountered within a string value. If the part is not existent, -1 is returned. Uses a * culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static int lastIndexOf(@NotNull final String value, @NotNull final String part, Locale locale, Collator collator, boolean caseSensitive) { return lastIndexOfLocaleSensitive(value, part, value.length() - 1, value.length(), locale, collator, caseSensitive); } /** * Returns the first, second, third, etc. index where a part is encountered within a string value, starting at the specified index and * moving to the left of the string. If the part is not existent, -1 is returned. Uses the specified string comparison. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ @Validate public static int lastIndexOf(@NotNull final String value, @NotNull final String part, int startIndex, int count, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: return lastIndexOfLocaleSensitive(value, part, startIndex, count, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, true); case CurrentLocaleIgnoreCase: return lastIndexOfLocaleSensitive(value, part, startIndex, count, CURRENT_LOCALE, CURRENT_LOCALE_COLLATOR, false); case InvariantLocale: return lastIndexOfLocaleSensitive(value, part, startIndex, count, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, true); case InvariantLocaleIgnoreCase: return lastIndexOfLocaleSensitive(value, part, startIndex, count, INVARIANT_LOCALE, INVARIANT_LOCALE_COLLATOR, false); case Ordinal: return lastIndexOfOrdinal(value, part, startIndex, count, true); case OrdinalIgnoreCase: return lastIndexOfOrdinal(value, part, startIndex, count, false); default: throw new IllegalArgumentException( "stringComparison has an unexpected value: " + stringComparison.toString()); } } /** * Returns the first, second, third, etc. index where a part is encountered within a string value, starting at the specified index and * moving to the left of the string. If the part is not existent, -1 is returned. Uses a culture-aware higher performance string * comparison. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ @Validate public static int lastIndexOf(@NotNull final String value, @NotNull final String part, int startIndex, int count, Locale locale, Collator collator, boolean caseSensitive) { return lastIndexOfLocaleSensitive(value, part, startIndex, count, locale, collator, caseSensitive); } /** * Performs a locale-sensitive string comparison * * @param value The source value * @param part The value we're looking for * @param startIndex The index in source where we start looking * @param count Up to how many positions to look backward * @param locale The locale to use for toLowercase conversions, if a case sensitive comparison * @param collator The collator to use to compare locale-sensitive strings * @param caseSensitive Whether case sensitive or not * * @return The index where the part was found in value, or -1 if not found. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ @Validate private static int lastIndexOfLocaleSensitive(String value, String part, int startIndex, int count, @NotNull final Locale locale, @NotNull final Collator collator, boolean caseSensitive) { int valueLen = value.length(); int partLen = part.length(); int endIndex = startIndex - count + 1; if ((valueLen == 0) && ((startIndex == -1) || (startIndex == 0))) if (partLen != 0) return -1; else return 0; if ((startIndex < 0) || (startIndex > valueLen)) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " valueLen=" + valueLen); if (count < 0 || endIndex < 0) throw new IllegalArgumentException("count=" + count + " startIndex=" + startIndex); // select comparison type if (caseSensitive) // case-sensitive comparison from start position to end position for (int i = startIndex + 1; i > endIndex; i--) // some Strings have different lengths but are equal // e.g. for US: "\u00C4" "LATIN CAPITAL LETTER A WITH DIAERESIS" () and "\u0041\u0308" "LATIN CAPITAL LETTER A" (A) - // "COMBINING DIAERESIS" () // therefore we have to examine whether the part is equal to ANY portion of the length of the string for (int j = i - 1; j >= 0; j--) { String val = value.substring(j, i); if (collator.equals(val, part)) return j; } else { String lowerPart = part.toLowerCase(locale); // case-insensitive comparison from start position to end position for (int i = startIndex + 1; i > endIndex; i--) // some Strings have different lengths but are equal such as the diaeresis example above, // additionally (for this case) in some instances the string lengths of the toLowercase conversion will differ // e.g. for LT: "\u00cc" () becomes 3 characters (i) for (int j = i - 1; j >= 0; j--) { String val = value.substring(j, i); if (collator.equals(val.toLowerCase(locale), lowerPart)) return j; } } return -1; } /** * Performs an ordinal string comparison. * * @param value The source value * @param part The value we're looking for * @param startIndex The index in source where we start looking * @param count Up to how many positions to look forward * @param caseSensitive Whether case sensitive or not * * @return The index where the part was found in value, or -1 if not found. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds * @throws IllegalArgumentException An argument is out of range */ private static int lastIndexOfOrdinal(String value, String part, int startIndex, int count, boolean caseSensitive) { int valueLen = value.length(); int partLen = part.length(); int endIndex = startIndex - count + 1; if ((valueLen == 0) && (startIndex == -1 || startIndex == 0)) if (partLen != 0) return -1; else return 0; if ((startIndex < 0) || (startIndex > valueLen)) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " valueLen=" + valueLen); // following commented out: replaced by this if ((count < 0) || endIndex < 0) throw new IllegalArgumentException("count=" + count + " startIndex=" + startIndex); // calculate the least amount of time we have to iterate through string characters int minCount = startIndex - (valueLen - partLen); if (endIndex > minCount) minCount = endIndex; char[] vArr = value.toCharArray(); char[] pArr = part.toCharArray(); if (caseSensitive) for (int i = startIndex; i >= minCount; i--) { boolean found = true; for (int j = 0; j < partLen; j++) if (i - j < 0) found = false; else { char vCh = vArr[i - j]; char pCh = pArr[partLen - j - 1]; // compare chars if (vCh != pCh) { found = false; break; } } if (found) return i - partLen + 1; } else // case insensitive for (int i = startIndex; i >= minCount; i--) { boolean found = true; for (int j = 0; j < partLen; j++) if (i - j < 0) found = false; else { char vCh = vArr[i - j]; char pCh = pArr[partLen - j - 1]; // ASCII letters are converted to lowercase if ((vCh >= 65 && vCh <= 90) || (vCh >= 97 && vCh <= 122)) { vCh = Character.toLowerCase(vCh); pCh = Character.toLowerCase(pCh); } // compare chars if (vCh != pCh) { found = false; break; } } if (found) return i - partLen + 1; } return -1; } /** * Returns the index of the first/second/third/etc. occurrence of an element in a value, starting from the right and moving backward. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Occurrence is out of range. */ @Validate public static int lastIndexOf(@NotNull final String value, @NotNull final String part, int occurrenceFromEnd, StringComparison stringComparison) { if (value.length() <= 0 || part.length() <= 0) return 0; if (occurrenceFromEnd <= 0) throw new IllegalArgumentException("occurrenceFromEnd" + occurrenceFromEnd); int result = 0; int index = value.length() - 1; while ((index = lastIndexOf(value, part, index, index + 1, stringComparison)) >= 0) { result++; // check if occurrence reached, if so we found our result if (result == occurrenceFromEnd) return index; index--; if (index < 0) break; } return -1; } /** * Returns the index of the first/second/third/etc. occurrence of an element in a value, starting from the right and moving backward. Uses * a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Occurrence is out of range. */ @Validate public static int lastIndexOf(@NotNull final String value, @NotNull final String part, int occurrenceFromEnd, Locale locale, Collator collator, boolean caseSensitive) { if (value.length() <= 0 || part.length() <= 0) return 0; if (occurrenceFromEnd <= 0) throw new IllegalArgumentException("occurrenceFromEnd" + occurrenceFromEnd); int result = 0; int index = value.length() - 1; while ((index = lastIndexOf(value, part, index, index + 1, locale, collator, caseSensitive)) >= 0) { result++; // check if occurrence reached, if so we found our result if (result == occurrenceFromEnd) return index; index--; if (index < 0) break; } return -1; } /** * Allows for matching a string to another, using Equals, StartsWith, EndsWith or Contains and a string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean match(@NotNull final String a, MatchType stringMatch, @NotNull final String b, StringComparison stringComparison) { switch (stringMatch) { case Equals: return equal(a, b, stringComparison); case Contains: return indexOf(a, b, stringComparison) >= 0; case StartsWith: return startsWith(a, b, stringComparison); case EndsWith: return endsWith(a, b, stringComparison); default: throw new IllegalArgumentException("Unrecognized string match type: " + stringMatch); } } /** * Allows for matching a string to another, using Equals, StartsWith, EndsWith or Contains and a string comparison. Uses a culture-aware * higher performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static boolean match(@NotNull final String a, MatchType stringMatch, @NotNull final String b, Locale locale, Collator collator, boolean caseSensitive) { switch (stringMatch) { case Equals: return equal(a, b, locale, collator, caseSensitive); case Contains: return indexOf(a, b, locale, collator, caseSensitive) >= 0; case StartsWith: return startsWith(a, b, locale, collator, caseSensitive); case EndsWith: return endsWith(a, b, locale, collator, caseSensitive); default: throw new IllegalArgumentException("Unrecognized string match type: " + stringMatch); } } /** * Right-aligns the characters in this instance, padding on the left a specified character * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException An invalid argument was given. */ @Validate public static String padRight(@NotNull final String value, int totalLength, char pad) { if (totalLength < 0) throw new IllegalArgumentException("totalLength=" + totalLength); int add = totalLength - value.length(); if (add < 0) throw new IllegalArgumentException("totalLength=" + totalLength + " len=" + value.length()); StringBuilder str = new StringBuilder(value); char[] ch = new char[add]; Arrays.fill(ch, pad); str.append(ch); return str.toString(); } /** * Left-aligns the characters in this instance, padding on the right a specified character * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException An invalid argument was given. */ @Validate public static String padLeft(@NotNull final String value, int totalLength, char pad) { if (totalLength < 0) throw new IllegalArgumentException("totalLength=" + totalLength); int add = totalLength - value.length(); if (add < 0) throw new IllegalArgumentException("totalLength=" + totalLength + " len=" + value.length()); StringBuilder str = new StringBuilder(value); char[] ch = new char[add]; Arrays.fill(ch, pad); str.insert(0, ch); return str.toString(); } /** * Parses a boolean from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static boolean parseBool(String value) { return parseBool(value, CONSTANT.TRUE, CONSTANT.FALSE, StringComparison.OrdinalIgnoreCase); } /** * Parses a boolean from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static boolean parseBool(@NotNull final String value, @NotNull final String trueValue, @NotNull final String falseValue, StringComparison comparisonType) { // parse if (equal(trueValue, value, comparisonType)) return true; else if (equal(falseValue, value, comparisonType)) return false; // sanity check throw new NumberFormatException( "Value given was neither " + trueValue + " nor " + falseValue + ": " + value); } /** * Parses the first character from a string. * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static char parseChar(String value) { return parseChar(value, Character.MIN_VALUE, Character.MAX_VALUE); } /** * Parses the first character from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static char parseChar(@NotNull final String value, char minValue, char maxValue) { if (value.length() != 1) throw new NumberFormatException("Value is not 1 character long: " + value); char result = value.charAt(0); // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a DateTime from a string. Uses common ISO formats as well as some locale-specific formats. See * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html ISO format examples: * <ul> * <li>yyyyMMdd'T'HHmmssZ</li> * <li>yyyyMMdd'T'HHmmss.SSSZ</li> * <li>yyyy-MM-dd</li> * <li>yyyy-MM-dd'T'HH:mm:ss.SSS</li> * <li>yyyy-MM-dd'T'HH:mm:ssZZ</li> * <li>yyyy-MM-dd'T'HH:mm:ss.SSSZZ</li> * <li>yyyy-MM-dd HH:mm:ss</li> * <li>yyyy-MM-dd HH:mm:ss.SSSSSSS</li> * <li>yyyy-MM-dd'T'HH:mm:ss</li> * <li>yyyy-MM-dd'T'HH:mm:ss.SSSSSSS</li> * </ul> * <p/> * Also supports non-ISO formats such as yyyy/MM/dd. Furthermore attempts to parse using locale-specific parsers. * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static LocalDateTime parseDateTime(@NotNull final String value) { LocalDateTime result = null; // attempt ISO standard parsing try { result = STANDARD_FORMATTERS.parseDateTime(value).toLocalDateTime(); } catch (Throwable e) { // continues parsing attempts } if (result == null) // first try locale-specific date/time parsing for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++) for (int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; timeStyle++) if (result == null) try { // Parse with a default format Date date = DateFormat.getDateTimeInstance(dateStyle, timeStyle, CURRENT_LOCALE) .parse(value); result = new LocalDateTime(date); break; } catch (ParseException e) { continue; } if (result == null) // now try locale-specific date parsing for (int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++) try { // Parse with a default format Date date = DateFormat.getDateInstance(dateStyle, CURRENT_LOCALE).parse(value); result = new LocalDateTime(date); break; } catch (ParseException e) { continue; } if (result == null) // lastly try locale-specific time parsing for (int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; timeStyle++) try { // Parse with a default format Date date = DateFormat.getTimeInstance(timeStyle, CURRENT_LOCALE).parse(value); result = new LocalDateTime(date); break; } catch (ParseException e) { continue; } if (result == null) throw new NumberFormatException("The specified date/time is not in an identifiable format: " + value); // sanity check if (result.compareTo(MIN_DATETIME) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + MIN_DATETIME + ")."); if (result.compareTo(MAX_DATETIME) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + MAX_DATETIME + ")."); return result; } /** * Parses a DateTime from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static LocalDateTime parseDateTime(String value, DateTimeFormatter formatter) { return parseDateTime(value, MIN_DATETIME, MAX_DATETIME, formatter); } /** * Parses a DateTime from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static LocalDateTime parseDateTime(@NotNull final String value, @NotNull final LocalDateTime minValue, @NotNull final LocalDateTime maxValue, @NotNull final DateTimeFormatter formatter) { // parse LocalDateTime result = formatter.parseDateTime(value).toLocalDateTime(); // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a decimal from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static BigDecimal parseDecimal(@NotNull final String value) { // parse BigDecimal result; try { // check if the current locale uses the same decimal separator and grouping chars as expected by the parser if (DECIMAL_SEPARATOR != CONSTANT.COMMA_CHAR) { // remove grouping separators and replace decimal separators to commas String converted = StringUtils.replace(value, GROUPING_SEPARATOR + CONSTANT.EMPTY_STRING, CONSTANT.EMPTY_STRING, StringComparison.Ordinal); result = new BigDecimal(converted); } else result = new BigDecimal(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } return result; } /** * Parses a decimal from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static BigDecimal parseDecimal(@NotNull final String value, @NotNull final BigDecimal minValue, @NotNull final BigDecimal maxValue) { // parse BigDecimal result; try { // check if the current locale uses the same decimal separator and grouping chars as expected by the parser if (DECIMAL_SEPARATOR != CONSTANT.COMMA_CHAR) { // remove grouping separators and replace decimal separators to commas String converted = StringUtils.replace(value, GROUPING_SEPARATOR + CONSTANT.EMPTY_STRING, CONSTANT.EMPTY_STRING, StringComparison.Ordinal); result = new BigDecimal(converted); } else result = new BigDecimal(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a double from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static double parseDouble(String value) { return parseDouble(value, -Double.MAX_VALUE, Double.MAX_VALUE, true, true); } /** * Parses a double from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static double parseDouble(@NotNull final String value, double minValue, double maxValue, boolean allowInfinity, boolean allowNaN) { // parse double result; try { // check if the current locale uses the same decimal separator and grouping chars as expected by the parser if (DECIMAL_SEPARATOR != CONSTANT.COMMA_CHAR) { // remove grouping separators and replace decimal separators to commas String converted = StringUtils.replace(value, GROUPING_SEPARATOR + CONSTANT.EMPTY_STRING, CONSTANT.EMPTY_STRING, StringComparison.Ordinal); result = Double.parseDouble(converted); } else result = Double.parseDouble(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } if (allowInfinity) if (result == Double.POSITIVE_INFINITY || result == Double.NEGATIVE_INFINITY) return result; if (allowNaN) if (result == Double.NaN) return result; // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a float from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static float parseFloat(String value) { return parseFloat(value, -Float.MAX_VALUE, Float.MAX_VALUE, true, true); } /** * Parses a float from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static float parseFloat(@NotNull final String value, float minValue, float maxValue, boolean allowInfinity, boolean allowNaN) { // parse float result; try { // check if the current locale uses the same decimal separator and grouping chars as expected by the parser if (DECIMAL_SEPARATOR != CONSTANT.COMMA_CHAR) { // remove grouping separators and replace decimal separators to commas String converted = StringUtils.replace(value, GROUPING_SEPARATOR + CONSTANT.EMPTY_STRING, CONSTANT.EMPTY_STRING, StringComparison.Ordinal); result = Float.parseFloat(converted); } else result = Float.parseFloat(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } if (allowInfinity) if (result == Double.POSITIVE_INFINITY || result == Double.NEGATIVE_INFINITY) return result; if (allowNaN) if (result == Double.NaN) return result; // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a byte from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static byte parseInt8(String value) { return parseInt8(value, Byte.MIN_VALUE, Byte.MAX_VALUE); } /** * Parses a byte from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static byte parseInt8(@NotNull final String value, byte minValue, byte maxValue) { // parse byte result; try { result = Byte.parseByte(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a short from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static short parseInt16(String value) { return parseInt16(value, Short.MIN_VALUE, Short.MAX_VALUE); } /** * Parses a short from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static short parseInt16(@NotNull final String value, short minValue, short maxValue) { // parse short result; try { result = Short.parseShort(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses an int from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static int parseInt32(String value) { return parseInt32(value, Integer.MIN_VALUE, Integer.MAX_VALUE); } /** * Parses an int from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static int parseInt32(@NotNull final String value, int minValue, int maxValue) { // parse int result; try { result = Integer.parseInt(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a long from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static long parseInt64(String value) { return parseInt64(value, Long.MIN_VALUE, Long.MAX_VALUE); } /** * Parses a long from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static long parseInt64(@NotNull final String value, long minValue, long maxValue) { // parse long result; try { result = Long.parseLong(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result < minValue) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result > maxValue) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses an Int128 from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static Int128 parseInt128(String value) { return parseInt128(value, Int128.MIN_VALUE, Int128.MAX_VALUE); } /** * Parses an Int128 from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static Int128 parseInt128(@NotNull final String value, @NotNull final Int128 minValue, @NotNull final Int128 maxValue) { // parse Int128 result; try { result = new Int128(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses the value of the given string: simply returns the string after checking for null. * * @throws NullPointerException When an argument is null */ @Validate public static String parseString(@NotNull final String value) { return value; } /** * Parses the value of the given object: simply returns the toString() result after checking for null, if the object is null the result is * null. */ public static String parseString(Object value) { return value != null ? value.toString() : null; } /** * Parses a TimeSpan from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static Duration parseTimeSpan(String value) { return parseTimeSpan(value, MIN_DURATION, MAX_DURATION); } /** * Parses a TimeSpan from a string. TimeSpans are .NET structs and do not have an equivalent in Java. They express time durations in * ticks, which are units 1000 times smaller than milliseconds. * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static Duration parseTimeSpan(@NotNull final String value, @NotNull final Duration minValue, @NotNull final Duration maxValue) { Duration result; try { result = new Duration(Long.parseLong(value) / 1000); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses an sbyte from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static UnsignedByte parseUInt8(String value) { return parseUInt8(value, UnsignedByte.MIN_VALUE, UnsignedByte.MAX_VALUE); } /** * Parses an sbyte from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static UnsignedByte parseUInt8(@NotNull final String value, @NotNull final UnsignedByte minValue, @NotNull final UnsignedByte maxValue) { // parse UnsignedByte result; try { result = new UnsignedByte(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a ushort from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static UnsignedShort parseUInt16(String value) { return parseUInt16(value, UnsignedShort.MIN_VALUE, UnsignedShort.MAX_VALUE); } /** * Parses a ushort from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static UnsignedShort parseUInt16(@NotNull final String value, @NotNull final UnsignedShort minValue, @NotNull final UnsignedShort maxValue) { // parse UnsignedShort result; try { result = new UnsignedShort(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a uint from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static UnsignedInteger parseUInt32(String value) { return parseUInt32(value, UnsignedInteger.MIN_VALUE, UnsignedInteger.MIN_VALUE); } /** * Parses a uint from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static UnsignedInteger parseUInt32(@NotNull final String value, @NotNull final UnsignedInteger minValue, @NotNull final UnsignedInteger maxValue) { // parse UnsignedInteger result; try { result = new UnsignedInteger(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Parses a ulong from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ public static UnsignedLong parseUInt64(String value) { return parseUInt64(value, UnsignedLong.MIN_VALUE, UnsignedLong.MAX_VALUE); } /** * Parses a ulong from a string * * @throws NullPointerException An argument is null. * @throws NumberFormatException Parsed value is outside of configured range, or not of correct type. */ @Validate public static UnsignedLong parseUInt64(@NotNull final String value, @NotNull final UnsignedLong minValue, @NotNull final UnsignedLong maxValue) { // parse UnsignedLong result; try { result = new UnsignedLong(value); } catch (Throwable e) { throw new NumberFormatException("The value '" + value + "' could not be parsed: " + e.getMessage()); } // sanity check if (result.compareTo(minValue) < 0) throw new NumberFormatException( "Value (" + result + ") was less than allowed minimum (" + minValue + ")."); if (result.compareTo(maxValue) > 0) throw new NumberFormatException( "Value (" + result + ") was more than allowed maximum (" + maxValue + ")."); return result; } /** * Replaces text in a value with the specified replacement text, using the given string comparison type. * * @throws NullPointerException An argument is null. */ @Validate public static String replace(@NotNull String value, @NotNull final String textToReplace, @NotNull final String replaceWithText, StringComparison stringComparison) { if (textToReplace.length() == 0) return value; int index = 0; switch (stringComparison) { case CurrentLocale: case CurrentLocaleIgnoreCase: case InvariantLocale: case InvariantLocaleIgnoreCase: // for these we must not assume that the length is the same as textToReplace.length() while ((index = indexOf(value, textToReplace, index, value.length() - index, stringComparison)) >= 0) { String prefix = value.substring(0, index); for (int i = index + 1; i <= value.length(); i++) { // find index String replace = value.substring(index, i); if (equal(replace, textToReplace, stringComparison)) { // end index found, replace value = prefix + replaceWithText + value.substring(i); break; } } index += replaceWithText.length(); } break; case Ordinal: case OrdinalIgnoreCase: while ((index = indexOf(value, textToReplace, index, value.length() - index, stringComparison)) >= 0) { value = value.substring(0, index) + replaceWithText + value.substring(index + textToReplace.length()); index += replaceWithText.length(); } break; default: throw new IllegalArgumentException("Unrecognized string comparison type: " + stringComparison); } return value; } /** * Replaces text in a value with the specified replacement text, using the given string comparison type. Uses a culture-aware higher * performance string comparison. * * @throws NullPointerException An argument is null. */ @Validate public static String replace(@NotNull String value, @NotNull final String textToReplace, @NotNull final String replaceWithText, Locale locale, Collator collator, boolean caseSensitive) { if (textToReplace.length() == 0) return value; int index = 0; // for these we must not assume that the length is the same as textToReplace.length() while ((index = indexOf(value, textToReplace, index, value.length() - index, locale, collator, caseSensitive)) >= 0) { String prefix = value.substring(0, index); for (int i = index + 1; i <= value.length(); i++) { // find index String replace = value.substring(index, i); if (equal(replace, textToReplace, locale, collator, caseSensitive)) { // end index found, replace value = prefix + replaceWithText + value.substring(i); break; } } index += replaceWithText.length(); } return value; } /** * Replace method working on a string builder, for more efficient replacement. * * @throws NullPointerException An argument is null. */ @Validate public static void replace(@NotNull final StringBuilder builder, @NotNull final String textToReplace, @NotNull final String replaceWithText) { int indexOfTarget = -1; while ((indexOfTarget = builder.indexOf(textToReplace)) > 0) builder.replace(indexOfTarget, indexOfTarget + textToReplace.length(), replaceWithText); } /** * Returns a number of ToString() result concatenations of the given character. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Repetitions argument is out of range. */ public static String repeat(char value, int repetitions) { return repeat(Character.toString(value), repetitions); } /** * Returns a number of ToString() result concatenations of the given string value. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException Repetitions argument is out of range. */ @Validate public static String repeat(@NotNull final String value, int repetitions) { if (repetitions < 0) throw new IllegalArgumentException("repetitions=" + repetitions); StringBuilder sb = new StringBuilder(value.length() * repetitions); for (int i = 0; i < repetitions; i++) sb.append(value); return sb.toString(); } /** * Reverses a string. * * @throws NullPointerException An argument is null. */ @Validate public static String reverse(@NotNull final String value) { val sb = new StringBuilder(value); return sb.reverse().toString(); } /** * Returns true if two character sequences are equal * * @throws NullPointerException An argument is null. */ @Validate public static boolean sequenceEqual(@NotNull final char[] a, @NotNull final char[] b) { if (a.length != b.length) return false; if (a.length == 0) return false; return sequenceEqual(a, 0, b, 0, a.length); } /** * Returns true if two character sequences are equal * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException An index is out of bounds. * @throws IllegalArgumentException An argument is out of range. */ @Validate public static boolean sequenceEqual(@NotNull final char[] a, int startIndexA, @NotNull final char[] b, int startIndexB, int count) { if (count == 0) return true; if (startIndexA < 0 || startIndexA > a.length) throw new IndexOutOfBoundsException("startIndexA=" + startIndexA + " aLen=" + a.length); if (startIndexB < 0 || startIndexB > b.length) throw new IndexOutOfBoundsException("startIndexB=" + startIndexB + " bLen=" + b.length); if (count < 0) throw new IllegalArgumentException("count=" + count); if (startIndexA + count > a.length || startIndexA + count < 0) throw new IllegalArgumentException( "startIndexA=" + startIndexA + " count=" + count + " aLen=" + a.length); if (startIndexB + count > b.length || startIndexB + count < 0) throw new IllegalArgumentException( "startIndexB=" + startIndexB + " count=" + count + " bLen=" + b.length); for (int i = 0; i < count; i++) if (a[startIndexA + i] != b[startIndexB + i]) return false; return true; } /** * Splits a sequence into parts delimited by the specified delimited. Empty entries between delimiters are removed. * * @throws NullPointerException When an argument is null, or an item in the iterable is null. */ @Validate public static List<char[]> split(@NotNull final char[] values, char delimiter) { List<ReifiedList<Character>> parts = new ArrayList<ReifiedList<Character>>(); parts.add(new ReifiedArrayList<Character>(Character.class)); for (char item : values) if (item != delimiter) parts.get(parts.size() - 1).add(item); else parts.add(new ReifiedArrayList<Character>(Character.class)); List<char[]> result = new ArrayList<char[]>(); for (ReifiedList<Character> arr : parts) if (arr.size() > 0) result.add(ArrayUtils.unbox(arr.toArray())); return result; } /** * Splits a string, using StringSplitOptions.RemoveEmptyEntries. * * @throws NullPointerException An argument is null. */ public static String[] split(String text, char delimiter) { return split(text, delimiter, StringSplitOptions.RemoveEmptyEntries); } /** * Splits a string using the specified split option. * * @throws NullPointerException An argument is null. */ public static String[] split(String text, char delimiter, StringSplitOptions options) { char[] delimiters = new char[] { delimiter }; return split(text, delimiters, options); } /** * Returns a string array that contains the substrings of the text instance that are delimited by elements of a specified Unicode * character array. * * @throws NullPointerException An argument is null. */ @Validate public static String[] split(@NotNull final String text, @NotNull final char[] delimiters, StringSplitOptions options) { val result = new ReifiedArrayList<String>(String.class); // if no separators, return the original string if (delimiters.length == 0) { result.add(text); return result.toArray(); } int lastFound = 0; int index = 0; for (char ch : text.toCharArray()) { // check if character is a separator if (contains(delimiters, ch)) { if (lastFound == index) result.add(CONSTANT.EMPTY_STRING); else // add part without separator result.add(text.substring(lastFound, index)); // mark last found position lastFound = index + 1; } index++; } // add last part if any if (index > lastFound) result.add(text.substring(lastFound, index)); else if (index == lastFound && text.length() > 0 && contains(delimiters, text.charAt(text.length() - 1))) result.add(CONSTANT.EMPTY_STRING); switch (options) { case None: return result.toArray(); case RemoveEmptyEntries: return Linq.where(result.toArray(), isNotNullOrEmpty()); default: throw new IllegalArgumentException("stringSplitOptions has an unexpected value: " + options.toString()); } } /** * Splits a string, using StringSplitOptions.RemoveEmptyEntries. When splitting strings, Ordinal string comparison is always used. * * @throws NullPointerException An argument is null. */ public static String[] split(String text, String delimiter) { return split(text, delimiter, StringSplitOptions.RemoveEmptyEntries); } /** * Splits a string using the specified split option. When splitting strings, Ordinal string comparison is always used. * * @throws NullPointerException An argument is null. */ @Validate public static String[] split(@NotNull final String text, @NotNull final String delimiter, StringSplitOptions options) { val delimiters = new String[] { delimiter }; return split(text, delimiters, options); } /** * Returns a string array that contains the substrings of the text instance that are delimited by elements provided in the specified * Unicode string array. When splitting strings, Ordinal string comparison is always used. * * @throws NullPointerException An argument is null. */ @Validate public static String[] split(@NotNull final String text, @NotNull String[] delimiters, StringSplitOptions options) { // ignore null and empty delimiters delimiters = Linq.where(delimiters, isNotNullOrEmpty()); // case where there are no delimiters ReifiedList<String> result = new ReifiedArrayList<String>(String.class); if (delimiters.length <= 0) { result.add(text); return result.toArray(); } // simplify if all delimiters are chars, call character delimiter method if (Linq.all(delimiters, lengthEquals(1))) return split(text, ArrayUtils.unbox(Linq.select(delimiters, charAt(0))), options); // multiple delimiters, handled separately result.add(text); for (int i = 0; i < delimiters.length; i++) { ReifiedList<String> currentResults = new ReifiedArrayList<String>(String.class); for (String part : result) { String[] splitParts = part.split(delimiters[i]); for (String splitPart : splitParts) currentResults.add(splitPart); } result = currentResults; } switch (options) { case None: return result.toArray(); case RemoveEmptyEntries: return Linq.toArray(Linq.where(result, isNotNullOrEmpty()), String.class); default: throw new IllegalArgumentException("Unrecognized string split option: " + options); } } /** * Splits a string by finding consecutive 'tags' i.e. delimiters. E.g. for 0d1h2m3s, using "d,h,m,s" as delimiters would return { 0,1,2,3 * }. Delimiters that are not found will be ignored. E.g. for 0d1h2m3s, using "d,m,h,s" as delimiters would return { 0,1h2,3 } (i.e. h not * found after m). Uses Ordinal string comparison. Does not continuously split in the same way split() does, uses anchor points instead. * When splitting strings, Ordinal string comparison is always used. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException A delimiter is null or empty. */ @Validate public static String[] splitAnchor(@NotNull String text, @NotNull final Iterable<String> delimiters) { // parts are stored here val result = new ReifiedArrayList<String>(String.class); // process delimiters serially for (String delim : delimiters) { if (isNullOrEmpty(delim)) throw new IllegalArgumentException("A delimiter cannot be null or empty!"); if (!isNullOrEmpty(text)) { ReifiedList<String> parts = new ReifiedArrayList<String>(split(text, delim)); if (parts.size() >= 2) { // store if any found result.add(parts.get(0)); text = text.substring(parts.get(0).length() + 1); } } } return result.toArray(); } /** * Splits a string by finding consecutive 'tags' i.e. delimiters. E.g. for 0d1h2m3s, using "d,h,m,s" as delimiters would return { 0,1,2,3 * }. Delimiters that are not found will be ignored. E.g. for 0d1h2m3s, using "d,m,h,s" as delimiters would return { 0,1h2,3 } (i.e. h not * found after m). Uses Ordinal string comparison. Does not continuously split in the same way split() does, uses anchor points instead. * When splitting strings, Ordinal string comparison is always used. * * @throws NullPointerException An argument is null. * @throws IllegalArgumentException A delimiter is null or empty. */ @Validate public static String[] splitAnchor(String text, @NotNull final String[] delimiters) { return splitAnchor(text, Arrays.asList(delimiters)); } /** * Returns true if the value starts with a prefix. * * @throws NullPointerException An argument is null. */ @Validate public static boolean startsWith(@NotNull final String value, char prefix) { if (value.length() == 0) return false; return value.charAt(0) == prefix; } /** * Returns true if a value starts with a prefix. Uses the CurrentLocale string comparison. * * @throws NullPointerException An argument is null. */ public static boolean startsWith(String value, String prefix) { return indexOf(value, prefix, 0, value.length(), StringComparison.CurrentLocale) == 0; } /** * Returns true if a value starts with a prefix. Uses the specified string comparison. * * @throws NullPointerException An argument is null. */ public static boolean startsWith(String value, String prefix, StringComparison stringComparison) { return indexOf(value, prefix, 0, 1, stringComparison) == 0; } /** * Returns true if a value starts with a prefix. Uses a culture-aware higher performance string comparison. * * @throws NullPointerException An argument is null. */ public static boolean startsWith(String value, String prefix, Locale locale, Collator collator, boolean caseSensitive) { return indexOf(value, prefix, 0, 1, locale, collator, caseSensitive) == 0; } /** * Similar to String.Substring of .NET, uses a length instead of endIndex. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException The length is out of range. */ public static String substring(String value, int length) { return substring(value, 0, length); } /** * Similar to String.Substring of .NET, uses a length instead of endIndex. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException The index or length is out of range. */ @Validate public static String substring(@NotNull final String value, int startIndex, int length) { int valueLen = value.length(); if (startIndex < 0 || startIndex >= valueLen) throw new IndexOutOfBoundsException("startIndex=" + startIndex + " valueLen=" + valueLen); if (length < 0 || startIndex + length > valueLen || startIndex + length < 0) throw new IndexOutOfBoundsException( "length=" + length + " startIndex=" + startIndex + " valueLen=" + valueLen); return new String(value.toCharArray(), startIndex, length); } /** * Title-cases a string * * @throws NullPointerException An argument is null */ @Validate public static String titleCase(@NotNull final String value) { val parts = split(value, CONSTANT.WHITESPACE_CHAR, StringSplitOptions.None); for (int i = 0; i < parts.length; i++) if (parts[i].length() > 0) parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase(); return delimit(parts, CONSTANT.WHITESPACE); } /** * Returns a character range from start to end (inclusive) * * @throws NullPointerException An argument is null * @throws IllegalArgumentException When the end is before start */ public static Character[] to(Character start, Character end) { return ArrayUtils.box(charRange(start.charValue(), end.charValue() + 1)); } /** * Trims a value's beginning of all instances of the given char. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ @Validate public static String trimStart(@NotNull final String value, char ch) { return trimStart(value, new char[] { ch }); } /** * Trims a value's beginning of all the given chars. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ @Validate public static String trimStart(@NotNull final String value, @NotNull final char[] chars) { int startIndex = 0; while (startIndex <= value.length() - 1 && contains(chars, value.charAt(startIndex))) startIndex++; return value.substring(startIndex); } /** * Trims a value's tail of all the instance of the given char. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ @Validate public static String trimEnd(@NotNull final String value, char ch) { return trimEnd(value, new char[] { ch }); } /** * Trims a value's tail of all the given chars. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ @Validate public static String trimEnd(@NotNull final String value, @NotNull final char[] chars) { int endIndex = value.length() - 1; while (endIndex > 0 && contains(chars, value.charAt(endIndex))) endIndex--; return value.substring(0, endIndex + 1); } /** * Trims a value of all whitespace chars, i.e. ' ', '\t', '\r', '\n'. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ public static String trim(String value) { return trim(value, CONSTANT.WHITESPACE_CHARS); } /** * Trims a value of all the given chars. Does so repeatedly until no more matches are found. * * @throws NullPointerException When an argument is null. */ public static String trim(String value, char[] chars) { return trimEnd(trimStart(value, chars), chars); } /** * Trims a value using the trimmed string. * * @throws NullPointerException An argument is null. */ @Validate public static String trimStart(@NotNull String value, @NotNull final String trimmed, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: case CurrentLocaleIgnoreCase: case InvariantLocale: case InvariantLocaleIgnoreCase: // we must not assume that the length is the same as trimmed.length() while (startsWith(value, trimmed, stringComparison)) // find end position for (int i = 0; i <= value.length(); i++) if (equal(trimmed, value.substring(0, i), stringComparison)) { value = value.substring(i); break; } case Ordinal: case OrdinalIgnoreCase: while (startsWith(value, trimmed, stringComparison)) value = value.substring(trimmed.length()); break; } return value; } /** * Trims a value using the trimmed string. * * @throws NullPointerException An argument is null. */ @Validate public static String trimEnd(@NotNull String value, @NotNull final String trimmed, StringComparison stringComparison) { switch (stringComparison) { case CurrentLocale: case CurrentLocaleIgnoreCase: case InvariantLocale: case InvariantLocaleIgnoreCase: // we must not assume that the length is the same as trimmed.length() while (endsWith(value, trimmed, stringComparison)) // find end position for (int i = value.length() - 1; i >= 0; i--) if (equal(trimmed, value.substring(i, value.length()))) { value = value.substring(0, i); break; } case Ordinal: case OrdinalIgnoreCase: while (endsWith(value, trimmed, stringComparison)) value = value.substring(0, value.length() - trimmed.length()); break; } return value; } /** * Trims a value using the trimmed string. * * @throws NullPointerException An argument is null. */ public static String trim(String value, String trimmed, StringComparison stringComparison) { return trimEnd(trimStart(value, trimmed, stringComparison), trimmed, stringComparison); } /** * Cuts the tail of a string, at the specified index. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException The index is out of bounds. */ @Validate public static String truncate(@NotNull final String value, int endIndex) { if (endIndex < 0 || endIndex > value.length()) throw new IndexOutOfBoundsException("endIndex=" + endIndex + " length=" + value.length()); return value.substring(0, endIndex); } /** * Cuts the tail of a string, if it exceeds a specified index, otherwise does nothing. * * @throws NullPointerException An argument is null. * @throws IndexOutOfBoundsException The index is negative. */ @Validate public static String truncateIfLonger(@NotNull final String value, int endIndex) { if (endIndex < 0) throw new IndexOutOfBoundsException("endIndex=" + endIndex); if (endIndex > value.length()) return value; return value.substring(0, endIndex); } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Boolean> tryParseBool(String value) { try { return new TryResult<Boolean>(parseBool(value)); } catch (Throwable e) { return new TryResult<Boolean>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Boolean> tryParseBool(String value, String trueValue, String falseValue, StringComparison comparisonType) { try { return new TryResult<Boolean>(parseBool(value, trueValue, falseValue, comparisonType)); } catch (Throwable e) { return new TryResult<Boolean>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Character> tryParseChar(String value) { try { return new TryResult<Character>(parseChar(value)); } catch (Throwable e) { return new TryResult<Character>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Character> tryParseChar(String value, char minValue, char maxValue) { try { return new TryResult<Character>(parseChar(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Character>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<LocalDateTime> tryParseDateTime(String value) { try { return new TryResult<LocalDateTime>(parseDateTime(value)); } catch (Throwable e) { return new TryResult<LocalDateTime>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<LocalDateTime> tryParseDateTime(String value, DateTimeFormatter fmt) { try { return new TryResult<LocalDateTime>(parseDateTime(value, fmt)); } catch (Throwable e) { return new TryResult<LocalDateTime>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<LocalDateTime> tryParseDateTime(String value, LocalDateTime minValue, LocalDateTime maxValue, DateTimeFormatter fmt) { try { return new TryResult<LocalDateTime>(parseDateTime(value, minValue, maxValue, fmt)); } catch (Throwable e) { return new TryResult<LocalDateTime>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<BigDecimal> tryParseDecimal(String value) { try { return new TryResult<BigDecimal>(parseDecimal(value)); } catch (Throwable e) { return new TryResult<BigDecimal>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<BigDecimal> tryParseDecimal(String value, BigDecimal minValue, BigDecimal maxValue) { try { return new TryResult<BigDecimal>(parseDecimal(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<BigDecimal>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Double> tryParseDouble(String value) { try { return new TryResult<Double>(parseDouble(value)); } catch (Throwable e) { return new TryResult<Double>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Double> tryParseDouble(String value, double minValue, double maxValue, boolean allowInfinity, boolean allowNaN) { try { return new TryResult<Double>(parseDouble(value, minValue, maxValue, allowInfinity, allowNaN)); } catch (Throwable e) { return new TryResult<Double>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Float> tryParseFloat(String value) { try { return new TryResult<Float>(parseFloat(value)); } catch (Throwable e) { return new TryResult<Float>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Float> tryParseFloat(String value, float minValue, float maxValue, boolean allowInfinity, boolean allowNaN) { try { return new TryResult<Float>(parseFloat(value, minValue, maxValue, allowInfinity, allowNaN)); } catch (Throwable e) { return new TryResult<Float>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Byte> tryParseInt8(String value) { try { return new TryResult<Byte>(parseInt8(value)); } catch (Throwable e) { return new TryResult<Byte>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Byte> tryParseInt8(String value, byte minValue, byte maxValue) { try { return new TryResult<Byte>(parseInt8(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Byte>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Short> tryParseInt16(String value) { try { return new TryResult<Short>(parseInt16(value)); } catch (Throwable e) { return new TryResult<Short>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Short> tryParseInt16(String value, short minValue, short maxValue) { try { return new TryResult<Short>(parseInt16(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Short>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Integer> tryParseInt32(String value) { try { return new TryResult<Integer>(parseInt32(value)); } catch (Throwable e) { return new TryResult<Integer>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Integer> tryParseInt32(String value, int minValue, int maxValue) { try { return new TryResult<Integer>(parseInt32(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Integer>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Long> tryParseInt64(String value) { try { return new TryResult<Long>(parseInt64(value)); } catch (Throwable e) { return new TryResult<Long>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Long> tryParseInt64(String value, long minValue, long maxValue) { try { return new TryResult<Long>(parseInt64(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Long>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Int128> tryParseInt128(String value) { try { return new TryResult<Int128>(parseInt128(value)); } catch (Throwable e) { return new TryResult<Int128>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Int128> tryParseInt128(String value, Int128 minValue, Int128 maxValue) { try { return new TryResult<Int128>(parseInt128(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Int128>(); } } /** * Tries to parse the given value. Supports IPv4 and IPv6. * <p/> * Does not throw exceptions while parsing under any circumstances. */ public static TryResult<InetAddress> tryParseIpAddress(String value) { try { return new TryResult<InetAddress>(Inet4Address.getByName(value)); } catch (Throwable e) { try { return new TryResult<InetAddress>(InetAddress.getByName(value)); } catch (Throwable e2) { return new TryResult<InetAddress>(); } } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Duration> tryParseTimeSpan(String value) { try { return new TryResult<Duration>(parseTimeSpan(value)); } catch (Throwable e) { return new TryResult<Duration>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<Duration> tryParseTimeSpan(String value, Duration minValue, Duration maxValue) { try { return new TryResult<Duration>(parseTimeSpan(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<Duration>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedByte> tryParseUInt8(String value) { try { return new TryResult<UnsignedByte>(parseUInt8(value)); } catch (Throwable e) { return new TryResult<UnsignedByte>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedByte> tryParseUInt8(String value, UnsignedByte minValue, UnsignedByte maxValue) { try { return new TryResult<UnsignedByte>(parseUInt8(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<UnsignedByte>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedShort> tryParseUInt16(String value) { try { return new TryResult<UnsignedShort>(parseUInt16(value)); } catch (Throwable e) { return new TryResult<UnsignedShort>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedShort> tryParseUInt16(String value, UnsignedShort minValue, UnsignedShort maxValue) { try { return new TryResult<UnsignedShort>(parseUInt16(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<UnsignedShort>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedInteger> tryParseUInt32(String value) { try { return new TryResult<UnsignedInteger>(parseUInt32(value)); } catch (Throwable e) { return new TryResult<UnsignedInteger>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedInteger> tryParseUInt32(String value, UnsignedInteger minValue, UnsignedInteger maxValue) { try { return new TryResult<UnsignedInteger>(parseUInt32(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<UnsignedInteger>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedLong> tryParseUInt64(String value) { try { return new TryResult<UnsignedLong>(parseUInt64(value)); } catch (Throwable e) { return new TryResult<UnsignedLong>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UnsignedLong> tryParseUInt64(String value, UnsignedLong minValue, UnsignedLong maxValue) { try { return new TryResult<UnsignedLong>(parseUInt64(value, minValue, maxValue)); } catch (Throwable e) { return new TryResult<UnsignedLong>(); } } /** * Tries to parse the given value. Does not throw exceptions while parsing under any circumstances. */ public static TryResult<UUID> tryParseUuid(String value) { try { return new TryResult<UUID>(UUID.fromString(value)); } catch (Throwable e) { return new TryResult<UUID>(); } } /** * Returns a character range from start (inclusive) to end (exclusive) * * @throws NullPointerException An argument is null * @throws IllegalArgumentException When the end is before start */ public static Character[] until(Character start, Character end) { return ArrayUtils.box(charRange(start.charValue(), end.charValue())); } /** * Returns ISO standard and other frequently used date/time parsers */ private static DateTimeParser[] createCommonDateTimeParsers() { return new DateTimeParser[] { ISODateTimeFormat.basicDateTimeNoMillis().getParser(), // yyyyMMdd'T'HHmmssZ ISODateTimeFormat.basicDateTime().getParser(), // yyyyMMdd'T'HHmmss.SSSZ ISODateTimeFormat.dateHourMinuteSecondFraction().getParser(), // yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS (only 3 ms positions used though) ISODateTimeFormat.dateTimeNoMillis().getParser(), // yyyy-MM-dd'T'HH:mm:ssZZ ISODateTimeFormat.dateTime().getParser(), // yyyy-MM-dd'T'HH:mm:ss.SSSZZ (ISO 8601) DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss Z").getParser(), // RFC 2822 DateTimeFormat.forPattern("yyyy/MM/dd").getParser(), DateTimeFormat.forPattern("yyyy/MM/dd HH:mm").getParser(), DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss").getParser(), DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss.SSSSSSSSS").getParser(), DateTimeFormat.forPattern("yyyy-MM-dd").getParser(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").getParser(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").getParser(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS").getParser(), DateTimeFormat.forPattern("yyyy.MM.dd").getParser(), DateTimeFormat.forPattern("yyyy.MM.dd HH:mm").getParser(), DateTimeFormat.forPattern("yyyy.MM.dd HH:mm:ss").getParser(), DateTimeFormat.forPattern("yyyy.MM.dd HH:mm:ss.SSSSSSSSS").getParser(), DateTimeFormat.forPattern("HH:mm").getParser(), DateTimeFormat.forPattern("HH:mm:ss").getParser(), DateTimeFormat.forPattern("HH:mm:ss.SSSSSSSSS").getParser() }; } private StringUtils() { } }