当前位置: 代码网 > it编程>前端脚本>Python > Python实现人民币大写金额转数字和大写规范校验

Python实现人民币大写金额转数字和大写规范校验

2026年07月22日 Python 我要评论
前言在财务系统、发票ocr识别、报销单据解析、合同文本抽取等业务中,经常会遇到中文大写人民币金额:比如“壹拾万零捌佰元整”“负贰亿零伍万元”,业务需要把

前言

在财务系统、发票ocr识别、报销单据解析、合同文本抽取等业务中,经常会遇到中文大写人民币金额:比如“壹拾万零捌佰元整”“负贰亿零伍万元”,业务需要把它转换成可计算的阿拉伯小数用于对账、汇总、统计。

市面上很多简易转换脚本存在大量缺陷:

  1. 无法处理亿、万多级大数,计算逻辑错乱;
  2. 不支持「负、调减」负数场景;
  3. 无法兼容全角字符、圆/元混用、末尾“整”;
  4. 缺少大写合法性校验,脏数据直接转换导致金额错乱;
  5. 不能从长文本中自动截取大写金额片段。

本文提供一套生产级完整代码,包含四大能力:全角转半角、文本抽取大写金额、大写转数字、财务大写规范校验,附带详细原理、坑点说明与测试用例,拿来即可集成到erp、票据识别、python数据分析项目。

一、财务大写基础规范(先懂规则再写代码)

1. 合法字符集

数字:零、壹、贰、叁、肆、伍、陆、柒、捌、玖

单位:拾、佰、仟、万、亿、元(圆)、角、分、整

规范前缀:人民币

2. 硬性书写规则(代码校验逻辑来源)

  1. 标准大写必须以「人民币」开头;
  2. 禁止简体数字(一/二/十)、阿拉伯数字、特殊符号;
  3. 拾位不能单独出现,必须写「壹拾」,禁止“拾元、拾万”;
  4. 不能连续多个零(零零);
  5. 末尾带有「分」时,不能再加「整」;
  6. 金额分为三段:整数元部分、角、分;
  7. 负数业务标识:文本含「负」「调减」代表金额为负。

二、整体架构说明

整套工具拆分为三层,低耦合、易维护:

  1. 预处理层:全角转半角、正则截取文本中的大写金额片段、负数标记识别;
  2. 转换核心层cnmoney_to_num,纯大写字符串转浮点数(单位元),支持亿/万/角/分;
  3. 校验层check_fin_capital,校验大写是否符合财务规范,返回错误原因;
  4. 业务封装入口get_payment_fix,对外统一调用,适配原始长文本输入。

三、完整可运行源码

# -*- coding: utf-8 -*-
# 财务人民币大写金额转换+规范校验完整工具类
import re

# 正则:匹配文本中“大写”到括号的金额片段,用于长文本抽取
re_big_write_content = re.compile('大写[-\d\d]*?)')

def q2b(uchar):
    """单个字符 全角转半角"""
    inside_code = ord(uchar)
    if inside_code == 0x3000:
        inside_code = 0x0020
    else:
        inside_code -= 0xfee0
    if inside_code < 0x0020 or inside_code > 0x7e:
        return uchar
    return chr(inside_code)

def stringq2b(ustring):
    """整段字符串全角转半角,统一文本格式"""
    return "".join([q2b(uchar) for uchar in ustring])

def cnmoney_to_num(cn_str: str) -> float:
    """
    人民币大写转数字小写(单位:元)核心算法
    :param cn_str: 纯财务大写字符串,如 "壹万贰仟叁佰肆拾伍元陆角柒分"
    :return: float 金额(元,保留两位小数)
    """
    digit_map = {
        '零': 0, '壹': 1, '贰': 2, '叁': 3, '肆': 4,
        '伍': 5, '陆': 6, '柒': 7, '捌': 8, '玖': 9
    }
    unit_map = {
        '拾': 10, '佰': 100, '仟': 1000,
        '万': 10000, '亿': 100000000,
        '角': 0.1, '分': 0.01
    }

    # 清理无关字符
    s = cn_str.replace("整", "").replace("圆", "元").strip()
    yuan_part = 0
    jiao_fen = 0.0
    yuan_str = ""

    # 分割整数元 和 角分小数部分
    if "元" in s:
        yuan_str, jf_str = s.split("元", 1)
    else:
        jf_str = s

    # 解析角、分
    jiao = 0
    fen = 0
    if "角" in jf_str:
        jiao_part, fen_part = jf_str.split("角", 1)
        if jiao_part and jiao_part in digit_map:
            jiao = digit_map[jiao_part]
        if "分" in fen_part and fen_part.replace("分", "") in digit_map:
            fen = digit_map[fen_part.replace("分", "")]
    elif "分" in jf_str:
        fen_str = jf_str.replace("分", "")
        if fen_str in digit_map:
            fen = digit_map[fen_str]
    jiao_fen = jiao * 0.1 + fen * 0.01

    # 核心:解析亿、万、仟、佰、拾整数部分
    total = 0
    tmp = 0
    num_buf = none

    for char in yuan_str:
        if char in digit_map:
            num_buf = digit_map[char]
        elif char in unit_map:
            u = unit_map[char]
            if num_buf is not none:
                val = num_buf * u
                # 亿、万属于大单位,需要累加前置临时值
                if u >= 10000:
                    total += (tmp + val)
                    tmp = 0
                else:
                    tmp += val
                num_buf = none
    # 处理末尾无单位数字(例:壹拾万零捌佰,末尾捌佰无后续单位)
    if num_buf is not none:
        tmp += num_buf
    yuan_part = total + tmp

    return round(yuan_part + jiao_fen, 2)

