From 61cfdecaf6b76acb27478e5901eb0908244e3875 Mon Sep 17 00:00:00 2001
From: sinake <sinake1@qq.com>
Date: 星期四, 15 十月 2026 16:36:54 +0800
Subject: [PATCH] 发票识别

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java |  303 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 301 insertions(+), 2 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
index e978d6c..f43a4da 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
@@ -1,6 +1,47 @@
 package com.ruoyi.common.utils;
 
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
 public class ChineseUtils {
+    private static final String[] CN_NUM = {
+            "闆�", "澹�", "璐�", "鍙�", "鑲�", "浼�", "闄�", "鏌�", "鎹�", "鐜�"
+    };
+
+    private static final String[] CN_UNIT = {
+            "", "鎷�", "浣�", "浠�"
+    };
+
+    private static final String[] CN_BIG_UNIT = {
+            "", "涓�", "浜�", "鍏�"
+    };
+    private static final Map<Character, Integer> CN_NUM_MAP = new HashMap<>();
+    private static final Map<Character, Integer> CN_UNIT_MAP = new HashMap<>();
+
+    static {
+        for (int i = 0; i < CN_NUM.length; i++) {
+            CN_NUM_MAP.put(CN_NUM[i].charAt(0), i);
+        }
+        CN_NUM_MAP.put('闆�', 0);
+        CN_NUM_MAP.put('涓�', 1);
+        CN_NUM_MAP.put('浜�', 2);
+        CN_NUM_MAP.put('涓�', 3);
+        CN_NUM_MAP.put('鍥�', 4);
+        CN_NUM_MAP.put('浜�', 5);
+        CN_NUM_MAP.put('鍏�', 6);
+        CN_NUM_MAP.put('涓�', 7);
+        CN_NUM_MAP.put('鍏�', 8);
+        CN_NUM_MAP.put('涔�', 9);
+        CN_NUM_MAP.put('涓�', 2);
+
+        CN_UNIT_MAP.put('鎷�', 10);
+        CN_UNIT_MAP.put('浣�', 100);
+        CN_UNIT_MAP.put('浠�', 1000);
+        CN_UNIT_MAP.put('鍗�', 10);
+        CN_UNIT_MAP.put('鐧�', 100);
+        CN_UNIT_MAP.put('鍗�', 1000);
+    }
 
     /**
      * 鏍¢獙鏄惁鏄腑鏂�
@@ -9,7 +50,265 @@
      * @return
      */
     public static boolean isChinese(String str) {
-        String regex = "[\\u4e00-\\u9fa5]+";
-        return str.matches(regex);
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (isChineseCharacter(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isChineseCharacter(char c) {
+        // 姹夊瓧鐨刄nicode缂栫爜鑼冨洿鏄�0x4E00鍒�0x9FA5
+        return c >= 0x4E00 && c <= 0x9FA5;
+    }
+
+    /**
+     * 鏁板瓧閲戦杞腑鏂囧ぇ鍐�
+     * 渚嬪锛�1234.56 -> 澹逛粺璐颁桨鍙佹嬀鑲嗗厓浼嶈闄嗗垎
+     */
+    public static String numberToChinese(BigDecimal amount) {
+        if (amount == null) {
+            throw new IllegalArgumentException("閲戦涓嶈兘涓虹┖");
+        }
+
+        boolean negative = amount.signum() < 0;
+        amount = amount.abs().setScale(2, BigDecimal.ROUND_HALF_UP);
+
+        long integerPart = amount.longValue();
+        int decimalPart = amount.subtract(new BigDecimal(integerPart))
+                .multiply(new BigDecimal(100))
+                .intValue();
+
+        int jiao = decimalPart / 10;
+        int fen = decimalPart % 10;
+
+        StringBuilder sb = new StringBuilder();
+
+        if (negative) {
+            sb.append("璐�");
+        }
+
+        if (integerPart == 0) {
+            sb.append("闆跺厓");
+        } else {
+            sb.append(integerToChinese(integerPart)).append("鍏�");
+        }
+
+        if (jiao == 0 && fen == 0) {
+            sb.append("鏁�");
+        } else {
+            if (jiao > 0) {
+                sb.append(CN_NUM[jiao]).append("瑙�");
+            } else if (fen > 0 && integerPart > 0) {
+                sb.append("闆�");
+            }
+
+            if (fen > 0) {
+                sb.append(CN_NUM[fen]).append("鍒�");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    public static String numberToChinese(double amount) {
+        return numberToChinese(BigDecimal.valueOf(amount));
+    }
+
+    public static String numberToChinese(String amount) {
+        return numberToChinese(new BigDecimal(amount));
+    }
+
+    /**
+     * 鏁存暟閮ㄥ垎杞腑鏂囧ぇ鍐�
+     */
+    private static String integerToChinese(long num) {
+        if (num == 0) {
+            return "闆�";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        int unitIndex = 0;
+        boolean needZero = false;
+
+        while (num > 0) {
+            int section = (int) (num % 10000);
+            if (section != 0) {
+                String sectionStr = sectionToChinese(section);
+                if (needZero || (section < 1000 && sb.length() > 0)) {
+                    sb.insert(0, "闆�");
+                }
+                sb.insert(0, sectionStr + CN_BIG_UNIT[unitIndex]);
+                needZero = section < 1000;
+            } else {
+                if (sb.length() > 0 && !sb.toString().startsWith("闆�")) {
+                    needZero = true;
+                }
+            }
+            num /= 10000;
+            unitIndex++;
+        }
+
+        String result = sb.toString();
+        result = result.replaceAll("闆�+", "闆�");
+        result = result.replaceAll("闆�$", "");
+        result = result.replaceAll("闆朵竾", "涓�");
+        result = result.replaceAll("闆朵嚎", "浜�");
+        return result;
+    }
+
+    /**
+     * 鍥涗綅浠ュ唴鏁板瓧杞腑鏂�
+     */
+    private static String sectionToChinese(int section) {
+        StringBuilder sb = new StringBuilder();
+        int unit = 1000;
+        boolean zeroFlag = false;
+
+        while (section > 0) {
+            int digit = section / unit;
+            if (digit == 0) {
+                if (sb.length() > 0 && !zeroFlag) {
+                    zeroFlag = true;
+                    sb.append("闆�");
+                }
+            } else {
+                zeroFlag = false;
+                sb.append(CN_NUM[digit]).append(CN_UNIT[getUnitIndex(unit)]);
+            }
+            section %= unit;
+            unit /= 10;
+        }
+
+        String result = sb.toString();
+        if (result.endsWith("闆�")) {
+            result = result.substring(0, result.length() - 1);
+        }
+        return result;
+    }
+
+    private static int getUnitIndex(int unit) {
+        switch (unit) {
+            case 1000: return 3;
+            case 100: return 2;
+            case 10: return 1;
+            default: return 0;
+        }
+    }
+
+    /**
+     * 涓枃澶у啓閲戦杞暟瀛�
+     * 渚嬪锛氬9浠熻窗浣板弫鎷捐倖鍏冧紞瑙掗檰鍒� -> 1234.56
+     */
+    public static BigDecimal chineseToNumber(String chinese) {
+        if (chinese == null || chinese.trim().isEmpty()) {
+            throw new IllegalArgumentException("涓枃閲戦涓嶈兘涓虹┖");
+        }
+
+        String str = chinese.trim()
+                .replace("鏁�", "")
+                .replace("姝�", "")
+                .replace("浜烘皯甯�", "");
+
+        boolean negative = str.startsWith("璐�");
+        if (negative) {
+            str = str.substring(1);
+        }
+
+        // 鍒嗙鍏冦�佽銆佸垎
+        String integerPartStr;
+        String decimalPartStr = "";
+
+        int yuanIndex = str.indexOf("鍏�");
+        if (yuanIndex >= 0) {
+            integerPartStr = str.substring(0, yuanIndex);
+            String rest = str.substring(yuanIndex + 1);
+
+            int jiaoIndex = rest.indexOf("瑙�");
+            int fenIndex = rest.indexOf("鍒�");
+
+            if (jiaoIndex >= 0) {
+                decimalPartStr += chineseDigitToNumber(rest.substring(0, jiaoIndex)) + "";
+            } else if (fenIndex > 0) {
+                decimalPartStr += "0";
+            }
+
+            if (fenIndex >= 0) {
+                String fenStr = rest.substring(jiaoIndex >= 0 ? jiaoIndex + 1 : 0, fenIndex);
+                decimalPartStr += chineseDigitToNumber(fenStr) + "";
+            } else {
+                if (decimalPartStr.length() == 1) {
+                    decimalPartStr += "0";
+                }
+            }
+        } else {
+            // 娌℃湁鈥滃厓鈥濓紝鎸夌函鏁板瓧涓枃澶勭悊
+            integerPartStr = str;
+        }
+
+        long integerPart = chineseIntegerToNumber(integerPartStr);
+
+        if (decimalPartStr.isEmpty()) {
+            decimalPartStr = "00";
+        } else if (decimalPartStr.length() == 1) {
+            decimalPartStr += "0";
+        }
+
+        BigDecimal result = new BigDecimal(integerPart + "." + decimalPartStr);
+        return negative ? result.negate() : result;
+    }
+    /**
+     * 涓枃鏁存暟杞� long
+     */
+    private static long chineseIntegerToNumber(String chinese) {
+        if (chinese == null || chinese.isEmpty() || chinese.equals("闆�")) {
+            return 0;
+        }
+
+        long result = 0;
+        long section = 0;
+        long number = 0;
+
+        for (int i = 0; i < chinese.length(); i++) {
+            char c = chinese.charAt(i);
+
+            if (CN_NUM_MAP.containsKey(c)) {
+                number = CN_NUM_MAP.get(c);
+            } else if (CN_UNIT_MAP.containsKey(c)) {
+                int unit = CN_UNIT_MAP.get(c);
+                if (number == 0) {
+                    number = 1;
+                }
+                section += number * unit;
+                number = 0;
+            } else if (c == '涓�') {
+                section += number;
+                result += section * 10000;
+                section = 0;
+                number = 0;
+            } else if (c == '浜�') {
+                section += number;
+                result += section * 100000000;
+                section = 0;
+                number = 0;
+            } else if (c == '鍏�') {
+                section += number;
+                result += section * 1000000000000L;
+                section = 0;
+                number = 0;
+            }
+        }
+
+        return result + section + number;
+    }
+
+    private static int chineseDigitToNumber(String chinese) {
+        if (chinese == null || chinese.isEmpty()) {
+            return 0;
+        }
+        char c = chinese.charAt(0);
+        return CN_NUM_MAP.getOrDefault(c, 0);
     }
 }

--
Gitblit v1.9.3