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

org.kiwiproject.base.KiwiStrings Maven / Gradle / Ivy

Go to download

Kiwi is a utility library. We really like Google's Guava, and also use Apache Commons. But if they don't have something we need, and we think it is useful, this is where we put it.

There is a newer version: 4.5.2
Show newest version
package org.kiwiproject.base;

import static org.apache.commons.lang3.StringUtils.isBlank;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import lombok.experimental.UtilityClass;

import java.util.List;

/**
 * Utility methods relating to strings or similar.
 */
@UtilityClass
@SuppressWarnings("WeakerAccess")
public final class KiwiStrings {

    /**
     * A space character.
     */
    public static final char SPACE = ' ';

    /**
     * A tab character.
     */
    public static final char TAB = '\t';

    /**
     * A comma character.
     */
    public static final char COMMA = ',';

    /**
     * A newline character.
     */
    public static final char NEWLINE = '\n';

    private static final Splitter TRIMMING_AND_EMPTY_OMITTING_SPACE_SPLITTER =
            Splitter.on(SPACE).omitEmptyStrings().trimResults();

    private static final Splitter TRIMMING_AND_EMPTY_OMITTING_TAB_SPLITTER =
            Splitter.on(TAB).omitEmptyStrings().trimResults();

    private static final Splitter TRIMMING_AND_EMPTY_OMITTING_COMMA_SPLITTER =
            Splitter.on(COMMA).omitEmptyStrings().trimResults();

    private static final Splitter TRIMMING_AND_EMPTY_OMITTING_NEWLINE_SPLITTER =
            Splitter.on(NEWLINE).omitEmptyStrings().trimResults();

