计算工具类

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;

public class CalculatorUtils {
    private final static Logger logger = LoggerFactory.getLogger(CalculatorUtils.class);

    /**
     * 计算
     *
     * @param strA 字符串1
     * @param strB 字符串2
     * @return 相似度
     */
    @Deprecated
    public static double similarDegreeByLongestCommon(String strA, String strB) {
        String newStrA = filterString(strA);
        String newStrB = filterString(strB);
        // 用较大的字符串长度作为分母,相似子串作为分子计算出字串相似度
        int temp = Math.max(newStrA.length(), newStrB.length());
        if (temp == 0) {
            return 0;
        }
        int temp2 = longestCommonSubstring(newStrA, newStrB).length();
        return temp2 * 1.0 / temp;
    }


    /**
     * 过滤非中文和数字
     *
     * @param str 字符串
     * @return 过滤后的数据
     */
    private static String filterString(String str) {
        if (StringUtils.isBlank(str)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (char item : str.toCharArray()) {
            if (!charRegex(item)) {
                continue;
            }
            sb.append(item);
        }
        return sb.toString();
    }


    /**
     * 判断字符是否为汉字,数字和字母(因为对符号进行相似度比较没有实际意义,故符号不加入考虑范围。)
     *
     * @param charValue 字符
     * @return 是否中文或者数组或者英文
     */
    private static boolean charRegex(char charValue) {
        return (charValue >= 0x4E00 && charValue <= 0X9FA5) || (charValue >= 'a' && charValue <= 'z')
                || (charValue >= 'A' && charValue <= 'Z') || (charValue >= '0' && charValue <= '9');
    }

    /**
     * 判断字符是否为字母
     *
     * @param charValue 字符
     * @return 是否字母
     */
    public static boolean charCharacter(char charValue) {
        return (charValue >= 'a' && charValue <= 'z') || (charValue >= 'A' && charValue <= 'Z');
    }

    /**
     * 求公共子串,采用动态规划算法。 其不要求所求得的字符在所给的字符串中是连续的。
     *
     * @param strA 字符串1
     * @param strB 字符串2
     * @return 公共子串
     */
    public static String longestCommonSubstring(String strA, String strB) {
        if (StringUtils.isBlank(strA) || StringUtils.isBlank(strB)) {
            return "";
        }
        char[] charsStrA = strA.toCharArray();
        char[] charsStrB = strB.toCharArray();
        int m = charsStrA.length;
        int n = charsStrB.length;
        /*
         * 初始化矩阵数据,matrix[0][0]的值为0,
         * 如果字符数组charsStrA和charsStrB的对应位相同,则matrix[i][j]的值为左上角的值加1,
         * 否则,matrix[i][j]的值等于左上方最近两个位置的较大值,
         * 矩阵中其余各点的值为0.
         */
        int[][] matrix = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (charsStrA[i - 1] == charsStrB[j - 1]) {
                    matrix[i][j] = matrix[i - 1][j - 1] + 1;
                } else {
                    matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);
                }
            }
        }
        /*
         * 矩阵中,如果matrix[m][n]的值不等于matrix[m-1][n]的值也不等于matrix[m][n-1]的值,
         * 则matrix[m][n]对应的字符为相似字符元,并将其存入result数组中。
         */
        char[] result = new char[matrix[m][n]];
        int currentIndex = result.length - 1;
        while (matrix[m][n] != 0) {
            if (matrix[m][n] == matrix[m][n - 1]) {
                n--;
            } else if (matrix[m][n] == matrix[m - 1][n]) {
                m--;
            } else {
                result[currentIndex] = charsStrA[m - 1];
                currentIndex--;
                n--;
                m--;
            }
        }
        return new String(result);
    }

    /**
     * {similarDegreeByLongestCommon}
     * 先取两个字符串长度的最大值 maxLen,用 1-(需要操作数 除 maxLen),得到相似度。
     * 短距
     * https://www.cnblogs.com/xiaoyulong/p/8846745.html
     * https://blog.youkuaiyun.com/u013035314/article/details/50340443
     *
     * @param strA 字符串1
     * @param strB 字符串2
     * @return Levenshtein Distance
     */
    public static double getStringDistance(String strA, String strB) {
        // 定义距离表
        double[][] distance;
        int s1Len = strA.length();
        int s2Len = strB.length();
        if (s1Len == 0) {
            return s2Len;
        }
        if (s2Len == 0) {
            return s1Len;
        }
        distance = new double[s1Len + 1][s2Len + 1];
        // 二维数组第一行和第一列放置自然数
        for (int i = 0; i <= s1Len; i++) {
            distance[i][0] = i;
        }
        for (int j = 0; j <= s2Len; j++) {
            distance[0][j] = j;
        }
        // 比较,若行列相同,则代价为0,否则代价为1;
        for (int i = 1; i <= s1Len; i++) {
            char s1I = strA.charAt(i - 1);
            // 逐一比较
            for (int j = 1; j <= s2Len; j++) {
                char s2J = strB.charAt(j - 1);
                // 若相等,则代价取0;直接取左上方值
                if (s1I == s2J) {
                    distance[i][j] = distance[i - 1][j - 1];
                } else {
                    // 否则代价取1,取左上角、左、上 最小值 + 代价(代价之和便是最终距离)
                    distance[i][j] = getMin(distance[i - 1][j], distance[i][j - 1], distance[i - 1][j - 1]) + 1;
                }
            }
        }
        // 取二位数组最后一位便是两个字符串之间的距离
        return distance[s1Len][s2Len];
    }


    /**
     * 取最小值
     *
     * @param a 数值1
     * @param b 数值2
     * @param c 数值3
     * @return 最小值
     */
    private static double getMin(double a, double b, double c) {
        double min = a;
        if (b < min) {
            min = b;
        }
        if (c < min) {
            min = c;
        }
        return min;
    }

    /**
     * 效率高点
     * 计算
     *
     * @param strA 字符串1
     * @param strB 字符串2
     * @return 相似度
     */
    public static double similarDegreeByDistance(String strA, String strB) {
        String newStrA = filterString(strA);
        String newStrB = filterString(strB);
        // 用较大的字符串长度作为分母,相似子串作为分子计算出字串相似度
        int temp = Math.max(newStrA.length(), newStrB.length());
        if (temp == 0) {
            return 0;
        }
        double temp2 = getStringDistance(newStrA, newStrB);
        return 1 - (temp2 / temp);
    }


    /**
     * 除法计算   (保留四位小数,四舍五入)
     * @param current
     * @param pre
     * @param <T>
     * @return
     */
    public static  <T extends Number> BigDecimal countDivision(T current, T pre) {
        BigDecimal result = null;
        if (Objects.isNull(current) || Objects.isNull(pre)) {
            return result;
        }
        BigDecimal currentNum = new BigDecimal(current.toString());
        BigDecimal preNum = new BigDecimal(pre.toString());
        if (preNum.compareTo(BigDecimal.ZERO) == 0) {
            return null;
        }
        // 保留四位小数
        result = currentNum.divide(preNum.abs(),4, RoundingMode.HALF_UP);
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子笙—望舒

整理编写不易,希望能支持支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值