
cn.micro.core.util.StringUtil Maven / Gradle / Ivy
package cn.micro.core.util;
import cn.micro.core.constant.Cants;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 继承自Spring util的工具类,减少jar依赖
*/
public class StringUtil extends StringUtils {
/**
* 特殊字符正则,sql特殊字符和空白符
*/
private static final Pattern SPECIAL_CHARS_REGEX = Pattern.compile("[`'\"|/,;()-+*%#·•� \\s]");
/**
* The maximum size to which the padding constant(s) can expand.
*/
private static final int PAD_LIMIT = 8192;
/**
* 首字母变小写
*
* @param str 字符串
* @return {String}
*/
public static String firstCharToLower(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'A' && firstChar <= 'Z') {
char[] arr = str.toCharArray();
arr[0] += ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* 首字母变大写
*
* @param str 字符串
* @return {String}
*/
public static String firstCharToUpper(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'a' && firstChar <= 'z') {
char[] arr = str.toCharArray();
arr[0] -= ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* Check whether the given {@code CharSequence} contains actual text.
* More specifically, this method returns {@code true} if the
* {@code CharSequence} is not {@code null}, its length is greater than
* 0, and it contains at least one non-whitespace character.
*
* StringUtil.isBlank(null) = true
* StringUtil.isBlank("") = true
* StringUtil.isBlank(" ") = true
* StringUtil.isBlank("12345") = false
* StringUtil.isBlank(" 12345 ") = false
*
*
* @param cs the {@code CharSequence} to check (may be {@code null})
* @return {@code true} if the {@code CharSequence} is not {@code null},
* its length is greater than 0, and it does not contain whitespace only
* @see Character#isWhitespace
*/
public static boolean isBlank(@Nullable final CharSequence cs) {
return !StringUtils.hasText(cs);
}
/**
* Checks if a CharSequence is not empty (""), not null and not whitespace only.
*
* StringUtil.isNotBlank(null) = false
* StringUtil.isNotBlank("") = false
* StringUtil.isNotBlank(" ") = false
* StringUtil.isNotBlank("bob") = true
* StringUtil.isNotBlank(" bob ") = true
*
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is
* not empty and not null and not whitespace
* @see Character#isWhitespace
*/
public static boolean isNotBlank(@Nullable final CharSequence cs) {
return StringUtils.hasText(cs);
}
/**
* 有 任意 一个 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isAnyBlank(final CharSequence... css) {
if (ObjectUtils.isEmpty(css)) {
return true;
}
return Stream.of(css).anyMatch(StringUtil::isBlank);
}
/**
* 有 任意 一个 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isAnyBlank(Collection css) {
if (CollectionUtils.isEmpty(css)) {
return true;
}
return css.stream().anyMatch(StringUtil::isBlank);
}
/**
* 是否全非 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isNoneBlank(final CharSequence... css) {
if (ObjectUtils.isEmpty(css)) {
return false;
}
return Stream.of(css).allMatch(StringUtil::isNotBlank);
}
/**
* 是否全非 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isNoneBlank(Collection css) {
if (CollectionUtils.isEmpty(css)) {
return false;
}
return css.stream().allMatch(StringUtil::isNotBlank);
}
/**
* 有 任意 一个 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isAnyNotBlank(CharSequence... css) {
if (ObjectUtils.isEmpty(css)) {
return false;
}
return Stream.of(css).anyMatch(StringUtil::isNotBlank);
}
/**
* 有 任意 一个 Blank
*
* @param css CharSequence
* @return boolean
*/
public static boolean isAnyNotBlank(Collection css) {
if (CollectionUtils.isEmpty(css)) {
return false;
}
return css.stream().anyMatch(StringUtil::isNotBlank);
}
/**
* 判断一个字符串是否是数字
*
* @param cs the CharSequence to check, may be null
* @return {boolean}
*/
public static boolean isNumeric(final CharSequence cs) {
if (StringUtil.isBlank(cs)) {
return false;
}
for (int i = cs.length(); --i >= 0; ) {
int chr = cs.charAt(i);
if (chr < 48 || chr > 57) {
return false;
}
}
return true;
}
/**
* startWith char
*
* @param cs CharSequence
* @param c char
* @return {boolean}
*/
public static boolean startWith(CharSequence cs, char c) {
return cs.charAt(0) == c;
}
/**
* endWith char
*
* @param cs CharSequence
* @param c char
* @return {boolean}
*/
public static boolean endWith(CharSequence cs, char c) {
return cs.charAt(cs.length() - 1) == c;
}
/**
* 提取字符串中指定的key值
*
* use: formatKeys("my name is ${name}, and i like ${like}!")
*
* @param message 需要转换的字符串
* @return keys 去重
*/
public static List formatKeys(@Nullable String message) {
List keys = new ArrayList<>();
// message 为 null 返回空字符串
if (message == null) {
return Collections.emptyList();
}
// 提取变量
int cursor = 0;
for (int start, end; (start = message.indexOf("${", cursor)) != -1 && (end = message.indexOf("}", start)) != -1; ) {
String key = message.substring(start + 2, end);
keys.add(key);
cursor = end + 1;
}
return keys.stream().distinct().collect(Collectors.toList());
}
/**
* 将字符串中特定模式的字符转换成map中对应的值
*
* use: format("my name is ${name}, and i like ${like}!", {"name":"L.cm", "like": "Java"})
*
* @param message 需要转换的字符串
* @param params 转换所需的键值对集合
* @return 转换后的字符串
*/
public static String format(@Nullable String message, @Nullable Map params) {
// message 为 null 返回空字符串
if (message == null) {
return Cants.STRING_EMPTY;
}
// 参数为 null 或者为空
if (params == null || params.isEmpty()) {
return message;
}
// 替换变量
StringBuilder sb = new StringBuilder((int) (message.length() * 1.5));
int cursor = 0;
for (int start, end; (start = message.indexOf("${", cursor)) != -1 && (end = message.indexOf("}", start)) != -1; ) {
sb.append(message, cursor, start);
String key = message.substring(start + 2, end);
Object value = params.get(StringUtils.trimWhitespace(key));
sb.append(value == null ? Cants.STRING_EMPTY : value);
cursor = end + 1;
}
sb.append(message.substring(cursor));
return sb.toString();
}
/**
* 同 log 格式的 format 规则
*
* use: format("my name is {}, and i like {}!", "L.cm", "Java")
*
* @param message 需要转换的字符串
* @param arguments 需要替换的变量
* @return 转换后的字符串
*/
public static String format(@Nullable String message, @Nullable Object... arguments) {
// message 为 null 返回空字符串
if (message == null) {
return Cants.STRING_EMPTY;
}
// 参数为 null 或者为空
if (arguments == null || arguments.length == 0) {
return message;
}
StringBuilder sb = new StringBuilder((int) (message.length() * 1.5));
int cursor = 0;
int index = 0;
int argsLength = arguments.length;
for (int start, end; (start = message.indexOf("{", cursor)) != -1 && (end = message.indexOf("}", start)) != -1 && index < argsLength; ) {
sb.append(message, cursor, start);
sb.append(arguments[index]);
cursor = end + 1;
index++;
}
sb.append(message.substring(cursor));
return sb.toString();
}
/**
* 格式化执行时间,单位为 ms 和 s,保留三位小数
*
* @param nanos 纳秒
* @return 格式化后的时间
*/
public static String format(long nanos) {
if (nanos < 1) {
return "0ms";
}
double millis = (double) nanos / (1000 * 1000);
// 不够 1 ms,最小单位为 ms
if (millis > 1000) {
return String.format("%.3fs", millis / 1000);
} else {
return String.format("%.3fms", millis);
}
}
/**
* Convert a {@code Collection} into a delimited {@code String} (e.g., CSV).
*
Useful for {@code toString()} implementations.
*
* @param coll the {@code Collection} to convert
* @return the delimited {@code String}
*/
public static String join(Collection> coll) {
return StringUtils.collectionToCommaDelimitedString(coll);
}
/**
* Convert a {@code Collection} into a delimited {@code String} (e.g. CSV).
*
Useful for {@code toString()} implementations.
*
* @param coll the {@code Collection} to convert
* @param delim the delimiter to use (typically a ",")
* @return the delimited {@code String}
*/
public static String join(Collection> coll, String delim) {
return StringUtils.collectionToDelimitedString(coll, delim);
}
/**
* Convert a {@code String} array into a comma delimited {@code String}
* (i.e., CSV).
*
Useful for {@code toString()} implementations.
*
* @param arr the array to display
* @return the delimited {@code String}
*/
public static String join(Object[] arr) {
return StringUtils.arrayToCommaDelimitedString(arr);
}
/**
* Convert a {@code String} array into a delimited {@code String} (e.g. CSV).
*
Useful for {@code toString()} implementations.
*
* @param arr the array to display
* @param delim the delimiter to use (typically a ",")
* @return the delimited {@code String}
*/
public static String join(Object[] arr, String delim) {
return StringUtils.arrayToDelimitedString(arr, delim);
}
/**
* 分割 字符串
*
* @param str 字符串
* @param delimiter 分割符
* @return 字符串数组
*/
public static String[] split(@Nullable String str, @Nullable String delimiter) {
return StringUtils.delimitedListToStringArray(str, delimiter);
}
/**
* 分割 字符串 删除常见 空白符
*
* @param str 字符串
* @param delimiter 分割符
* @return 字符串数组
*/
public static String[] splitTrim(@Nullable String str, @Nullable String delimiter) {
return StringUtils.delimitedListToStringArray(str, delimiter, " \t\n\n\f");
}
/**
* 字符串是否符合指定的 表达式
*
*
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
*
*
* @param pattern 表达式
* @param str 字符串
* @return 是否匹配
*/
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
return PatternMatchUtils.simpleMatch(pattern, str);
}
/**
* 字符串是否符合指定的 表达式
*
*
* pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
*
*
* @param patterns 表达式 数组
* @param str 字符串
* @return 是否匹配
*/
public static boolean simpleMatch(@Nullable String[] patterns, String str) {
return PatternMatchUtils.simpleMatch(patterns, str);
}
/**
* 清理字符串,清理出某些不可见字符和一些sql特殊字符
*
* @param txt 文本
* @return {String}
*/
@Nullable
public static String cleanText(@Nullable String txt) {
if (txt == null) {
return null;
}
return SPECIAL_CHARS_REGEX.matcher(txt).replaceAll(Cants.STRING_EMPTY);
}
/**
* 获取标识符,用于参数清理
*
* @param param 参数
* @return 清理后的标识符
*/
@Nullable
public static String cleanIdentifier(@Nullable String param) {
if (param == null) {
return null;
}
StringBuilder paramBuilder = new StringBuilder();
for (int i = 0; i < param.length(); i++) {
char c = param.charAt(i);
if (Character.isJavaIdentifierPart(c)) {
paramBuilder.append(c);
}
}
return paramBuilder.toString();
}
/**
* 参考自 commons lang 微调
*
* Returns padding using the specified delimiter repeated
* to a given length.
*
*
* StringUtils.repeat('e', 0) = ""
* StringUtils.repeat('e', 3) = "eee"
* StringUtils.repeat('e', -2) = ""
*
*
* Note: this method does not support padding with
* Unicode Supplementary Characters
* as they require a pair of {@code char}s to be represented.
*
*
* @param ch character to repeat
* @param repeat number of times to repeat char, negative treated as zero
* @return String with repeated character
*/
public static String repeat(final char ch, final int repeat) {
if (repeat <= 0) {
return Cants.STRING_EMPTY;
}
final char[] buf = new char[repeat];
Arrays.fill(buf, ch);
return new String(buf);
}
/**
* 参考自 commons lang 微调
*
* Gets the leftmost {@code len} characters of a String.
*
* If {@code len} characters are not available, or the
* String is {@code null}, the String will be returned without
* an exception. An empty String is returned if len is negative.
*
*
* StringUtils.left(null, *) = null
* StringUtils.left(*, -ve) = ""
* StringUtils.left("", *) = ""
* StringUtils.left("abc", 0) = ""
* StringUtils.left("abc", 2) = "ab"
* StringUtils.left("abc", 4) = "abc"
*
*
* @param str the CharSequence to get the leftmost characters from, may be null
* @param len the length of the required String
* @return the leftmost characters, {@code null} if null String input
*/
@Nullable
public static String left(@Nullable final String str, final int len) {
if (str == null) {
return null;
}
if (len < 0) {
return Cants.STRING_EMPTY;
}
if (str.length() <= len) {
return str;
}
return str.substring(0, len);
}
/**
* 参考自 commons lang 微调
*
* Gets the rightmost {@code len} characters of a String.
*
* If {@code len} characters are not available, or the String
* is {@code null}, the String will be returned without an
* an exception. An empty String is returned if len is negative.
*
*
* StringUtils.right(null, *) = null
* StringUtils.right(*, -ve) = ""
* StringUtils.right("", *) = ""
* StringUtils.right("abc", 0) = ""
* StringUtils.right("abc", 2) = "bc"
* StringUtils.right("abc", 4) = "abc"
*
*
* @param str the String to get the rightmost characters from, may be null
* @param len the length of the required String
* @return the rightmost characters, {@code null} if null String input
*/
@Nullable
public static String right(@Nullable final String str, final int len) {
if (str == null) {
return null;
}
if (len < 0) {
return Cants.STRING_EMPTY;
}
int length = str.length();
if (length <= len) {
return str;
}
return str.substring(length - len);
}
/**
* 参考自 commons lang 微调
*
* Right pad a String with spaces (' ').
*
* The String is padded to the size of {@code size}.
*
*
* StringUtils.rightPad(null, *) = null
* StringUtils.rightPad("", 3) = " "
* StringUtils.rightPad("bat", 3) = "bat"
* StringUtils.rightPad("bat", 5) = "bat "
* StringUtils.rightPad("bat", 1) = "bat"
* StringUtils.rightPad("bat", -1) = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @return right padded String or original String if no padding is necessary,
* {@code null} if null String input
*/
@Nullable
public static String rightPad(@Nullable final String str, final int size) {
return rightPad(str, size, Cants.SPACE);
}
/**
* 参考自 commons lang 微调
*
* Right pad a String with a specified character.
*
* The String is padded to the size of {@code size}.
*
*
* StringUtils.rightPad(null, *, *) = null
* StringUtils.rightPad("", 3, 'z') = "zzz"
* StringUtils.rightPad("bat", 3, 'z') = "bat"
* StringUtils.rightPad("bat", 5, 'z') = "batzz"
* StringUtils.rightPad("bat", 1, 'z') = "bat"
* StringUtils.rightPad("bat", -1, 'z') = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padChar the character to pad with
* @return right padded String or original String if no padding is necessary,
* {@code null} if null String input
*/
@Nullable
public static String rightPad(@Nullable final String str, final int size, final char padChar) {
if (str == null) {
return null;
}
final int pads = size - str.length();
if (pads <= 0) {
// returns original String when possible
return str;
}
if (pads > PAD_LIMIT) {
return rightPad(str, size, String.valueOf(padChar));
}
return str.concat(repeat(padChar, pads));
}
/**
* 参考自 commons lang 微调
*
* Right pad a String with a specified String.
*
* The String is padded to the size of {@code size}.
*
*
* StringUtils.rightPad(null, *, *) = null
* StringUtils.rightPad("", 3, "z") = "zzz"
* StringUtils.rightPad("bat", 3, "yz") = "bat"
* StringUtils.rightPad("bat", 5, "yz") = "batyz"
* StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
* StringUtils.rightPad("bat", 1, "yz") = "bat"
* StringUtils.rightPad("bat", -1, "yz") = "bat"
* StringUtils.rightPad("bat", 5, null) = "bat "
* StringUtils.rightPad("bat", 5, "") = "bat "
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padStr the String to pad with, null or empty treated as single space
* @return right padded String or original String if no padding is necessary,
* {@code null} if null String input
*/
@Nullable
public static String rightPad(@Nullable final String str, final int size, String padStr) {
if (str == null) {
return null;
}
if (!StringUtils.hasLength(padStr)) {
padStr = Cants.SPACE;
}
final int padLen = padStr.length();
final int strLen = str.length();
final int pads = size - strLen;
if (pads <= 0) {
// returns original String when possible
return str;
}
if (padLen == 1 && pads <= PAD_LIMIT) {
return rightPad(str, size, padStr.charAt(0));
}
if (pads == padLen) {
return str.concat(padStr);
} else if (pads < padLen) {
return str.concat(padStr.substring(0, pads));
} else {
final char[] padding = new char[pads];
final char[] padChars = padStr.toCharArray();
for (int i = 0; i < pads; i++) {
padding[i] = padChars[i % padLen];
}
return str.concat(new String(padding));
}
}
/**
* 参考自 commons lang 微调
*
* Left pad a String with spaces (' ').
*
* The String is padded to the size of {@code size}.
*
*
* StringUtils.leftPad(null, *) = null
* StringUtils.leftPad("", 3) = " "
* StringUtils.leftPad("bat", 3) = "bat"
* StringUtils.leftPad("bat", 5) = " bat"
* StringUtils.leftPad("bat", 1) = "bat"
* StringUtils.leftPad("bat", -1) = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @return left padded String or original String if no padding is necessary,
* {@code null} if null String input
*/
@Nullable
public static String leftPad(@Nullable final String str, final int size) {
return leftPad(str, size, Cants.SPACE);
}
/**
* 参考自 commons lang 微调
*
* Left pad a String with a specified character.
*
* Pad to a size of {@code size}.
*
*
* StringUtils.leftPad(null, *, *) = null
* StringUtils.leftPad("", 3, 'z') = "zzz"
* StringUtils.leftPad("bat", 3, 'z') = "bat"
* StringUtils.leftPad("bat", 5, 'z') = "zzbat"
* StringUtils.leftPad("bat", 1, 'z') = "bat"
* StringUtils.leftPad("bat", -1, 'z') = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padChar the character to pad with
* @return left padded String or original String if no padding is necessary,
* {@code null} if null String input
* @since 2.0
*/
@Nullable
public static String leftPad(@Nullable final String str, final int size, final char padChar) {
if (str == null) {
return null;
}
final int pads = size - str.length();
if (pads <= 0) {
// returns original String when possible
return str;
}
if (pads > PAD_LIMIT) {
return leftPad(str, size, String.valueOf(padChar));
}
return repeat(padChar, pads).concat(str);
}
/**
* 参考自 commons lang 微调
*
* Left pad a String with a specified String.
*
* Pad to a size of {@code size}.
*
*
* StringUtils.leftPad(null, *, *) = null
* StringUtils.leftPad("", 3, "z") = "zzz"
* StringUtils.leftPad("bat", 3, "yz") = "bat"
* StringUtils.leftPad("bat", 5, "yz") = "yzbat"
* StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
* StringUtils.leftPad("bat", 1, "yz") = "bat"
* StringUtils.leftPad("bat", -1, "yz") = "bat"
* StringUtils.leftPad("bat", 5, null) = " bat"
* StringUtils.leftPad("bat", 5, "") = " bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padStr the String to pad with, null or empty treated as single space
* @return left padded String or original String if no padding is necessary,
* {@code null} if null String input
*/
@Nullable
public static String leftPad(@Nullable final String str, final int size, String padStr) {
if (str == null) {
return null;
}
if (!StringUtils.hasLength(padStr)) {
padStr = Cants.SPACE;
}
final int padLen = padStr.length();
final int strLen = str.length();
final int pads = size - strLen;
if (pads <= 0) {
// returns original String when possible
return str;
}
if (padLen == 1 && pads <= PAD_LIMIT) {
return leftPad(str, size, padStr.charAt(0));
}
if (pads == padLen) {
return padStr.concat(str);
} else if (pads < padLen) {
return padStr.substring(0, pads).concat(str);
} else {
final char[] padding = new char[pads];
final char[] padChars = padStr.toCharArray();
for (int i = 0; i < pads; i++) {
padding[i] = padChars[i % padLen];
}
return new String(padding).concat(str);
}
}
/**
* 参考自 commons lang 微调
*
* Gets {@code len} characters from the middle of a String.
*
* If {@code len} characters are not available, the remainder
* of the String will be returned without an exception. If the
* String is {@code null}, {@code null} will be returned.
* An empty String is returned if len is negative or exceeds the
* length of {@code str}.
*
*
* StringUtils.mid(null, *, *) = null
* StringUtils.mid(*, *, -ve) = ""
* StringUtils.mid("", 0, *) = ""
* StringUtils.mid("abc", 0, 2) = "ab"
* StringUtils.mid("abc", 0, 4) = "abc"
* StringUtils.mid("abc", 2, 4) = "c"
* StringUtils.mid("abc", 4, 2) = ""
* StringUtils.mid("abc", -2, 2) = "ab"
*
*
* @param str the String to get the characters from, may be null
* @param pos the position to start from, negative treated as zero
* @param len the length of the required String
* @return the middle characters, {@code null} if null String input
*/
@Nullable
public static String mid(@Nullable final String str, int pos, final int len) {
if (str == null) {
return null;
}
int length = str.length();
if (len < 0 || pos > length) {
return Cants.STRING_EMPTY;
}
if (pos < 0) {
pos = 0;
}
if (length <= pos + len) {
return str.substring(pos);
}
return str.substring(pos, pos + len);
}
/**
* 判断是否 http 地址
*
* @param text 文本
* @return 是否 http 地址
*/
public static boolean isHttpUrl(String text) {
return text.startsWith("http://") || text.startsWith("https://");
}
}