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

spring.turbo.util.StringUtils Maven / Gradle / Ivy

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *    ____             _            _____           _
 *   / ___| _ __  _ __(_)_ __   __ |_   _|   _ _ __| |__   ___
 *   \___ \| '_ \| '__| | '_ \ / _` || || | | | '__| '_ \ / _ \
 *    ___) | |_) | |  | | | | | (_| || || |_| | |  | |_) | (_) |
 *   |____/| .__/|_|  |_|_| |_|\__, ||_| \__,_|_|  |_.__/ \___/
 *         |_|                 |___/   https://github.com/yingzhuo/spring-turbo
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package spring.turbo.util;

import org.springframework.lang.Nullable;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static spring.turbo.util.StringPool.COMMA;
import static spring.turbo.util.StringPool.EMPTY;

/**
 * {@link String} 相关工具
 *
 * @author 应卓
 * @see RandomStringUtils
 * @since 1.0.0
 */
public final class StringUtils {

    /**
     * 私有构造方法
     */
    private StringUtils() {
        super();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 判断字符串是否为空串
     *
     * @param string 字符串
     * @return 判断结果
     */
    public static boolean isEmpty(@Nullable String string) {
        return string == null || string.isEmpty();
    }

    /**
     * 判断字符串是否不为空串
     *
     * @param string 字符串
     * @return 判断结果
     */
    public static boolean isNotEmpty(@Nullable String string) {
        return !isEmpty(string);
    }

    /**
     * 判断字符串是否为空白串
     *
     * @param string 字符串
     * @return 判断结果
     */
    public static boolean isBlank(@Nullable String string) {
        return string == null || string.isBlank(); // since java 11
    }

    /**
     * 判断字符串是否不为空白串
     *
     * @param string 字符串
     * @return 判断结果
     */
    public static boolean isNotBlank(@Nullable String string) {
        return !isBlank(string);
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 获取字符串的长度
     *
     * @param string 字符串
     * @return 长度
     */
    public static int length(@Nullable final String string) {
        return string == null ? 0 : string.length();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 判断字符串是否包含白字符
     *
     * @param string 字符串
     * @return 判断结果
     */
    public static boolean containsWhitespace(String string) {
        Asserts.notNull(string);

        int strLen = string.length();
        for (int i = 0; i < strLen; i++) {
            if (CharUtils.isWhitespace(string.charAt(i))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断字符串是否包含任意一个指定的字符
     *
     * @param string       字符串
     * @param charsToCheck 需要检查的字符集
     * @return 检测结果
     */
    public static boolean containsAnyChars(String string, String charsToCheck) {
        Asserts.notNull(string);

        final Set charSet = toCharSet(string);
        if (charSet.isEmpty()) {
            return false;
        }
        return toCharStream(charsToCheck).anyMatch(charSet::contains);
    }

    /**
     * 判断字符串是否包含所有的指定的字符
     *
     * @param string       字符串
     * @param charsToCheck 需要检查的字符集
     * @return 检测结果
     */
    public static boolean containsAllChars(String string, String charsToCheck) {
        Asserts.notNull(string);

        final Set charSet = toCharSet(string);
        if (charSet.isEmpty()) {
            return false;
        }
        return toCharStream(charsToCheck).allMatch(charSet::contains);
    }

    /**
     * 判断字符串是否不包含任意一个指定的字符
     *
     * @param string       字符串
     * @param charsToCheck 需要检查的字符集
     * @return 检测结果
     */
    public static boolean containsNoneChars(String string, String charsToCheck) {
        Asserts.notNull(string);

        final Set charSet = toCharSet(string);
        if (charSet.isEmpty()) {
            return true;
        }
        return toCharStream(charsToCheck).noneMatch(charSet::contains);
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 字符出现个数计数
     *
     * @param string 字符串
     * @param ch     要查找的字符
     * @return 结果
     */
    public static int countMatches(String string, char ch) {
        Asserts.notNull(string);
        if (isEmpty(string)) {
            return 0;
        }
        int count = 0;
        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
        for (int i = 0; i < string.length(); i++) {
            if (ch == string.charAt(i)) {
                count++;
            }
        }
        return count;
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 删除白字符
     *
     * @param string 字符串
     * @return 结果
     */
    public static String deleteWhitespace(String string) {
        Asserts.notNull(string);

        if (string.isEmpty()) {
            return string;
        }

        final int sz = string.length();
        final char[] chs = new char[sz];
        int count = 0;
        for (int i = 0; i < sz; i++) {
            if (!Character.isWhitespace(string.charAt(i))) {
                chs[count++] = string.charAt(i);
            }
        }
        if (count == sz) {
            return string;
        }
        if (count == 0) {
            return EMPTY;
        }
        return new String(chs, 0, count);
    }

    /**
     * 删除字符串中的指定字符
     *
     * @param string        字符串
     * @param charsToDelete 待删除的字符集合
     * @return 结果
     */
    public static String deleteChars(String string, String charsToDelete) {
        Asserts.notNull(string);
        if (isEmpty(charsToDelete)) {
            return string;
        }

        final Set charsToDeleteSet = toCharSet(charsToDelete);

        final StringBuilder builder = new StringBuilder();
        toCharList(string).stream().filter(c -> !charsToDeleteSet.contains(c)).forEach(builder::append);
        return builder.toString();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 字符串转换为字符{@link Stream}
     *
     * @param string 字符串
     * @return 实例
     */
    public static Stream toCharStream(@Nullable String string) {
        if (string == null) {
            return Stream.empty();
        }
        return string.chars().mapToObj(ch -> (char) ch);
    }

    /**
     * 字符串转换为字符{@link List}
     *
     * @param string 字符串
     * @return 实例
     */
    public static List toCharList(@Nullable String string) {
        return toCharStream(string).collect(Collectors.toList());
    }

    /**
     * 字符串转换为字符{@link Set}
     *
     * @param string 字符串
     * @return 实例
     */
    public static Set toCharSet(@Nullable String string) {
        return toCharStream(string).collect(Collectors.toSet());
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 字符串逆向
     *
     * @param string 字符串
     * @return 结果
     */
    public static String reverse(String string) {
        Asserts.notNull(string);
        return new StringBuilder(string).reverse().toString();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 逗号分隔字符串转化成字符串数组
     *
     * @param string 逗号分隔的字符串
     * @return 结果
     */
    public static String[] commaDelimitedListToStringArray(@Nullable String string) {
        return commaDelimitedListToStringArray(string, false);
    }

    /**
     * 逗号分隔字符串转化成字符串数组
     *
     * @param string          逗号分隔的字符串
     * @param trimAllElements 是否trim所有的子字符串
     * @return 结果
     */
    public static String[] commaDelimitedListToStringArray(@Nullable String string, boolean trimAllElements) {
        if (string == null || isBlank(string)) {
            return new String[0];
        }

        final String[] array = string.split(COMMA);
        if (trimAllElements) {
            return Arrays.stream(array).map(String::trim).toArray(String[]::new);
        } else {
            return array;
        }
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 首字母大写
     *
     * @param string 字符串
     * @return 结果
     * @see #uncapitalize(String)
     */
    public static String capitalize(final String string) {
        Asserts.notNull(string);

        final int strLen = length(string);
        if (strLen == 0) {
            return string;
        }

        final int firstCodepoint = string.codePointAt(0);
        final int newCodePoint = Character.toTitleCase(firstCodepoint);
        if (firstCodepoint == newCodePoint) {
            // already capitalized
            return string;
        }

        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
        int outOffset = 0;
        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
            final int codepoint = string.codePointAt(inOffset);
            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
            inOffset += Character.charCount(codepoint);
        }
        return new String(newCodePoints, 0, outOffset);
    }

    /**
     * 取消首字母大写
     *
     * @param string 字符串
     * @return 结果
     * @see #capitalize(String)
     */
    public static String uncapitalize(final String string) {
        Asserts.notNull(string);
        final int strLen = length(string);
        if (strLen == 0) {
            return string;
        }

        final int firstCodepoint = string.codePointAt(0);
        final int newCodePoint = Character.toLowerCase(firstCodepoint);
        if (firstCodepoint == newCodePoint) {
            // already capitalized
            return string;
        }

        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
        int outOffset = 0;
        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
            final int codepoint = string.codePointAt(inOffset);
            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
            inOffset += Character.charCount(codepoint);
        }
        return new String(newCodePoints, 0, outOffset);
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 非{@code null} 字符串加入集合
     *
     * @param collection 集合
     * @param element    字符串
     */
    public static void nullSafeAdd(Collection collection, @Nullable String element) {
        CollectionUtils.nullSafeAdd(collection, element);
    }

    /**
     * 非{@code null} 字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void nullSafeAddAll(Collection collection, @Nullable String... elements) {
        CollectionUtils.nullSafeAddAll(collection, elements);
    }

    /**
     * 非{@code null} 字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void nullSafeAddAll(Collection collection, @Nullable Collection elements) {
        CollectionUtils.nullSafeAddAll(collection, elements);
    }

    /**
     * 非空字符串加入集合
     *
     * @param collection 集合
     * @param element    字符串
     */
    public static void emptySafeAdd(Collection collection, @Nullable String element) {
        emptySafeAddAll(collection, element);
    }

    /**
     * 非空字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void emptySafeAddAll(Collection collection, @Nullable String... elements) {
        Asserts.notNull(collection);
        if (elements != null) {
            for (String element : elements) {
                if (isNotEmpty(element)) {
                    collection.add(element);
                }
            }
        }
    }

    /**
     * 非空字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void emptySafeAddAll(Collection collection, @Nullable Collection elements) {
        Asserts.notNull(collection);
        if (elements != null) {
            for (String element : elements) {
                if (isNotEmpty(element)) {
                    collection.add(element);
                }
            }
        }
    }

    /**
     * 非空白字符串加入集合
     *
     * @param collection 集合
     * @param element    字符串
     */
    public static void blankSafeAdd(Collection collection, @Nullable String element) {
        blankSafeAddAll(collection, element);
    }

    /**
     * 非空白字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void blankSafeAddAll(Collection collection, @Nullable String... elements) {
        Asserts.notNull(collection);
        if (elements != null) {
            for (String element : elements) {
                if (isNotBlank(element)) {
                    collection.add(element);
                }
            }
        }
    }

    /**
     * 非空白字符串加入集合
     *
     * @param collection 集合
     * @param elements   字符串(多个)
     */
    public static void blankSafeAddAll(Collection collection, @Nullable Collection elements) {
        Asserts.notNull(collection);
        if (elements != null) {
            for (String element : elements) {
                if (isNotBlank(element)) {
                    collection.add(element);
                }
            }
        }
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 多个元素拼接成一个字符串 (忽略null元素)
     *
     * @param elements  多个元素
     * @param separator 分隔符
     * @return 结果
     */
    public static String nullSafeJoin(@Nullable Iterable elements, @Nullable String separator) {
        if (elements == null) {
            return EMPTY;
        }

        var strJoiner = new StringJoiner(Objects.requireNonNullElse(separator, EMPTY));
        for (var ele : elements) {
            if (ele != null) {
                strJoiner.add(String.valueOf(ele));
            }
        }
        return strJoiner.toString();
    }

    /**
     * 多个元素拼接成一个字符串 (忽略null元素)
     *
     * @param elements  多个元素
     * @param separator 分隔符
     * @return 结果
     */
    public static String nullSafeJoin(@Nullable Iterator elements, @Nullable String separator) {
        if (elements == null) {
            return EMPTY;
        }

        var strJoiner = new StringJoiner(Objects.requireNonNullElse(separator, EMPTY));
        while (elements.hasNext()) {
            var ele = elements.next();
            if (ele != null) {
                strJoiner.add(String.valueOf(ele));
            }
        }
        return strJoiner.toString();
    }

    /**
     * 多个元素拼接成一个字符串 (忽略null元素)
     *
     * @param elements  多个元素
     * @param separator 分隔符
     * @return 结果
     */
    public static String nullSafeJoin(@Nullable Object[] elements, @Nullable String separator) {
        if (elements == null) {
            return EMPTY;
        }

        var strJoiner = new StringJoiner(Objects.requireNonNullElse(separator, EMPTY));
        for (var ele : elements) {
            if (ele != null) {
                strJoiner.add(String.valueOf(ele));
            }
        }
        return strJoiner.toString();
    }

    /**
     * 多个元素拼接成一个字符串 (忽略null元素)
     *
     * @param elements  多个元素
     * @param separator 分隔符
     * @return 结果
     */
    public static String nullSafeJoin(@Nullable String[] elements, @Nullable String separator) {
        if (elements == null) {
            return EMPTY;
        }

        var strJoiner = new StringJoiner(Objects.requireNonNullElse(separator, EMPTY));
        for (var ele : elements) {
            if (ele != null) {
                strJoiner.add(ele);
            }
        }
        return strJoiner.toString();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 判断一个字符串是否有指定的前缀
     *
     * @param string 字符串
     * @param prefix 前缀
     * @return 结果
     */
    public static boolean startsWith(@Nullable String string, String prefix) {
        Asserts.notNull(prefix);
        if (string == null) return false;
        return string.startsWith(prefix);
    }

    /**
     * 判断一个字符串是否有指定的后缀
     *
     * @param string 字符串
     * @param suffix 后缀
     * @return 结果
     */
    public static boolean endsWith(@Nullable String string, String suffix) {
        Asserts.notNull(suffix);
        if (string == null) return false;
        return string.endsWith(suffix);
    }

    /**
     * 判断一个字符串是否有指定的前缀 (大小写不敏感)
     *
     * @param string 字符串
     * @param prefix 前缀
     * @return 结果
     */
    public static boolean startsWithIgnoreCase(@Nullable String string, String prefix) {
        Asserts.notNull(prefix);
        return (string != null && string.length() >= prefix.length() &&
                string.regionMatches(true, 0, prefix, 0, prefix.length()));
    }

    /**
     * 判断一个字符串是否有指定的后缀 (大小写不敏感)
     *
     * @param string 字符串
     * @param suffix 后缀
     * @return 结果
     */
    public static boolean endsWithIgnoreCase(@Nullable String string, String suffix) {
        Asserts.notNull(suffix);
        return (string != null && string.length() >= suffix.length() &&
                string.regionMatches(true, string.length() - suffix.length(), suffix, 0, suffix.length()));
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 重复字符串
     *
     * @param string 字符串
     * @param n      重复的次数
     * @return 结果
     */
    public static String repeat(String string, int n) {
        Asserts.notNull(string);
        Asserts.isTrue(n >= 1);

        if (n == 1) {
            return string;
        }

        StringBuilder builder = new StringBuilder();
        while (n-- != 0) {
            builder.append(string);
        }
        return builder.toString();
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 比较两个字符串
     *
     * @param string1 字符串1
     * @param string2 字符串2
     * @return 结果
     */
    public static int compare(@Nullable String string1, @Nullable String string2) {
        return compare(string1, string2, true);
    }

    /**
     * 比较两个字符串
     *
     * @param string1    字符串1
     * @param string2    字符串2
     * @param nullIsLess 为{@code true}时 {@code null}排在前面
     * @return 结果
     */
    public static int compare(@Nullable String string1, @Nullable String string2, final boolean nullIsLess) {
        if (string1 == string2) {
            return 0;
        }
        if (string1 == null) {
            return nullIsLess ? -1 : 1;
        }
        if (string2 == null) {
            return nullIsLess ? 1 : -1;
        }
        return string1.compareTo(string2);
    }

    /**
     * 比较两个字符串 (大小写不敏感)
     *
     * @param string1 字符串1
     * @param string2 字符串2
     * @return 结果
     */
    public static int compareIgnoreCase(@Nullable String string1, @Nullable String string2) {
        return compareIgnoreCase(string1, string2, true);
    }

    /**
     * 比较两个字符串 (大小写不敏感)
     *
     * @param string1    字符串1
     * @param string2    字符串2
     * @param nullIsLess 为{@code true}时 {@code null}排在前面
     * @return 结果
     */
    public static int compareIgnoreCase(@Nullable String string1, @Nullable String string2, final boolean nullIsLess) {
        if (string1 == string2) {
            return 0;
        }
        if (string1 == null) {
            return nullIsLess ? -1 : 1;
        }
        if (string2 == null) {
            return nullIsLess ? 1 : -1;
        }
        return string1.compareToIgnoreCase(string2);
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 查找第一个非Empty字符串
     *
     * @param strings 字符串组
     * @return 结果或 {@code null}
     */
    @Nullable
    public static String firstNonEmpty(@Nullable String... strings) {
        if (strings != null) {
            for (String val : strings) {
                if (isNotEmpty(val)) {
                    return val;
                }
            }
        }
        return null;
    }

    /**
     * 查找第一个非Blank字符串
     *
     * @param values 字符串组
     * @return 结果或 {@code null}
     */
    @Nullable
    public static String firstNonBlank(@Nullable String... values) {
        if (values != null) {
            for (String val : values) {
                if (isNotBlank(val)) {
                    return val;
                }
            }
        }
        return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy