Files
timi-utils/src/main/java/com/imyeyu/utils/Text.java
2026-01-13 17:24:20 +08:00

404 lines
9.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 char[] HEX_DIGITS_LOWER = "0123456789abcdef".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 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 string 比较字符串
* @param other 其他字符串
* @return true 时全部其他字符串和比较字符串一致
*/
public static boolean eqAnd(String string, String... other) {
for (int i = 0; i < other.length; i++) {
if (!string.equals(other[i])) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行或比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时其他字符串存在和比较字符串一致
*/
public static boolean eqOr(String string, String... other) {
for (int i = 0; i < other.length; i++) {
if (!string.equals(other[i])) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行忽略大小写的与比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时全部其他字符串和比较字符串一致
*/
public static boolean eqIgnoreCaseAnd(String string, String... other) {
for (int i = 0; i < other.length; i++) {
if (!string.equalsIgnoreCase(other[i])) {
return false;
}
}
return true;
}
/**
* 与多个字符串进行忽略大小写的或比较
*
* @param string 比较字符串
* @param other 其他字符串
* @return true 时其他字符串存在和比较字符串一致
*/
public static boolean eqIgnoreCaseOr(String string, String... other) {
for (int i = 0; i < other.length; i++) {
if (string.equalsIgnoreCase(other[i])) {
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 (int i = 0; i < other.length; i++) {
if (stringLower.contains(other[i].toLowerCase()) || stringUpper.contains(other[i].toUpperCase())) {
return true;
}
}
return false;
}
public static String randomString(int length) {
return randomString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 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() - 1)));
}
return sb.toString();
}
/**
* 较短的临时 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 clazz 类
* @return 驼峰类名
*/
public static String camelCaseClassName(Class<?> clazz) {
return Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
}
}