    /**
     * Splits the given {@link CharSequence}, using a {@link #SPACE} as the separator character, omitting any empty
     * strings and trimming leading and trailing whitespace.
     *
     * @param sequence the character sequence to be split
     * @return an Iterable over the split strings
     * @see #splitWithTrimAndOmitEmpty(CharSequence, char)
     */
    public static Iterable splitWithTrimAndOmitEmpty(CharSequence sequence) {
        return splitWithTrimAndOmitEmpty(sequence, SPACE);
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator character, omitting any empty
     * strings and trimming leading and trailing whitespace.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator character to use
     * @return an Iterable over the split strings
     */
    public static Iterable splitWithTrimAndOmitEmpty(CharSequence sequence, char separator) {
        switch (separator) {
            case COMMA:
                return TRIMMING_AND_EMPTY_OMITTING_COMMA_SPLITTER.split(sequence);
            case SPACE:
                return TRIMMING_AND_EMPTY_OMITTING_SPACE_SPLITTER.split(sequence);
            case TAB:
                return TRIMMING_AND_EMPTY_OMITTING_TAB_SPLITTER.split(sequence);
            case NEWLINE:
                return TRIMMING_AND_EMPTY_OMITTING_NEWLINE_SPLITTER.split(sequence);
            default:
                return Splitter.on(separator).omitEmptyStrings().trimResults().split(sequence);
        }
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator string, omitting any empty
     * strings and trimming leading and trailing whitespace.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator to use, e.g. {@code ", "}
     * @return an Iterable over the split strings
     */
    public static Iterable splitWithTrimAndOmitEmpty(CharSequence sequence, String separator) {
        return Splitter.on(separator).omitEmptyStrings().trimResults().split(sequence);
    }

    /**
     * Splits the given {@link CharSequence}, using a {@link #SPACE} as the separator character, omitting any empty
     * strings and trimming leading and trailing whitespace. Returns an immutable list.
     *
     * @param sequence the character sequence to be split
     * @return an immutable list containing the split strings
     * @see #splitWithTrimAndOmitEmpty(CharSequence, char)
     */
    public static List splitToList(CharSequence sequence) {
        return splitToList(sequence, SPACE);
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator character, omitting any empty
     * strings and trimming leading and trailing whitespace. Returns an immutable list.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator character to use
     * @return an immutable list containing the split strings
     * @see #splitWithTrimAndOmitEmpty(CharSequence, char)
     */
    public static List splitToList(CharSequence sequence, char separator) {
        switch (separator) {
            case COMMA:
                return TRIMMING_AND_EMPTY_OMITTING_COMMA_SPLITTER.splitToList(sequence);
            case SPACE:
                return TRIMMING_AND_EMPTY_OMITTING_SPACE_SPLITTER.splitToList(sequence);
            case TAB:
                return TRIMMING_AND_EMPTY_OMITTING_TAB_SPLITTER.splitToList(sequence);
            case NEWLINE:
                return TRIMMING_AND_EMPTY_OMITTING_NEWLINE_SPLITTER.splitToList(sequence);
            default:
                return Splitter.on(separator).omitEmptyStrings().trimResults().splitToList(sequence);
        }
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator character, into the maximum number of groups
     * specified omitting any empty strings and trimming leading and trailing whitespace. Returns an
     * immutable list.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator character to use
     * @param maxGroups the maximum number of groups to separate into
     * @return an immutable list containing the split strings
     */
    public static List splitToList(CharSequence sequence, char separator, int maxGroups) {
        return Splitter.on(separator).limit(maxGroups).omitEmptyStrings().trimResults().splitToList(sequence);
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator string, omitting any empty
     * strings and trimming leading and trailing whitespace. Returns an immutable list.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator string to use
     * @return an immutable list containing the split strings
     */
    public static List splitToList(CharSequence sequence, String separator) {
        return Splitter.on(separator).omitEmptyStrings().trimResults().splitToList(sequence);
    }

    /**
     * Splits the given {@link CharSequence}, using the specified separator string, into the maximum number of groups
     * specified omitting any empty strings and trimming leading and trailing whitespace. Returns an
     * immutable list.
     *
     * @param sequence  the character sequence to be split
     * @param separator the separator string to use
     * @param maxGroups the maximum number of groups to separate into
     * @return an immutable list containing the split strings
     */
    public static List splitToList(CharSequence sequence, String separator, int maxGroups) {
        return Splitter.on(separator).limit(maxGroups).omitEmptyStrings().trimResults().splitToList(sequence);
    }

    /**
     * Convenience method that splits the given comma-delimited {@link CharSequence}, omitting any empty strings and
     * trimming leading and trailing whitespace. Returns an immutable list.
     *
     * @param sequence the character sequence to be split
     * @return an immutable list containing the split strings
     * @see #splitWithTrimAndOmitEmpty(CharSequence, char)
     */
    public static List splitOnCommas(CharSequence sequence) {
        return ImmutableList.copyOf(splitWithTrimAndOmitEmpty(sequence, COMMA));
    }

    /**
     * Convenience method that splits the given comma-delimited {@link CharSequence}, omitting any empty strings and
     * trimming leading and trailing whitespace. Returns an immutable list.
     *
     * @param sequence the character sequence to be split, may be null
     * @return an immutable list containing the split strings, or an empty list if {@code sequence} is blank
     * @see #splitWithTrimAndOmitEmpty(CharSequence, char)
     */
    public static List nullSafeSplitOnCommas(CharSequence sequence) {
        if (isBlank(sequence)) {
            return List.of();
        }

        return splitOnCommas(sequence);
    }

    /**
     * Returns a null if the input string is all whitespace characters or null.
     *
     * @param sequence a possibly null, blank, or zero length String.
     * @return null if {@code sequence} is blank, otherwise return {@code sequence}
     */
    public static String blankToNull(String sequence) {
        return isBlank(sequence) ? null : sequence;
    }

    /**
     * Substitutes each {@code %s} or {@code {}} in {@code template} with an argument. These are matched by
     * position: the first {@code %s} (or {@code {}}) gets {@code args[0]}, etc. If there are more arguments than
     * placeholders, the unmatched arguments will be appended to the end of the formatted message in
     * square braces.
     * 

* This method currently accepts either {@code %s} or {@code {}} but not both at * the same time. It won't work if you mix and match them as that is confusing anyway. What will happen * is that only the {@code %s} placeholders will be resolved, and the {@code {}} will appear as a literal {@code {}} * and the resulting message will thus be very difficult to understand, as there will be more arguments than * {@code %s} placeholders. *

* Generally you should pick one style and be consistent throughout your entire application. Since originally this * method only supported the Guava {@code %s}, this support was retained for obvious backward-compatibility reasons, * and the SLF4J {@code {}} style as added because we kept coming across instances where people are used to SLF4J * replacement parameter style and used that, thus making the message not interpolate correctly (though thanks to * Guava's implementation, all the parameter values are still displayed after the message as extra parameters). *

* This method was originally copied directly from Guava 18.0's * {@code com.google.common.base.Preconditions#format(String, Object...)} * because it was not public in Guava, and it is useful and provides better performance than using the * {@link String#format(java.util.Locale, String, Object...)} method. A slight modification we made is to not * re-assign the {@code template} argument. Guava 25.1 moved this very useful functionality into the Guava * {@link com.google.common.base.Strings} class as * {{@link com.google.common.base.Strings#lenientFormat(String, Object...)}}. However, it only accepts {@code %s} * as the replacement placeholder. For performance comparisons of the JDK {@link String#format(String, Object...)} * method, see http://stackoverflow.com/questions/12786902/performance-javas-string-format * * @param template a non-null string containing 0 or more {@code %s} or {@code {}} placeholders. * @param args the arguments to be substituted into the message template. Arguments are converted * to strings using {@link String#valueOf(Object)}. Arguments can be null. * @return the formatted string after making replacements */ public static String format(String template, Object... args) { var nonNullTemplate = String.valueOf(template); // null -> "null" if (nonNullTemplate.contains("%s")) { return formatGuavaStyle(template, args); } return formatSlf4jJStyle(nonNullTemplate, args); } /** * Alias for {@link #format(String, Object...)}. * * @param template a non-null string containing 0 or more {@code %s} or {@code {}} placeholders. * @param args the arguments to be substituted into the message template. Arguments are converted * to strings using {@link String#valueOf(Object)}. Arguments can be null. * @return the formatted string after making replacements */ public static String f(String template, Object... args) { return format(template, args); } /** * Same as {@link #format(String, Object...)} assuming Guava-style placeholders. * * @param template a non-null string containing 0 or more {@code %s} placeholders. * @param args the arguments to be substituted into the message template. Arguments are converted * to strings using {@link String#valueOf(Object)}. Arguments can be null. * @return the formatted string after making replacements * @see #format(String, Object...) */ public static String formatGuavaStyle(String template, Object... args) { return formatInternal(template, "%s", args); } /** * Same as {@link #format(String, Object...)} assuming SLF4J-style placeholders. * * @param template a non-null string containing 0 or more {@code {}} placeholders. * @param args the arguments to be substituted into the message template. Arguments are converted * to strings using {@link String#valueOf(Object)}. Arguments can be null. * @return the formatted string after making replacements * @see #format(String, Object...) */ public static String formatSlf4jJStyle(String template, Object... args) { return formatInternal(template, "{}", args); } /** * This is copied and modified from Guava 18 to accommodate {@code %s} or {@code {}} placeholders. */ private static String formatInternal(String template, String placeholder, Object... args) { var nonNullTemplate = String.valueOf(template); // null -> "null" // start substituting the arguments into the placeholders var builder = new StringBuilder(nonNullTemplate.length() + 16 * args.length); var templateStart = 0; var i = 0; while (i < args.length) { var placeholderStart = nonNullTemplate.indexOf(placeholder, templateStart); if (placeholderStart == -1) { break; } builder.append(nonNullTemplate, templateStart, placeholderStart); builder.append(args[i++]); templateStart = placeholderStart + 2; } builder.append(nonNullTemplate, templateStart, nonNullTemplate.length()); // if we run out of placeholders, append the extra args in square braces if (i < args.length) { builder.append(" ["); builder.append(args[i++]); while (i < args.length) { builder.append(", "); builder.append(args[i++]); } builder.append(']'); } return builder.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy