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 similarityRatioList(Collection sources, String target) { return similarityRatioList(sources, target, true); } /** * 批量相似度比较字符串,返回相似度比较列表倒叙结果,较为相似的排最前 * * @param sources 需比较的字符串列表 * @param target 被比较的字符串 * @param isIgnoreCase true 为忽略大小写 * @return 比较结果列表 */ public static LinkedHashMap similarityRatioList(Collection sources, String target, boolean isIgnoreCase) { Map 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); } }