标准库不支持中文数字转换,必须手写解析逻辑;整数范围建议控制在int64以内。中文数字需按权位分段计算,“万”“亿”为大权位、“千百十”为小权位,需预定义映射并处理“零”的语义及“十”的位置特例;阿拉伯转中文应四位分组,用strings.Builder高效拼接,并严格校验Unicode字符和边界情况。

直接说结论:标准库不支持中文数字转换,必须手写解析逻辑;整数范围建议控制在 int64 以内,避免溢出和权位错乱。
中文数字转阿拉伯数字:先拆解权位再分段计算
中文数字不是线性映射,而是带权位的组合结构。“一万二千三百四十五”不能逐字查表相加,得识别“万”是大权位(10⁴)、“千/百/十”是小权位(10³/10²/10¹)。
- 预定义两个映射:
ChToArNumberMap(“零”→0,“一”→1…)和chPowerNumMap(“万”→10000,“千”→1000…),注意“万”“亿”只能出现一次,且位置决定分段边界 - 遍历字符串
rune,遇到小权位(十/百/千)就乘当前累积值;遇到大权位(万/亿)就把当前段结果乘权值后累加进总和,并重置段内累积值 - 必须处理“零”的语义:它不参与权位计算,但影响读法(如“一万零五”中“零”不可省略,而“一万千五”非法);实际实现中可跳过“零”,靠上下文判断是否补位
- 常见错误:
"十"单独出现时应为 10,不是 1;"一百"是 100,不是 1×100 + 0×10;需对“十”在首位(如“十二”)和非首位(如“二十”)做不同处理
阿拉伯数字转中文字符串:按四位分组 + 权位模板拼接
中文习惯以“万”“亿”为界分段,每段内部用“千百十”描述。直接从高位到低位硬编码易出错,推荐按 4 位一组切分(对应“个/万/亿/万亿”),每组复用同一套转换逻辑。
- 把
int64转成字符串后,从右向左每 4 位切一刀,得到[]string,例如123456789→["6789", "2345", "1"] - 为每组写一个
toChineseGroup(s string)函数:去掉前导零,逐位查digits表(“零”“一”…),并在非零位后追加“千”“百”“十”,注意“十”在个位数前省略(“十一”不是“一十一”) - 组间插入“万”“亿”:索引 0 是个级,1 是万级,2 是亿级,3 是万亿级;但若某组全为 0,则整个组及其权位都跳过(“10000” → “一万”,不是“一万零千零百零十零”)
- 性能提示:避免在循环里反复
fmt.Sprintf拼接,用strings.Builder累积更高效;strconv.Itoa转每位数字比fmt.Sprintf("%d", d)快 3–5 倍
Unicode 和边界字符必须显式过滤
Go 的 string 是 UTF-8 编码,“一”和“1”(全角)、“−”(U+2212)和“-”(U+002D)在字节层面完全不同。strings.Contains 或简单 == 判断会失败。
立即学习“go语言免费学习笔记(深入)”;
- 输入校验不能只用
strings.TrimSpace:得先用unicode.IsDigit或正则[\u4e00-\u9fff]确认全是中文字符,再查表;否则“123”混入“一”会崩 - 输出时也别假设终端支持中文:如果日志或 HTTP header 需 ASCII 安全,得提前转拼音或 base64,这不是转换逻辑该管的事
- 负数、“零”、“十亿零一”这类特例要单独测:比如
0必须输出“零”,不能空;-123中文无负号概念,应报错或约定前置“负”字(需协议层明确)
JSON 场景下别指望自动转换
前端传 {"amount": "壹佰贰拾叁"},Go 的 json.Unmarshal 不会识别这是中文数字——它只会当普通字符串塞进 string 字段。想兼容,得自己写 UnmarshalJSON 方法。
- 字段声明为
json.RawMessage,延迟解析;或定义自定义类型type ChineseNumber struct{ value int64 },实现UnmarshalJSON先尝试中文转数字,失败再试strconv.ParseInt - 别在
UnmarshalJSON里调fmt或log:线上服务高频调用时,格式化开销明显;错误统一返回fmt.Errorf("invalid chinese number: %q", s)即可 - 如果 API 同时接受
"123"和"壹佰贰拾叁",说明协议已退化为字符串传输,转换逻辑应放在业务层而非 JSON 解析层
最麻烦的其实是“零”的位置判断和跨权位进位,比如“一亿零一”和“一亿一”差一个字,但数值差一亿;手写状态机比堆 if-else 更可靠。上线前务必用含“零”的 100 个随机样例跑一遍,别信直觉。


















