开发者工具箱-鸿蒙金额转换开发笔记
鸿蒙金额转换开发笔记
前言
最近在搞鸿蒙工具箱,想着加个金额转换功能。说实话,这玩意看着简单,真动手才发现坑一堆。比如把"1234.56"转成"壹仟贰佰叁拾肆元伍角陆分",一开始我还挺自信,结果各种边界情况把我折腾得够呛,调试了好几天才算能用。
写这个工具的时候,真是一路踩坑。金额格式、小数位数、零的处理……每个都能让人头大。好在最后都一一搞定了,现在用起来还挺顺手。
一、功能说明
1.1 主要功能
- 数字转中文大写
- 支持小数
- 一键复制
- 收藏功能
1.2 界面功能
- 金额输入框
- 转换按钮
- 结果显示
- 复制按钮
二、实现过程
2.1 开发小故事
刚开始写的时候,直接网上抄了个转换函数,结果一堆问题。比如输入"1000.00",出来是"壹仟元整",结果被用户吐槽,说应该是"壹仟元零角零分"。我一查,发现不同场景对零的要求还真不一样,有的要显示,有的不要,真是服了。
还有一次,用户说输入"0.1"出来是"壹角",但他想看到"零元壹角"。我又改了好几遍,最后加了个判断,整数部分是0的时候也得显示"零元"。
最离谱的是小数点。一开始没限制小数位数,结果有人输入"123.456",直接给他转成"壹佰贰拾叁元肆角伍分陆厘",用户看了都懵了。后来赶紧加了个限制,只保留两位小数。
2.2 临时解决方案
-
零的处理问题
- 临时方案:直接用正则把连续的零替换成一个零,图省事。
- 问题:有时候把不该替换的零也给干掉了,结果一堆奇怪的结果。
- 最终方案:老老实实用计数器,记录连续零的个数,虽然麻烦点,但靠谱。
-
大数字处理
- 临时方案:字符串拼接,一位一位往后加。
- 问题:慢不说,还容易出错,尤其是十万、百万那种。
- 最终方案:分段处理,每4位一组,效率高多了。
-
小数处理
- 临时方案:直接截两位小数,简单粗暴。
- 问题:有时候精度丢了,用户不乐意。
- 最终方案:先四舍五入再截,体验好多了。
-
前导零处理
- 临时方案:全去掉,结果用户说"00123"应该保留一个零。
- 最终方案:如果全是零就留一个,其他情况去掉。
2.3 调试案例
- 金额格式化
private formatAmount(value: string): string {// 移除非数字和小数点value = value.replace(/[^\d.]/g, '');// 处理多个小数点const parts = value.split('.');if (parts.length > 2) {value = parts[0] + '.' + parts[1];}// 处理小数位数if (parts.length === 2) {parts[1] = parts[1].slice(0, 2);value = parts[0] + (parts[1] ? '.' + parts[1] : '');}// 处理前导零if (parts[0].length > 1 && parts[0].startsWith('0')) {parts[0] = parts[0].replace(/^0+/, '') || '0';value = parts[0] + (parts.length > 1 ? '.' + parts[1] : '');}// 如果只输入了小数点,补充前导零if (value === '.') {value = '0.';}return value;
}
这个格式化函数我真是改了又改。最开始"00123"直接变成"123",结果被怼了,说要保留前导零。后来又加了判断,整数全是0就留一个。
- 金额验证
private validateAmount(amount: string): boolean {this.showError = false;this.errorMessage = '';if (!amount) {this.showError = true;this.errorMessage = '请输入金额';return false;}if (!/^\d+(\.\d{0,2})?$/.test(amount)) {this.showError = true;this.errorMessage = '请输入正确的金额格式';return false;}const num = parseFloat(amount);if (num > this.MAX_AMOUNT) {this.showError = true;this.errorMessage = '金额超出限制';return false;}if (num < this.MIN_AMOUNT) {this.showError = true;this.errorMessage = '金额不能小于0.01';return false;}return true;
}
验证也是一波三折。刚开始只看数字,后来发现有人输负数,赶紧加了正数判断。再后来有人输0,又加了最小值。最后还得防止超大金额,真是防不胜防。
- 转换实现
static numberToChineseMoney(money: string): string {const num = parseFloat(money);if (isNaN(num)) return '金额格式错误';if (num === 0) return '零元整';const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];const cnIntRadice = ['', '拾', '佰', '仟'];const cnIntUnits = ['', '万', '亿', '兆'];const cnDecUnits = ['角', '分'];const parts = money.split('.');let integerPart = parts[0];const decimalPart = parts[1] ? parts[1].substr(0, 2) : '';let chineseStr = '';// 处理整数部分if (parseInt(integerPart) > 0) {let zeroCount = 0;const IntLen = integerPart.length;for (let i = 0; i < IntLen; i++) {const n = parseInt(integerPart.substr(i, 1));const p = IntLen - i - 1;const q = p / 4;const m = p % 4;if (n === 0) {zeroCount++;} else {if (zeroCount > 0) {chineseStr += cnNums[0];}zeroCount = 0;chineseStr += cnNums[n] + cnIntRadice[m];}if (m === 0 && zeroCount < 4) {chineseStr += cnIntUnits[q];}}chineseStr += '元';}// 处理小数部分if (decimalPart) {for (let i = 0; i < decimalPart.length; i++) {const n = parseInt(decimalPart.substr(i, 1));if (n !== 0) {chineseStr += cnNums[n] + cnDecUnits[i];}}}if (!decimalPart) {chineseStr += '整';}return chineseStr;
}
这个转换函数,真是改到怀疑人生。一开始用的算法太简单,遇到大数字直接跪。后来分段处理,零又出问题。现在这版虽然看着乱,但各种奇葩情况都能搞定。
三、踩坑记录
3.1 遇到的问题
-
金额格式问题
- 问题:用户输入不规范,比如多个小数点。
- 解决:加了格式化函数,自动处理。
- 建议:输入时就限制格式,别给自己找麻烦。
-
小数位数问题
- 问题:小数位数不固定。
- 解决:统一保留两位小数。
- 建议:其实可以让用户自定义。
-
零的处理问题
- 问题:连续零的处理不规范。
- 解决:多个零只保留一个。
- 建议:有空可以加个自定义选项。
-
金额范围问题
- 问题:金额超出范围。
- 解决:加了范围限制。
- 建议:可以自定义范围,灵活点。
3.2 优化建议
-
功能优化
- 支持更多金额格式
- 加个历史记录
- 支持批量转换
- 金额分类、导入导出、管理、分享、备份啥的都能加
-
性能优化
- 优化转换速度
- 减少内存占用
- 及时释放资源
- 多线程、算法优化、结果缓存、异步处理都可以试试
-
用户体验
- 加个使用说明
- 支持快捷键
- 动画效果、主题、分享、收藏、导入、备份啥的都能加
四、总结
这个金额转换工具,基本功能都齐了:
- 数字转中文大写
- 支持小数转换
- 一键复制结果
- 收藏常用设置
有些边角问题其实还没完全搞定,不过大部分场景都能用。后面有空再慢慢优化吧。
五、参考资料
- 鸿蒙应用开发指南
欢迎体验
这个金额转换工具已经集成到鸿蒙开发者工具箱里了,欢迎下载体验!
鸿蒙开发者工具箱
作者:在人间耕耘
邮箱:1743914721@qq.com
版权声明:本文为原创文章
如果你也遇到类似问题,欢迎留言交流,搞不定咱们一起头疼