def get_payment_fix(raw_text):
    """
    业务层统一入口:原始长文本抽取大写并转换为金额(支持负数)
    :param raw_text: 原始单据文本,如 "单据大写:负壹万贰仟叁佰肆拾伍元陆角柒分)"
    :return: float 最终金额,负数自动标记
    """
    # 1. 预处理:全角转半角统一格式
    text = stringq2b(raw_text)
    flag = 0
    # 识别负数标识
    if '调减' in text:
        flag = 1
    elif '负' in text:
        flag = 2
    # 正则截取大写片段
    big_match = re_big_write_content.search(text)
    if big_match:
        cn_str = big_match.group(0).replace("大写","").replace(")","").strip()
    else:
        cn_str = text
    # 调用核心转换
    num = cnmoney_to_num(cn_str.replace("圆","元"))
    # 处理负金额
    if flag == 1 or flag == 2:
        num = -num
    return num

# ------------------- 财务大写合法性校验模块 -------------------
# 1. 定义合法大写汉字
valid_chars = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖",
               "拾", "佰", "仟", "万", "亿", "元", "角", "分", "整"}

# 2. 正则匹配标准财务大写完整模板
pattern = re.compile(
    r"^人民币"
    r"(零|壹[拾佰仟万亿]*|贰[拾佰仟万亿]*|叁[拾佰仟万亿]*|肆[拾佰仟万亿]*|伍[拾佰仟万亿]*|陆[拾佰仟万亿]*|柒[拾佰仟万亿]*|捌[拾佰仟万亿]*|玖[拾佰仟万亿]*)*"
    r"(元)?"
    r"(零|壹|贰|叁|肆|伍|陆|柒|捌|玖)角?"
    r"(零|壹|贰|叁|肆|伍|陆|柒|捌|玖)分?"
    r"(整)?$"
)

def check_fin_capital(cap_str: str) -> tuple[bool, str]:
    """
    校验财务大写金额是否规范合规
    :param cap_str: 完整大写字符串,例:人民币壹万贰仟叁佰肆拾伍元陆角柒分
    :return: (是否合法, 错误说明)
    """
    s = cap_str.strip()
    if not s:
        return false, "输入不能为空"

    # 规则1:必须以人民币开头
    if not s.startswith("人民币"):
        return false, "规范大写必须以「人民币」开头"

    # 规则2:过滤非法字符
    char_list = list(s)
    for char in char_list:
        if char not in valid_chars and char not in {"人", "民", "币"}:
            return false, f"包含非法字符:{char},仅允许标准财务大写汉字"

    # 规则3:整体格式正则校验
    if not pattern.match(s):
        return false, "金额格式不符合财务规范,单位语序错误(拾无前壹、单位错乱等)"

    # 规则4:有分不能带整
    if "分" in s and "整" in s:
        return false, "含分位的金额末尾不能添加「整」字"

    # 规则5:拾位前必须带壹,禁止拾元、拾万
    if re.search(r"([零佰仟万亿])拾(元|万|亿)", s):
        pass
    elif re.search(r"^人民币拾", s) or re.search(r"元拾", s) or re.search(r"万拾", s) or re.search(r"亿拾", s):
        return false, "拾位前缺少「壹」,规范应为壹拾元/壹拾万"

    # 规则6:禁止连续多个零
    if "零零" in s:
        return false, "禁止书写连续多个「零」"

    return true, "财务大写格式规范"

# ------------------- 测试入口 -------------------
if __name__ == "__main__":
    print("===== 大写转数字测试 =====")
    print(get_payment_fix("负壹万贰仟叁佰肆拾伍元陆角柒分"))  # -12345.67
    print(get_payment_fix("壹拾万零捌佰元整"))              # 100800.0
    print(get_payment_fix("叁拾元贰角"))                   # 30.2
    print(get_payment_fix("伍分"))                         # 0.05
    print(get_payment_fix("零元捌分"))                     # 0.08
    print(get_payment_fix("贰亿零伍万元整"))               # 200050000.0

    print("\n===== 财务大写规范校验测试 =====")
    test_cases = [
        "人民币壹佰元整",          # 合法
        "人民币壹拾贰元叁角肆分",  # 合法
        "人民币拾元整",            # 非法:缺壹
        "人民币壹佰零拾元整",      # 非法:零拾
        "人民币壹佰元叁角贰分整",  # 非法:有分带整
        "人民币二佰元整",          # 非法:简体二
        "人民币100元整",           # 非法:阿拉伯数字
        "人民币壹万零零伍元整"     # 非法:连续零
    ]
    for case in test_cases:
        res, msg = check_fin_capital(case)
        print(f"{case} → {res} | {msg}")

四、核心模块深度解析

1. 全角转半角函数 q2b / stringq2b

业务场景中ocr识别、扫描件文本经常出现全角汉字、全角空格,会导致匹配、转换失败。原理:

  • 全角字符编码区间 0xff00 ~ 0xff5e,减去偏移 0xfee0 即可转为半角;
  • 全角空格 0x3000 单独映射为半角空格 0x0020
  • 超出半角可视字符范围的字符保持原样,避免破坏原有文本。

2. 大写转数字核心 cnmoney_to_num

分段逻辑

将金额拆分为整数元角、分两部分分别计算,角分直接转为小数(0.1、0.01)。

大数(亿/万)计算逻辑(难点)

普通拾、佰、仟是局部单位,万、亿是分段单位,不能简单顺序相乘:

例:贰亿零伍万元 = 2 * 1亿 + 5 * 1万

代码使用 total 存储亿、万级大数总和,tmp 存储万以内临时数值,遇到亿/万时将临时值合并进总和,清空临时缓存,完美解决多级大数叠加错乱问题。

兼容处理

  • 「圆」自动替换为「元」;
  • 末尾「整」直接剔除;
  • 无元只有角分(伍分、叁角零分)兼容;
  • 末尾无单位数字(壹拾万零捌佰)兜底处理。

3. 业务封装 get_payment_fix

面向业务系统的顶层函数,解决3个工程痛点:

  1. 原始文本长、混杂无关文字,通过正则自动截取「大写xxx)」金额片段;
  2. 识别「负」「调减」两种财务负数场景,自动返回负金额;
  3. 统一预处理全角字符,上层业务无需额外格式化。

4. 财务大写校验 check_fin_capital

生产环境必备防护,防止错误大写流入计算导致对账差错,覆盖6类高频错误:

  1. 缺少「人民币」前缀;
  2. 混入简体数字、阿拉伯数字、特殊符号;
  3. 单位语序错误(拾无前壹、零拾);
  4. 分后加「整」;
  5. 连续多个零;
  6. 空输入拦截。

五、常见业务坑点与解决方案

坑点场景问题现象代码解决方案
文本含全角大写正则匹配失败、转换结果为0前置 stringq2b 统一半角
金额使用「圆」分割元失败,角分丢失replace("圆","元") 兼容
拾元、拾万简写财务不合规,人工篡改风险校验函数拦截,提示缺少壹
亿万多级大数叠加普通顺序算法数值翻倍错乱分层缓存 total + tmp 分段计算
单据标注「调减」需要负金额参与对账业务入口识别flag,结果取反
ocr脏字符、简体字转换抛出异常、金额错误校验模块提前拦截非法字符
有分又带整财务凭证不规范校验规则直接报错

六、落地集成建议

票据ocr场景:ocr返回整张单据文本,直接调用 get_payment_fix 自动抽取并转换金额;转换前可先调用 check_fin_capital 校验大写合法性,非法金额标记异常单据人工复核。

erp财务对账:读取合同、报销单的大写字段,批量转换为数字用于总额核对、差异计算。

数据分析/报表:pandas批量处理文本列,封装apply函数批量转换大写金额:

import pandas as pd
df["数字金额"] = df["原始文本"].apply(get_payment_fix)

接口安全防护:对外提供金额转换接口时,先执行check_fin_capital校验,不合法大写直接返回错误提示,避免脏数据计算异常。

七、扩展优化方向(按需改造)

  1. 增加大写转数字反向函数(数字自动生成标准财务大写);
  2. 支持更高单位(兆),扩展unit_map字典;
  3. 增加金额上下限校验,拦截超大异常金额;
  4. 日志埋点:记录非法大写、负数金额日志,便于财务审计;
  5. 适配pdf解析、excel读取场景,封装工具类。

结语

本文方案区别于网上简易demo,完全贴合财务真实业务,兼顾文本抽取、格式兼容、大数计算、数据校验四大核心需求,代码无第三方依赖,仅使用python内置re正则库,python3.6+均可直接运行,可快速集成到票据识别、财务系统、数据分析各类项目,解决中文大写金额自动化解析痛点。

以上就是python实现人民币大写金额转数字和大写规范校验的详细内容,更多关于python大写金额转数字的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com