前面刷过一个题,关于罗马字和阿拉伯数字转换,我之前的文章链接:
https://blog.csdn.net/sleepingboy888/article/details/89814335
最近在看《算法的乐趣》王晓华著,其中的“阿拉伯数字和中文数字”。这篇也是自己学习记录下。
阿拉伯数字转中文数字
具体的思路可以参考书中的段落,文章中只说重点的地方。中文数字中0的表述比较复杂,总结起来为一下三点:

  1. 以 10000 为小节,小节的结尾即使是 0 ,也不使用 “零”。例如:60000,6万
  2. 小节内(一个小节为 4 位数)两个非 0 数字之间要使用“零”。例如:504,五百零四
  3. 当小节的“千”位是 0 时,若本小节的前一小节无其他数字,则不用“零”,否则就要用“零”。50,五十;10050,一万零五十。

如果对这三条规则是否完善存有疑惑,可以在代码写完以后用测试用例来检查。
需要说明的名词:

  1. 节,中文数字一般以4位为一小段,也就是万分位,对应与英文中的千分位。
  2. 权,一节中每一位都有对于的值,例如:1234,1对于的权是1千。
  3. 节权,每一节都有自己的权,最低的4位可以理解为节权位空,例如:163481234,1亿6384万1234。特别说明,代码中节权只识别到万亿。
  4. 位权,每一位数字在一节中的对应的值,分别是:千,百,十,(个位为空)。


比较麻烦的可能是“零”的处理,书中归纳总结的挺好的,我个人稍微变通下。根据日常习惯,其实是阿拉伯数字中连续的零只读一个零。调试代码过程中,个人总结:

  1. 值为零的时候就不需要考虑权,节权和位权都不需要。
  2. 不出现多个“零”连续,有种情况需要特殊考虑,一节的最后几位都是0不需要“零”,例如:100000,一十万
  3. 返回字符串第一个字符和最后一个字符不能为“零”,当然,输入为0直接返回“零”。
 public static string NumberToChinese(uint num){string result = "";if (num == 0){return "零";}uint _num = num;//string[] chn_str = new string[] { "零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};//string[] unit_value = new string[] { "", "拾", "佰", "仟" };string[] chn_str = new string[] { "零","一", "二", "三", "四", "五", "六", "七", "八", "九" };string[] section_value = new string[] { "","万","亿","万亿"};string[] unit_value = new string[] { "", "十", "百", "千" };uint section = _num % 10000;for (int i = 0; _num != 0 && i < 4; i++){if (section == 0){//0不需要考虑节权值,不能出现连续的“零”if (result.Length > 0 && result.Substring(0, 1) != "零"){result = "零" + result;}_num = _num / 10000;section = _num % 10000;continue;}result = section_value[i]+result;uint unit = section % 10;for (int j = 0; j<4 ; j++){if (unit == 0){//0不需要考虑位权值,不能出现联系的“零”,每节最后的0不需要if (result.Length > 0 && result.Substring(0, 1) != "零" && result.Substring(0, 1) != section_value[i]){result = "零" + result;}}else{result = chn_str[unit] + unit_value[j] + result;}section = section / 10;unit = section % 10;}_num = _num / 10000;section = _num % 10000;}if (result.Length > 0 && result.Substring(0, 1) == "零"){//清理最前面的"零"result = result.Substring(1);}return result;}

测试用例代码:

public Dictionary<uint, string> m_dic_test = new Dictionary<uint, string>
{{ 0,"零" },{ 1,"一" },{ 2,"二" },{ 3,"三" },{ 4,"四" },{ 5,"五" },{ 6,"六" },{ 7,"七" },{ 8,"八" },{ 9,"九" },{ 10,"一十" },{ 11,"一十一" },{ 110,"一百一十" },{ 111,"一百一十一" },{ 100,"一百" },{ 102,"一百零二" },{ 1020,"一千零二十" },{ 1001,"一千零一" },{ 1015,"一千零一十五" },{ 1000,"一千" },{ 10000,"一万" },{ 20010,"二万零一十" },{ 20001,"二万零一" },{ 100000,"一十万" },{ 1000000,"一百万" },{ 10000000,"一千万" },{ 100000000,"一亿" },{ 1000000000,"一十亿" },{ 1000001000,"一十亿零一千" },//{ 1000001000,"一十亿一千" },{ 1000000100,"一十亿零一百" },{ 200010,"二十万零一十" },{ 2000105,"二百万零一百零五" },{ 20001007,"二千万一千零七" },{ 2000100190,"二十亿零一十万零一百九十" },{ 1040010000,"一十亿四千零一万" },{ 200012301,"二亿零一万二千三百零一" },{ 2005010010,"二十亿零五百零一万零一十" },{ 4009060200,"四十亿零九百零六万零二百" },{ 4294967295,"四十二亿九千四百九十六万七千二百九十五" }
};[TestMethod]
public void TestNumberToChinese()
{foreach (var item in m_dic_test){Assert.AreEqual(Solutions.NumberToChinese(item.Key), item.Value, "error");}
}

按照我的标准和书中的不太一样,例如:
{ 1000001000,“一十亿一千” }
这个测试用例不能通过,代码解析为:一十亿零一千,我个人感觉这种读法也能接受。这代码不能到万亿,如果需要识别到万亿级,可以把 uint 类型替换掉。

中文数字转阿拉伯数字
这个的思路相对容易一些,主要是分段和分节,需要注意的点:

  • “万亿”的特殊处理,这个是两个字的节权名。
  • “十”,“百”,“千”,和数字成套出现,要么是数字加上这写数,或者数字单独出现(一个节中的最低位)
  • 没有判断输入的字符串是否满足中文数字的表述规则,默认输入的字符串满足规则。
public static UInt64 ChineseToNumber(string chinese_str)
{UInt64 result = 0;Dictionary<string, UInt64> dic_section_number = new Dictionary<string, UInt64> {{ "万",10000 },{ "亿",100000000 },{ "万亿",1000000000000 }};Dictionary<string, UInt64> dic_unit_number = new Dictionary<string, UInt64> {{ "十",10 },{ "百",100 },{ "千",1000 }};Dictionary<string, UInt64> dic_chn_number = new Dictionary<string, UInt64> {{ "零",0}, { "一",1}, { "二",2} ,{ "三",3},{ "四",4},{ "五",5},{ "六",6},{ "七",7},{ "八",8},{ "九",9}};if (chinese_str.Length == 0){return 0;}UInt64 section_value = 0;for (int i = 0; i < chinese_str.Length; i++){string cur_str = chinese_str.Substring(i, 1);if (dic_section_number.ContainsKey(cur_str)){//万亿的特殊处理if (cur_str == "万" && i + 1 < chinese_str.Length && chinese_str.Substring(i + 1, 1) == "亿"){result += section_value * dic_section_number["万亿"];i++;}else{result += section_value * dic_section_number[cur_str];}section_value = 0;}else{if(dic_chn_number.ContainsKey(cur_str)){if (i + 1 < chinese_str.Length && dic_unit_number.ContainsKey(chinese_str.Substring(i + 1, 1))){//和数字一起成对出现的 十,百,千section_value += dic_chn_number[cur_str] * dic_unit_number[chinese_str.Substring(i + 1, 1)];i++;}else{section_value += dic_chn_number[cur_str];}}}}result += section_value;return result;
}//测试函数
[TestMethod]
public void TestChineseToNumber()
{foreach (var item in m_dic_test){Assert.AreEqual(Solutions.ChineseToNumber(item.Value), item.Key, "error");}
}

C# UnitTest 初使用

  1. 在工程中 Solution 上右键 ->Add-> New Project…
  2. 添加一个 (c#) Unit Test Project
  3. 在创建的 Unit Test 工程中把需要测试的工程添加到 Reference
  4. 在自动生成的测试代码中添加自己的测试函数,然后运行就可以了。记得 using namespace。

LeetCode刷题-190709-扩展:阿拉伯数字和中文数字转换相关推荐

  1. 阿拉伯数字与中文数字转换算法

    根据<算法的乐趣>简单总结一下: 中文数字的特点 中文数字直接"数字+权位"的方式组成数字,比如阿拉伯数字100,中文表示为一百,其中"一"为数字, ...

  2. C#LeetCode刷题之#747-至少是其他数字两倍的最大数( Largest Number At Least Twice of Others)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3746 访问. 在一个给定的数组nums中,总是存在一个最大元素 ...

  3. python3实现阿拉伯数字和中文数字转换

    # transNumnum= input("请输入阿拉伯数字:") han = "零一二三四五六七八九"for i in range(len(num)):num ...

  4. C#LeetCode刷题-数组

    数组篇 # 题名 刷题 通过率 难度 1 两数之和 C#LeetCode刷题之#1-两数之和(Two Sum) 43.1% 简单 4 两个排序数组的中位数 C#LeetCode刷题之#4-两个排序数组 ...

  5. ​LeetCode刷题实战276:栅栏涂色

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  6. python数字转中文_阿拉伯数字转换为中文数字的python实现

    #!/usr/bin/python # -*- coding: utf-8 -*- ''' 脚本功能:阿拉伯数字与中文数字转换 输入参数:阿拉伯数字,不带符号 初次编写日期:2018-07-24 说明 ...

  7. Leetcode-How-What 力扣Leetcode刷题指南

    Leetcode-How-What 力扣Leetcode刷题指南 About the way how to use Leetcode wisely for preparing the intervie ...

  8. LeetCode刷题框架总结

    LeetCode刷题框架总结 01 | 数组和链表遍历框架 1.数组遍历框架,典型的线性迭代结构 void traverse(int[] arr) {for (int i = 0; i < ar ...

  9. 零基础新手学习算法Leetcode刷题指南

    刷算法到底在刷什么?这是很多人会想不明白的.而算法为什么这么重要,今天想说下这块内容.市面上都在说不要重复造轮子,这里说的不是你在一开始就不造轮子. 我们学习成长的过程是,先模仿,后改造,最终创新.所 ...

  10. Leetcode刷题日记:21-25题篇

    Leetcode刷题日记:21-25题篇 简介 题目: 21. 合并两个有序链表 22. 括号生成 23. 合并K个升序链表 24. 两两交换链表中的节点 25. K 个一组翻转链表 注 简介 这个系 ...

最新文章

  1. 公开分布式高性能查询的源代码和部署方案(一)
  2. 2020-11-11 C++函数后面加“:”的含义
  3. 挂代理无法访问网页了怎么办_搜索引擎蜘蛛不能爬取网页的原因有哪些
  4. http://www.cnblogs.com/qtqq/p/5271164.html
  5. opencv中图像的基本结构 类型的定义
  6. Yarn资源分配示例
  7. centos 7 关闭 firewall、iptables
  8. 循环-20. 猜数字游戏(15)
  9. 如何使用TensorFlow对象检测API播放Quidditch
  10. WAP2.0(XHTML MP)基础介绍
  11. python壁纸数据抓取_Python《wallhaven壁纸爬取》
  12. HTML动态分页函数
  13. 辽宁高考成绩查询电话2021,2021年辽宁高考成绩查询电话,辽宁高考成绩查询短信和电话号码...
  14. 保留数据和程序win7升级win10,平滑升级,完美!
  15. 浅谈IPv4/IPv6地址转换技术-中科三方
  16. MemSQL学习笔记-类似MySQL的数据库
  17. 戴尔服务器无视频信号,开启电脑 显示器提示无视频信号
  18. (4.1.40.5)Android手势检测GestureDecetor详解
  19. 六十八个超级经典管理小故事(转)
  20. 小学五年级趣味计算机课程,新媒体联盟 | 五年级小学段课程记——项目研究乐游学 趣味活动展风采...

热门文章

  1. 参数估计的均方误差(MSE),偏置(Bias)与方差(Variance)分解,无偏估计
  2. 针对win2003服务器的恶意代码攻击
  3. 基于Android Tv制作一个Tv桌面(三)
  4. 回归中的相关度和R平方值——学习笔记
  5. 数据可视化有哪些展现形式
  6. pmp考试【5】emv期望货币价值计算
  7. Camera效果测试-白平衡AWB测试
  8. 华为手机多屏互动功能使用
  9. iOS 通过商品短链接跳转京东商品详情页
  10. 关于NBIoT的知识