package sk.stuba.fiit.perconik.utilities; import java.io.Serializable; import java.text.Collator; import java.util.Comparator; import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import jersey.repackaged.com.google.common.collect.Lists; import static java.lang.String.valueOf; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Strings.isNullOrEmpty; import static sk.stuba.fiit.perconik.utilities.MorePreconditions.checkNotNullOrEmpty; /** * Static utility methods pertaining to {@code String} or {@code CharSequence} * instances. * * @author Pavol Zbell * @since 1.0 */ public final class MoreStrings { static final String lineSeparatorRegex = "\r?\n|\r"; private MoreStrings() {} public static boolean equalsIgnoreLineSeparators(final String s, @Nullable final Object o) { if (s == o) { return true; } if (o instanceof String) { String r = (String) o; char[] v = r.toCharArray(); char[] u = s.toCharArray(); int m = v.length; int n = u.length; int i = 0; int j = 0; while (i < m) { char c = v[i ++]; if (c == '\n' || c == '\r') { continue; } while (j < n) { char d = u[j ++]; if (d == '\n' || d == '\r') { continue; } if (c == d) { break; } return false; } } while (j < n) { char c = u[j ++]; if (c != '\n' && c != '\r') { return false; } } return true; } return false; } public static String lineSeparatorRegex() { return lineSeparatorRegex; } public static List<Integer> lineNumbers(final String s, final int offset, final int length) { int limit = offset + length; checkState(offset >= 0 && length >= 0 && limit <= s.length()); List<Integer> lines = Lists.newArrayList(); int line = 0; for (int i = 0; i < limit; i ++) { char c = s.charAt(i); if (i >= offset) { lines.add(line); } if (c == '\n') { line ++; } else if (c == '\r') { line ++; int k = i + 1; if (k < limit && s.charAt(k) == '\n') { i = k; } lines.add(line); } } return lines; } public static List<String> lines(final String s) { return Splitter.onPattern(lineSeparatorRegex).splitToList(s); } public static String trim(final String s, final String v) { return trimTrailing(trimLeading(s, v), v); } public static String trimLeading(final String s, final String v) { if (s.startsWith(v)) { return s.substring(v.length()); } return s; } public static String trimTrailing(final String s, final String v) { if (s.endsWith(v)) { return s.substring(0, s.length() - v.length()); } return s; } public static String firstNonNullOrEmpty(@Nullable final String first, @Nullable final String second) { return !isNullOrEmpty(first) ? first : checkNotNullOrEmpty(second); } public static boolean isWhitespace(final String s) { int length = s.length(); for (int i = 0; i < length; i ++) { if (!Character.isWhitespace(s.charAt(i))) { return false; } } return true; } private enum IsNullOrEmptyPredicate implements Predicate<String> { INSTANCE; public boolean apply(final String s) { return isNullOrEmpty(s); } } public static Predicate<String> isNullOrEmptyPredicate() { return IsNullOrEmptyPredicate.INSTANCE; } private enum IsWhitespacePredicate implements Predicate<String> { INSTANCE; public boolean apply(@Nonnull final String s) { return isWhitespace(s); } } public static Predicate<String> isWhitespacePredicate() { return IsWhitespacePredicate.INSTANCE; } public static String toDefaultString(final Object o) { return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); } public static String toCanonicalString(final Object o) { String name = o.getClass().getCanonicalName(); if (name == null) { return null; } return name + "@" + Integer.toHexString(o.hashCode()); } public static String toImplementedString(final Object o) { String result = o.toString(); if (toDefaultString(o).equals(result)) { return null; } return result; } public static String toStringOrNull(@Nullable final Object o) { return o != null ? o.toString() : null; } private enum ToStringComparator implements Comparator<Object> { INSTANCE; public int compare(final Object a, final Object b) { return a.toString().compareTo(b.toString()); } } private static final class ToStringComparatorWithLocale<T> implements Comparator<T>, Serializable { private static final long serialVersionUID = 0L; private final Locale locale; ToStringComparatorWithLocale(final Locale locale) { this.locale = checkNotNull(locale); } Collator collator() { return Collator.getInstance(this.locale); } public final int compare(final T a, final T b) { return this.collator().compare(a.toString(), b.toString()); } } public static <T> Comparator<T> toStringComparator() { @SuppressWarnings("unchecked") Comparator<T> comparator = (Comparator<T>) ToStringComparator.INSTANCE; return comparator; } public static <T> Comparator<T> toStringComparator(final Locale locale) { return new ToStringComparatorWithLocale<>(locale); } public static String toStringFallback(final Object o) { String result = toImplementedString(o); if (result != null) { return result; } result = toCanonicalString(o); if (result == null) { return result; } return toDefaultString(o); } public static <T> Function<T, String> toStringFunction() { @SuppressWarnings("unchecked") Function<T, String> result = (Function<T, String>) Functions.toStringFunction(); return result; } public static String toLowerCase(@Nullable final Object o) { return valueOf(o).toLowerCase(); } public static String toLowerCase(@Nullable final Object o, final Locale locale) { return valueOf(o).toLowerCase(locale); } public static String toLowerCaseFirst(@Nullable final Object o) { return toLowerCaseFirst(valueOf(o)); } public static String toLowerCaseFirst(@Nullable final Object o, final Locale locale) { return toLowerCaseFirst(valueOf(o), locale); } public static String toLowerCaseFirst(final String s) { return Character.toLowerCase(s.charAt(0)) + s.substring(1); } public static String toLowerCaseFirst(final String s, final Locale locale) { return s.toLowerCase(locale).charAt(0) + s.substring(1); } public static String toUpperCase(@Nullable final Object o) { return valueOf(o).toUpperCase(); } public static String toUpperCase(@Nullable final Object o, final Locale locale) { return valueOf(o).toUpperCase(locale); } public static String toUpperCaseFirst(@Nullable final Object o) { return toUpperCaseFirst(valueOf(o)); } public static String toUpperCaseFirst(@Nullable final Object o, final Locale locale) { return toUpperCaseFirst(valueOf(o), locale); } public static String toUpperCaseFirst(final String s) { return Character.toUpperCase(s.charAt(0)) + s.substring(1); } public static String toUpperCaseFirst(final String s, final Locale locale) { return s.toUpperCase(locale).charAt(0) + s.substring(1); } private enum ToLowerCaseFunction implements Function<Object, String> { INSTANCE; public String apply(@Nullable final Object o) { return String.valueOf(o).toLowerCase(); } } private static final class ToLowerCaseFunctionWithLocale<T> implements Function<T, String>, Serializable { private static final long serialVersionUID = 0L; private final Locale locale; ToLowerCaseFunctionWithLocale(final Locale locale) { this.locale = checkNotNull(locale); } public String apply(@Nullable final Object o) { return valueOf(o).toLowerCase(this.locale); } } private enum ToUpperCaseFunction implements Function<Object, String> { INSTANCE; public String apply(@Nullable final Object o) { return String.valueOf(o).toUpperCase(); } } private static final class ToUpperCaseFunctionWithLocale<T> implements Function<T, String>, Serializable { private static final long serialVersionUID = 0L; private final Locale locale; ToUpperCaseFunctionWithLocale(final Locale locale) { this.locale = checkNotNull(locale); } public String apply(@Nullable final Object o) { return valueOf(o).toUpperCase(this.locale); } } public static <T> Function<T, String> toLowerCaseFunction() { @SuppressWarnings("unchecked") Function<T, String> result = (Function<T, String>) ToLowerCaseFunction.INSTANCE; return result; } public static <T> Function<T, String> toLowerCaseFunction(final Locale locale) { return new ToLowerCaseFunctionWithLocale<>(locale); } public static <T> Function<T, String> toUpperCaseFunction() { @SuppressWarnings("unchecked") Function<T, String> result = (Function<T, String>) ToUpperCaseFunction.INSTANCE; return result; } public static <T> Function<T, String> toUpperCaseFunction(final Locale locale) { return new ToUpperCaseFunctionWithLocale<>(locale); } }