【需求设计】小写数字金额转换成中文大写金额
amount2cn 设计文档小写数字金额 → 中文大写金额转换.原文参考:https://blog.csdn.net/liudglink/article/details/106820490本文件为设计说明,代码实现请访问 gitee仓库[零]用法与整体流水线多文件程序(同属package main),无外部依赖,由go.mod管理,直接运行:go run *.go1234.56# 命令行模式:逐个参数转换后打印go run *.go# 无参数:跑 main 中内置的自测用例DEBUG_MAT1go run *.go1234.56# 打印 materialize 的下标序列到 stderrgo run *.go-d1234.56# 同上,-d 可出现在参数列表任意位置对外唯一入口arabToChinese(string) string,内部是严格单向流水线:步骤函数职责STEP-1trimCaspAll清洗:去掉空格 / Tab / 千分位逗号STEP-2isZeroYuan零值字面量快捷返回(“零圆整”)STEP-3parseAmountDFA 校验与切分;失败则直接返回msgCodes[EC_MINUS_POS~EC_TOO_LONG]STEP-4convertIntPart/convertDecPart只产出[]int下标序列,不拼字符串STEP-5materialize下标 → 字符串,全文件唯一的字符输出口非法输入返回以[ERR]开头的中文提示串,调用方可用strings.HasPrefix(out, [ERR])判定转换失败.设计上解析与转换两阶段解耦:DFA 阶段只负责格式合法性校验与切分 负号 / 整数部分 / 小数部分,不关心具体的中文怎么写;返回码 0 成功,1~5 为错误.转换阶段只做纯数值 → 中文的映射,无状态机,易单测,易维护.核心改造点(详见 [三]):所有输出字符集中在digits/units/aux三张map[int]string中(键空间互不重叠;另有第四张msgCodes为返回码表,不参与字符输出),转换逻辑只向[]int下标序列 append 下标,materialize()统一把下标映射回字符并应用壹拾简写规则,实现字符定义与逻辑彻底解耦.[一]DFA(确定性有限状态机)形式化设计1. 状态集合 QQ { BEGIN, MINUS, ZEROPRE, INTEGER, ERROR }状态含义BEGIN起始态MINUS已读负号-(仅在开头合法)ZEROPRE前缀零模式(0.xx或-0.xx),用于禁止0XXX这类前置零INTEGER整数数字状态(进入后允许任意 0-9 连续)ERROR拒绝态(对应返回码EC_MINUS_POS~EC_TOO_LONG)实现说明:ERROR只是形式化描述----代码从不转移进ERROR,一旦判定非法就立即return,故state枚举里的errState从未被赋值(死常量,保留仅为与状态图对齐,见 [五]).2. 字母表 ΣΣ { -, ., 0, D(1-9), OTHER } D 1..9,OTHER 其他任意字符(非法)3. 状态转移函数 δ(current × input → next)当前\输入-.01-9OTHERBEGINMINUS无整数①ZEROPREINTEGERERROR(4)MINUSERR(1)无整数②ZEROPREINTEGERERROR(4)ZEROPREERR(1)切小数③ERROR(3)INTEGERERROR(4)INTEGERERR(1)切小数③INTEGERINTEGERERROR(4)①BEGIN遇.合法,表示无整数部分(如.19)②MINUS遇.合法,表示无整数部分(如-.12)③.最多出现一次,第二次出现 →ERROR(2)实现说明:两个与状态图不完全对应的细节----.之后状态一律置为INTEGER,等价于BEGIN/MINUS/ZEROPRE/INTEGER四态在此合并,因为后续只需靠seenDot决定数字写进哪个缓冲区;小数点重复并非由状态机发现,而是parseAmount开头用dotCount预检拦截(码 2),所以转移表里那格实际不会走到.4. 初态 / 终态(接受态)/ 拒绝态初态:BEGIN接受态:BEGIN, MINUS, ZEROPRE, INTEGER代码在扫描结束后并不校验终态,故这四个态全部算合法,包括一个数字都没有的BEGIN与MINUS.退化输入(空串,-等)即由此产生,实际输出见 [四].拒绝态:ERROR(判定即立即返回,不参与终态校验)5. 返回码体系(parseResult.ErrCode / msgCodes 键)代码中应统一使用a2c_tables.go中定义的EC_*具名常量,避免裸写魔法数字。码常量名含义0EC_OK成功(此时直接返回转换结果,不会去查msgCodes,故msgCodes[EC_OK]虽定义为却从未被读取,见 [五])1EC_MINUS_POS负号-位置错误(不在开头)2EC_DOT_MULTI小数点.出现多次3EC_LEAD_ZERO前置零违规(如0XXX,仅允许0.xx/-0.xx)4EC_BAD_CHAR非法字符(非 0-9 /-/.)5EC_TOO_LONG数值过大,整数部分位数超过units表支持的最大权位(见 [四])成功用EC_OK(0) 表示,非 0 即错误;错误提示串集中存于msgCodes[EC_MINUS_POS~EC_TOO_LONG].6. DFA 状态转移图(flowchart)- (仅开头). (无整数①)01-9OTHER. (无整数②)01-9- / OTHER. (切小数③)1-90 (EC_LEAD_ZERO:前置零)- / OTHER0 / 1-9 (自循环)- / OTHER判定即 return,返回 msgCodes[EC_MINUS_POS~EC_TOO_LONG]BEGIN(起始态)MINUS(已读负号)ZEROPRE(前缀零模式)INTEGER(整数数字态)ERROR(拒绝态,EC_MINUS_POS~EC_TOO_LONG)(终止)注:.之后状态统一置为INTEGER(四态合并),依靠seenDot决定数字写入整数还是小数缓冲区;小数点重复由parseAmount开头dotCount预检拦截(码 2),故转移表中.重复的情形实际不会走到.其它非法输入(负号不在开头 / 小数点多次 / 非法字符)→ERROR(码 1 / 2 / 4)7. 合法串示例1001000088080.01 -0.20 .19 -.12 80,493,071,641,101.12 (逗号在 DFA 之前由 trimCaspAll 清洗掉)[二]转换阶段(纯映射,无状态机)负号→ 序列头部插入 “负”;不影响后续任何数值规则.整数部分(convertIntPart):从左到右(高位 → 低位)逐位处理.w n - i 剩余长度(含当前位),即原文 C 实现的CU_INT[w]索引.权位单位取units[UNIT_BASE w]:w%4 1→ 级末单位:w1圆 /5萬 /9億 /13兆 /17京 /21垓 /25秭 …其余 → 拾 / 佰 / 仟(分别对应w%4 2 / 3 / 0)数字非零:先结算待补的 “零”(见下),再输出 数字 该位权位单位---- 注意非零位的单位是无条件输出的,不论它是 拾/佰/仟 还是 圆/萬/億.数字为零:a) 若其右侧(即更低位,下标i1 .. n-1)仍存在非零数字 → 置zeroPending,等遇到下一个非零数字时先补一个 “零”;连续多个零因此只会补出一个 “零”.b) 若该位恰是级末单位位(w%4 1):w 1→ 永远输出 “圆”;否则 → 仅当本级 4 位(下标i-3 .. i,左端截断到 0)非全零时才输出级单位;本级全零则不输出该级单位.例:1000000000→ 拾億圆整.億位(i1)本身是0,但本级实际只有 2 位 “10”,非全零,故仍输出 “億”.例:100000001→ 壹億零壹圆整.萬级 4 位全零,故 “萬” 不出现.边界:整数位数n maxUnitWidth()(即超过units表当前支持的最大权位,由maxUnitWidth()动态计算,当前为 24 垓仟级)时由parseAmount直接返回错误码EC_TOO_LONG,不再静默降级,见 [四].小数部分(convertDecPart):处理 角(第 1 位)/ 分(第 2 位)/ 厘(第 3 位)/ 毫(第 4 位)/ 丝(第 5 位)/ 忽(第 6 位)六级.角或分为 0 时该位整位跳过(.20→ 贰角;.02→ 贰分).六位皆 0(无小数,或.00/.000000)→ 返回nil,由调用方补 “整”.第 6 位后由parseAmount直接丢弃,不做四舍五入(见 [四]).整数与小数之间的 “零”:整数部分有效(即intPart非空且非0),且小数以0开头(角0)时,在圆后补一个 “零” 再接小数:1.01 → 壹圆零壹分; 10.05 → 拾圆零伍分若整数部分为空或0,则既不输出 “圆”,也不补这个 “零”,直接接角分:.01 → 壹分; 0.5 → 伍角; .19 → 壹角玖分; -0.20 → 负贰角(注意:补零条件的判据是整数部分有效,不是输入以 0 开头.)[三]字符表集中管理 下标序列统一输出(核心改造)所有可能的输出字符都集中在三张map[int]string,键一律是基址 偏移,三个键空间互不重叠,故materialize可按键精确查表:表基址键空间值digitsDIGIT_BASE00~9零~玖(偏移 d 即阿拉伯数字值本身)unitsUNIT_BASE100101~(随表扩展)圆/拾/佰/仟/萬/億/兆/京/垓/拾/佰/仟/拾/佰/仟/秭 …auxAUX_BASE200200~207负/整/角/分/厘/毫/丝/忽units表的键空间上界由maxUnitWidth()动态决定,随表中权位条目的增减自动变化;当前最大键为UNIT_BASE 25(对应 “秭” 级).整数最大可表示位数即等于maxUnitWidth()的返回值.digits基址取 0,是因为它排在最前,不可能与他表冲突,偏移直接用阿拉伯数字值,于是digits[d]里的d既是数字值也是表键.既然如此,为什么还要显式定义DIGIT_BASE?一是让三表结构对称,一眼看出键空间;二是把键空间判定收敛成具名谓词(见下);三是万一将来调整基址,所有DIGIT_BASE d的写法不会静默失效.另有一张不参与字符输出的码表:msgCodes:返回码表,键 1~5 为五类错误提示串(键 0 虽定义为但从未被读取).语义常量(避免魔法数字,均指向上述表的固定键):IDX_LING DIGIT_BASE0 (零) IDX_YI DIGIT_BASE1 (壹) IDX_YUAN UNIT_BASE1 (圆) IDX_FU / IDX_ZHENG / IDX_JIAO / IDX_FEN / IDX_LI / IDX_HAO / IDX_SI / IDX_HU AUX_BASE0/1/2/3/4/5/6/7“零” 在三处作补零下标(整数补零,圆后补零,零圆整),故与 “壹” 一样提升为常量,不再裸写 0.注:“拾” 没有独立常量----它在units中随w%42重复出现(拾/拾萬/拾億…),因此由materialize以units[key] 拾动态判定,而不是固定下标.键空间谓词(键空间判定的唯一出处,与三表基址绑定):isDigitKey(idx)idx ∈ [DIGIT_BASE, DIGIT_BASE10)→ 是数字位isLevelUnit(key)key ≥ UNIT_BASE且(key-UNIT_BASE)%4 1→ 是节单位maxUnitWidth()遍历units表,返回当前支持的最大权位w(整数最大可表示位数)转换逻辑(convertIntPart/convertDecPart)不直接拼接字符串,而是向一个[]int下标序列 append:数字位 →digits的键(DIGIT_BASE d;固定数字用IDX_LING/IDX_YI)权位单位 →units的键(UNIT_BASE w)辅助符 → 语义常量IDX_FU/ZHENG/JIAO/FEN/LI/HAO/SI/HU指向的固定键materialize(idxs []int) string是全文件唯一的下标 → 字符出口,内部三步:定位最高位数字firstDigit(供情形B 判定);扫一遍标记skipSet(壹拾简写,见下);按skipSet过滤后依次查digits → units → aux拼接.三表都未命中的越界下标直接跳过(不 panic,也不输出占位符).整体O(n):步骤② 每个位置只向前看 1~2 个元素.debugMat为真时,额外把idxs完整打到stderr 供校验:逐元素打印下标值与字符,被跳过的元素追加-- SKIPPED.壹拾简写规则(业务取舍,并非通行财务规范;在 materialize 中实施)当 数字壹(IDX_YI)紧邻后接 单位拾 时,满足下列任一情形则跳过壹(即 “壹拾” → “拾”):情形A:“拾” 之后紧跟节单位(圆/萬/億/兆/京/垓,即w%41)或已到序列末尾.1000000000 → 拾億圆整; 100000 → 拾萬圆整; 10 → 拾圆整情形B:“壹” 是序列中最高位(第一个)数字,且该 “拾” 属个级.代码判据写作w ≤ 4;但既然该单位必须是 “拾”(w%42),候选w只有2/6/10/14/18,故实际恒等于w 2,即个级的拾位.12.10 → 拾贰圆壹角; 15 → 拾伍圆整反之保留 “壹”:若 “拾” 之后是普通数字位,且 “壹” 并非最高位数字----160000 → 壹拾陸萬圆整(不可写成 陸萬)若要恢复全式 “壹拾”,只需去掉materialize中skipSet的置位逻辑,其余代码(字符表,下标序列)无需改动.这样做的好处:字符定义与转换逻辑彻底解耦,改字形/改措辞只动表;逻辑分支里只出现下标,可读性高,易审计,无魔法数字;统一出口,便于后续做去重,插值,调试打印下标等.[四]边界与退化行为(以下均为实测确认的输出)零值→ “零圆整”(带负号时前缀 “负”),有两条互不相同的到达路径:a)isZeroYuan字面量命中(在 DFA 之前,对清洗后整串做等值匹配):0 / 0. / 0.0 / 0.00 / . / .0 / .00b) 整数部分为空或0,且角分全为 0----走的是整数与小数都产出空序列的分支,例如0.000(它并不在清单 a 里).退化输入(DFA 接受,但一个数字也没有): → 零圆整 - / -0 / -. / -0.00 → 负零圆整(负号照常前置)超长(直接报错):整数位数n maxUnitWidth()(即超过units表当前支持的最大权位,当前为 24 垓仟级)时,parseAmount在扫描结束后立即返回错误码EC_TOO_LONG,由msgCodes[5]给出中文提示,不再静默降级为零值:12345678901234567890123456 → [ERR]数值过大,整数部分超出可表示的最大位数(units最大权位以上)(小数位则无此限制:最多收 6 位 角/分/厘/毫/丝/忽,超出截断,不四舍五入.)小数截断:第 6 位起由parseAmount直接丢弃,不做四舍五入----1234.567→ 壹仟贰佰叁拾肆圆伍角陸分柒厘.前置零:00,0012→ 错误码EC_LEAD_ZERO(只有0.xx/-0.xx允许).[五]已知取舍 / 待办(动手改代码前请先读这一节)“壹拾” → “拾” 属本地业务取舍,不是通行财务大写规范(见 [三]).errState常量从未被赋值----ERROR态在代码里以立即 return 表达.msgCodes[0]从未被读取----成功路径直接返回转换结果,不查表,该条目保留仅为让码表自洽.整数最大可表示位数由units表规模动态决定(见maxUnitWidth()),向units表新增权位条目后无需改动任何数字判断逻辑,超长上限自动跟随扩展.

相关新闻

Spring Boot 3 + Vue 3 全栈博客论坛系统:从零构建毕业设计与实战项目

Spring Boot 3 + Vue 3 全栈博客论坛系统:从零构建毕业设计与实战项目

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/14 3:45:25 阅读更多 →
英华学堂、仓辉实训、海琪科技等衍生平台刷课解决方案

英华学堂、仓辉实训、海琪科技等衍生平台刷课解决方案

一、平台简介 入口如下: MOOC网课管理平台 MOOC网课管理平台是一个集自动化学习、一站式管理和数据可视化于一体的在线教学管理工具。无论你是教师还是学生,这个平台都能帮助你更高效地完成课程管理与学习任务。 二、账号注册与登录 2.1 注册账号 如…

2026/10/25 3:14:51 阅读更多 →
Qt6桌面滚动字幕开发实战:从置顶窗口到动画绘制的完整指南

Qt6桌面滚动字幕开发实战:从置顶窗口到动画绘制的完整指南

简介:这是一款面向直播运营、门店展示及个人效率提升场景的Windows桌面滚动字幕工具Pro版,专为非专业开发者设计,兼顾易用性与深度自定义能力。它解决的是信息高频重复播报却难以被观众/访客有效接收的痛点,通过浮动置顶、不抢占焦…

2026/10/31 6:40:46 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/13 5:13:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/13 5:13:25 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/13 5:13:25 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/13 5:13:25 阅读更多 →

日新闻

周新闻

月新闻