404 lines
9.7 KiB
Java
404 lines
9.7 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 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);
|
||
}
|
||
}
|