Files
timi-utils/src/main/java/com/imyeyu/utils/Text.java
T
2026-07-21 14:34:51 +08:00

439 lines
11 KiB
Java

package com.imyeyu.utils;
import com.imyeyu.java.TimiJava;
import java.security.SecureRandom;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author 夜雨
* @version 2023-08-07 11:58
*/
public class Text {
public static String LETTER_POOL = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String NUMBER_POOL = "0123456789";
public static String LETTER_NUMBER_POOL = LETTER_POOL + NUMBER_POOL;
public static String PASSWORD_CHAR_POOL = LETTER_NUMBER_POOL + "!@#$%^&*-_=+[]{}|;:./?";
/** 十六进制小写 */
public static char[] HEX_DIGITS_LOWER = (NUMBER_POOL + "abcdef").toCharArray();
/**
* 是否为半角字符
*
* @param c 字符
* @return 为 true 是表示是半角字符
*/
public static boolean isHalfChar(char c) {
return (int) c < 129;
}
/**
* 字符串加双引号
*
* @param text 字符串内容
* @return 结果
*/
public static String quote(String text) {
return '"' + text + '"';
}
/**
* 前补零(最终长度 2 字符)
*
* @param number 数值
* @return 补零字符串
*/
public static String zero(Number number) {
return zero(2, number);
}
public static String paddedSpaceStart(String str, int totalWidth) {
return String.format("%" + totalWidth + "s", str);
}
public static String paddedSpaceEnd(String str, int totalWidth) {
return String.format("%-" + totalWidth + "s", str);
}
/**
* 前补零
*
* @param l 最终长度
* @param number 数值
* @return 补零字符串
*/
public static String zero(int l, Number number) {
return String.format("%0" + l + "d", number);
}
/**
* 与多个字符串进行与比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时全部其他字符串和比较字符串一致
*/
public static boolean eqAnd(String string, String... other) {
for (String s : other) {
if (!string.equals(s)) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行或比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时其他字符串存在和比较字符串一致
*/
public static boolean eqOr(String string, String... other) {
for (String s : other) {
if (!string.equals(s)) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行忽略大小写的与比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时全部其他字符串和比较字符串一致
*/
public static boolean eqIgnoreCaseAnd(String string, String... other) {
for (String s : other) {
if (!string.equalsIgnoreCase(s)) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行忽略大小写的或比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时其他字符串存在和比较字符串一致
*/
public static boolean eqIgnoreCaseOr(String string, String... other) {
for (String s : other) {
if (string.equalsIgnoreCase(s)) {
return true;
}
}
return false;
}
/**
* 与多个字符串进行忽略大小写包含关系
*
* @param string 原字符串
* @param other 其他字符串
* @return true 为 string 中至少含有一个 other 的忽略大小写的字符段
*/
public static boolean containsIgnoreCase(String string, String... other) {
String stringUpper = string.toUpperCase();
String stringLower = string.toLowerCase();
for (String s : other) {
if (stringLower.contains(s.toLowerCase()) || stringUpper.contains(s.toUpperCase())) {
return true;
}
}
return false;
}
public static String randomString(int length) {
return randomString(LETTER_NUMBER_POOL, length);
}
public static String randomString(String pool, int length) {
SecureRandom r = new SecureRandom();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(pool.charAt(r.nextInt(pool.length())));
}
return sb.toString();
}
public static String randomPassword(int length) {
if (length < 6 || 32 < length) {
throw new IllegalArgumentException("Password length must be between 6 and 32");
}
SecureRandom r = new SecureRandom();
char[] chars = new char[length];
chars[0] = LETTER_POOL.charAt(r.nextInt(LETTER_POOL.length()));
chars[1] = NUMBER_POOL.charAt(r.nextInt(NUMBER_POOL.length()));
for (int i = 2; i < length; i++) {
chars[i] = PASSWORD_CHAR_POOL.charAt(r.nextInt(PASSWORD_CHAR_POOL.length()));
}
for (int i = chars.length - 1; 0 < i; i--) {
int j = r.nextInt(i + 1);
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
return new String(chars);
}
/**
* 较短的临时 UUID,如果使用在庞大的数据里,很可能会发生重复
*
* @return 完整 UUID 前 8 位
*/
public static String tempUUID() {
return UUID.randomUUID().toString().substring(0, 8);
}
/**
* 计算字符串相似度(编辑距离算法)
*
* @param source 需比较的字符串
* @param target 被比较的字符串
* @param isIgnore 为 true 时忽略大小写
* @return 相似度 [0, 1]
*/
private static float levenshteinDistance(String source, String target, boolean isIgnore) {
int[][] d;
int n = source.length(), m = target.length(), i, j, temp;
char charS, charT;
if (n == 0) {
return m;
}
if (m == 0) {
return n;
}
d = new int[n + 1][m + 1];
for (i = 0; i <= n; i++) {
d[i][0] = i;
}
for (j = 0; j <= m; j++) {
d[0][j] = j;
}
for (i = 1; i <= n; i++) {
charS = source.charAt(i - 1);
for (j = 1; j <= m; j++) {
charT = target.charAt(j - 1);
if (isIgnore) {
if (charS == charT || charS == charT + 32 || charS + 32 == charT) {
temp = 0;
} else {
temp = 1;
}
} else {
if (charS == charT) {
temp = 0;
} else {
temp = 1;
}
}
d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
}
}
return d[n][m];
}
/**
* 三数求最小
*
* @param one 值一
* @param two 值二
* @param three 值三
* @return 最小值
*/
public static int min(int one, int two, int three) {
return (one = Math.min(one, two)) < three ? one : three;
}
/**
* 批量相似度比较字符串(忽略大小写),返回相似度比较列表倒叙结果,较为相似的排最前
*
* @param sources 需比较的字符串列表
* @param target 被比较的字符串
* @return 比较结果列表
*/
public static LinkedHashMap<String, Number> similarityRatioList(Collection<String> sources, String target) {
return similarityRatioList(sources, target, true);
}
/**
* 批量相似度比较字符串,返回相似度比较列表倒叙结果,较为相似的排最前
*
* @param sources 需比较的字符串列表
* @param target 被比较的字符串
* @param isIgnoreCase true 为忽略大小写
* @return 比较结果列表
*/
public static LinkedHashMap<String, Number> similarityRatioList(Collection<String> sources, String target, boolean isIgnoreCase) {
Map<String, Number> items = new HashMap<>();
for (String source : sources) {
items.put(source, 0);
}
items.replaceAll((k, v) -> similarityRatio(k, target, isIgnoreCase));
return Collect.sortMapByNumberValueDESC(items);
}
/**
* 求字符串相似度,忽略大小写
*
* @param source 需比较的字符串
* @param target 被比较的字符串
* @return 相似度 [0, 1]
*/
public static float similarityRatio(String source, String target) {
return similarityRatio(source, target, true);
}
/**
* 求字符串相似度
*
* @param source 需比较的字符串
* @param target 被比较的字符串
* @param isIgnoreCase true 为忽略大小写
* @return 相似度 [0, 1]
*/
public static float similarityRatio(String source, String target, boolean isIgnoreCase) {
float ret;
final int max = Math.max(source.length(), target.length());
if (max == 0) {
ret = 1;
} else {
ret = 1 - levenshteinDistance(source, target, isIgnoreCase) / max;
}
return ret;
}
/**
* 检验字符串是否为 json 数据,不校验是否有错误
*
* @param s 字符串
* @return true 为是 JSON 数据
*/
public static boolean isJson(String s) {
return isJsonObject(s) || isJsonArray(s);
}
/**
* 检验字符串是否为 json 对象,不校验是否有错误
*
* @param s 字符串
* @return true 为是 JSON 对象
*/
public static boolean isJsonObject(String s) {
return s.startsWith("{") && s.endsWith("}");
}
/**
* 检验字符串是否为 json 数组,不校验是否有错误
*
* @param s 字符串
* @return true 为是 JSON 数组
*/
public static boolean isJsonArray(String s) {
return s.startsWith("[") && s.endsWith("]");
}
/**
* 字符串替换,不需要正则的情况下
*
* @param string 字符串
* @param from 被替换字符
* @param to 替换字符串
* @return 替换结果
*/
public static String replaceAll(String string, char from, String to) {
return replaceAll(new StringBuilder(string), from, to);
}
/**
* 字符串替换,不需要正则的情况下
*
* @param sb 字符构造器
* @param from 被替换字符
* @param to 替换字符串
* @return 替换结果
*/
public static String replaceAll(StringBuilder sb, char from, String to) {
for (int i = 0; i < sb.length(); i++) {
if (sb.charAt(i) == from) {
sb.replace(i, ++i, to);
}
}
return sb.toString();
}
/**
* 驼峰转下划线
*
* @param camelCaseStr 驼峰字符串
* @return 下划线字符串
*/
public static String camelCase2underscore(String camelCaseStr) {
return camelCaseStr.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
}
/**
* 下划线转驼峰
*
* @param underscoreName 下划线字符串
* @return 驼峰字符串
*/
public static String underscore2camelCase(String underscoreName) {
if (TimiJava.isEmpty(underscoreName)) {
return underscoreName;
}
StringBuilder result = new StringBuilder();
boolean flag = false;
for (int i = 0; i < underscoreName.length(); i++) {
char c = underscoreName.charAt(i);
if ('_' == c) {
flag = true;
} else {
if (flag) {
result.append(Character.toUpperCase(c));
flag = false;
} else {
result.append(c);
}
}
}
return result.toString();
}
/**
* 获取驼峰类名
*
* @param clazz 类
* @return 驼峰类名
*/
public static String camelCaseClassName(Class<?> clazz) {
return Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
}
public static String underscoreClassName(Class<?> clazz) {
return camelCase2underscore(clazz.getSimpleName());
}
public static String bizClassName(Class<?> clazz) {
return underscoreClassName(clazz).toUpperCase();
}
}