利用结构化的设计看待人民币大写转换

开发 架构
在网上看到不少人民币大写转换的类,或多或少的总有一些问题,不放心用在企业开发上。而且每个人的思路总是天马行空,别说面向对象的方法,就是面向过程也说不通,充斥着各种各样的特殊情况。如果少考虑一种情况,那结果就很难预料,而且代码的可读性,我实在不敢恭维。

昨天,突然心血来潮,用结构化的思想整理了一遍,在这里就拿出来分享一下。

首先,数字应该分段,分成万以下的、万、亿、兆这几个段,并且每个段的长度固定是4个数字。比如说 123456 分为两个段,前面一个未满的段:12 ,后面是满的段:3456 。

其次,每个满段其实都是个十百千四个单位。比如:12345678 ,转成数字大写是:壹仟贰佰叁拾肆  万  伍仟陆佰柒拾捌,发现什么规律了吗?

***,就是处理一些必须有 0 的问题了,比如说:303 ,不能说:叁佰叁,应该是:叁佰零叁,这个“零”有很多讲究的。

针对这些规律,我有针对性的整理出来两个方法:SingleConvert 、MultiConvert 。其中 SingleConvert 处理段内的逻辑,MultiConvert 处理段间的逻辑,在段内的数字 0 问题穿插到 SingleConvert 方法中,段间的数字 0 问题穿插到 MultiConvert 方法中。另外,小数部分的处理,只有两位数字,可以写死,这个最简单了。

说一下数字 0 的逻辑。

数字【3003】转换出来应该是【叁仟零叁】,数字【303】转换出来应该是【叁佰零叁】,可以看到段内连续出现一个或多个数字 0 的情况下,只会出现一个汉字【零】。

数字【3000000000300】转换出来应该是【叁兆零叁佰】,数字【300000300】转换出来应该是【叁亿零叁佰】,可以看到段间连续出现一个或多个数字 0 的情况下,只会出现一个汉字【零】。

所以,段内逻辑和段间逻辑,在连续出现多个【零】的时候,只保留一个【零】。

数字【300】转换出来应该是【叁佰】,数字【3000】转换出来应该是【叁仟】,可以看到在段内***不管连续出现多少【零】,都抹掉不提。所以,段内逻辑中,末尾的一个或多个【零】,均不保留。

还有两个不值得提的规律:每个数字对应一个单位,必定是【个十百千】;每段对应一个单位,从低到高的对应是【空、万、亿、兆、……】。原谅我不知大更高的单位是什么了,这辈子没见过那么多钱,神那~~

然后,然后就没规律了,下面上代码:

 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Diagnostics; 
  4. using System.Linq; 
  5. using System.Text; 
  6.   
  7. namespace Lenic.Core 
  8.     /// <summary> 
  9.     /// 数字转大写汉字字符类 
  10.     /// </summary> 
  11.     [DebuggerStepThrough] 
  12.     public class NumericConvert 
  13.     { 
  14.         #region Private Fields 
  15.         /// <summary> 
  16.         /// 段的分隔字符,从低到高依次增加:空、万、亿、万亿,***不超过万亿的数字都可以 
  17.         /// </summary> 
  18.         public static readonly string[] DefaultRangeNumeric = new string[] { string.Empty, "万""亿""兆" }; 
  19.         /// <summary> 
  20.         /// 位的分隔字符,从低到高依次是:仟、佰、拾、空 
  21.         /// </summary> 
  22.         public static readonly char[] DefaultUnitNumeric = new char[] { '仟''佰''拾'char.MinValue }; 
  23.         /// <summary> 
  24.         /// 数字替换的字符,从低到高依次是:零、壹、贰、叁、肆、伍、陆、柒、捌、玖 
  25.         /// </summary> 
  26.         public static readonly char[] DefaultCharNumeric = new char[] { '零''壹''贰''叁''肆''伍''陆''柒''捌''玖' }; 
  27.   
  28.         private char[] charNumeric = DefaultCharNumeric; 
  29.         private string[] rangeNumeric = DefaultRangeNumeric; 
  30.         private char zeroNumeric = DefaultCharNumeric[0]; 
  31.         private char[] unitNumeric = DefaultUnitNumeric; 
  32.         #endregion 
  33.   
  34.         #region Business Methods 
  35.         /// <summary> 
  36.         /// 重置数字替换的字符,必须从小到大是 10 个汉字字符。 
  37.         /// </summary> 
  38.         /// <param name="data">目标字符数组</param> 
  39.         /// <returns>成功替换则返回 <c>true</c> 。</returns> 
  40.         public bool ResetCharNumeric(char[] data) 
  41.         { 
  42.             if (data == null || data.Length != 10) 
  43.                 return false
  44.   
  45.             charNumeric = data; 
  46.             zeroNumeric = data[0]; 
  47.             return true
  48.         } 
  49.   
  50.         /// <summary> 
  51.         /// 重置位的分隔字符,必须从小到大是 4 个汉字字符。 
  52.         /// </summary> 
  53.         /// <param name="data">目标字符数组</param> 
  54.         /// <returns>成功替换则返回 <c>true</c> 。</returns> 
  55.         public bool ResetUnitNumeric(char[] data) 
  56.         { 
  57.             if (data == null || data.Length != 4) 
  58.                 return false
  59.   
  60.             unitNumeric = data; 
  61.             return true
  62.         } 
  63.   
  64.         /// <summary> 
  65.         /// 重置段的分隔字符。 
  66.         /// </summary> 
  67.         /// <param name="data">目标字符数组</param> 
  68.         public void ResetRangeNumeric(string[] data) 
  69.         { 
  70.             rangeNumeric = data ?? DefaultRangeNumeric; 
  71.         } 
  72.   
  73.         /// <summary> 
  74.         /// 执行数字转大写汉字字符的操作。 
  75.         /// </summary> 
  76.         /// <param name="obj">待转换的数字</param> 
  77.         /// <returns>转换完成的大写汉字字符串。</returns> 
  78.         public string Convert(decimal obj) 
  79.         { 
  80.             if (obj > 9999999999999999.99M) 
  81.                 throw new ApplicationException("The numeric too big!"); 
  82.   
  83.             var data = obj.ToString("#.##"); 
  84.   
  85.             var list = data.Split('.'); 
  86.   
  87.             var result = MultiConvert(list[0]); 
  88.             if (list.Length > 1) 
  89.                 result += DecimalConvert(list[1]); 
  90.   
  91.             return result; 
  92.         } 
  93.         #endregion 
  94.   
  95.         #region Private Methods 
  96.         private string MultiConvert(string data) 
  97.         { 
  98.             var list = Split(data).ToArray(); 
  99.   
  100.             var results = new List<string>(); 
  101.             foreach (var item in list) 
  102.                 results.Add(SingleConvert(item)); 
  103.   
  104.             var sbResult = new StringBuilder(); 
  105.             var len = results.Count; 
  106.             var index = len - 1; 
  107.   
  108.             for (int i = 0; i < len; i++) 
  109.             { 
  110.                 var item = results[i]; 
  111.                 if ((i + 2 < len) && item == zeroNumeric.ToString() && results[i + 1].StartsWith(zeroNumeric.ToString())) 
  112.                     continue
  113.   
  114.                 if (!(i == (len - 1) && item == zeroNumeric.ToString())) 
  115.                     sbResult.Append(item); 
  116.   
  117.                 var unit = rangeNumeric[index - i]; 
  118.                 if (unit != string.Empty && item != zeroNumeric.ToString()) 
  119.                     sbResult.Append(unit); 
  120.             } 
  121.   
  122.             if (sbResult[sbResult.Length - 1] == zeroNumeric) 
  123.                 sbResult.Remove(sbResult.Length - 1, 1); 
  124.             sbResult.Append("元"); 
  125.   
  126.             return sbResult.ToString(); 
  127.         } 
  128.   
  129.         private string SingleConvert(string data) 
  130.         { 
  131.             var len = data.Length; 
  132.             var result = new List<char>(); 
  133.             var previousChar = char.MinValue; 
  134.             var unitIndex = len == 4 ? 0 : (4 - len); 
  135.   
  136.             for (int i = 0; i < len; i++) 
  137.             { 
  138.                 var item = CharToInt(data[i]); 
  139.                 var currentChineseChar = charNumeric[item]; 
  140.                 if (currentChineseChar == previousChar && previousChar == zeroNumeric && currentChineseChar == zeroNumeric) 
  141.                     continue
  142.                 else 
  143.                 { 
  144.                     result.Add(previousChar = currentChineseChar); 
  145.   
  146.                     var currentUnit = unitNumeric[unitIndex + i]; 
  147.                     if (currentChineseChar != zeroNumeric && currentUnit != char.MinValue) 
  148.                         result.Add(currentUnit); 
  149.                 } 
  150.             } 
  151.   
  152.             if (result.Count != 1 && result.Last() == zeroNumeric) 
  153.                 result.RemoveAt(result.Count - 1); 
  154.   
  155.             return new string(result.ToArray()); 
  156.         } 
  157.   
  158.         private string DecimalConvert(string data) 
  159.         { 
  160.             StringBuilder sbResult = new StringBuilder(); 
  161.             if (data[0] != '0'
  162.             { 
  163.                 sbResult.Append(charNumeric[CharToInt(data[0])]); 
  164.                 sbResult.Append("角"); 
  165.             } 
  166.             if (data[1] != '0'
  167.             { 
  168.                 sbResult.Append(charNumeric[CharToInt(data[1])]); 
  169.                 sbResult.Append("分"); 
  170.             } 
  171.             return sbResult.ToString(); 
  172.         } 
  173.   
  174.         private IEnumerable<string> Split(string data) 
  175.         { 
  176.             var len = data.Length / 4; 
  177.             var mod = data.Length % 4; 
  178.             if (mod != 0) 
  179.                 len += 1; 
  180.   
  181.             var startIndex = 0; 
  182.             var blockLength = mod != 0 ? mod : 4; 
  183.   
  184.             for (int i = 0; i < len; i++) 
  185.             { 
  186.                 yield return data.Substring(startIndex, blockLength); 
  187.                 startIndex += blockLength; 
  188.                 blockLength = 4; 
  189.             } 
  190.         } 
  191.   
  192.         private int CharToInt(char obj) 
  193.         { 
  194.             return ((int)obj) - 48; 
  195.         } 
  196.         #endregion 
  197.     } 
  198.   
 
如果你喜欢本文,请点一下推荐,谢谢!
责任编辑:彭凡 来源: 博客园
相关推荐

2021-07-31 10:38:53

数字人民币数字货币区块链

2021-07-17 23:02:15

数字人民币支付宝微信

2021-10-14 09:06:37

数字人民币数字货币区块链

2021-07-20 22:23:12

数字人民币支付宝微信

2021-08-09 15:08:15

数字人民币比特币货币

2022-02-07 14:18:06

数字人民币冬奥会安全

2022-02-15 21:52:25

数字人民币数字货币区块链

2021-07-07 09:31:41

数字人民币数字货币区块链

2021-01-18 23:05:35

数字货币人民币现金

2021-01-18 11:05:40

数字货币人民币现金

2021-05-14 14:44:42

支付宝数字人民币移动应用

2021-11-16 14:36:36

数字人民币数字货币区块链

2021-02-07 11:19:03

数字货币人民币金融

2021-03-19 11:13:37

区块链数字货币人民币

2021-03-23 17:28:19

数字人民币安全银行

2011-11-18 09:35:18

App Store

2021-05-12 07:10:55

支付宝数字人民币移动应用

2022-02-17 15:46:08

数字人民币区块链

2021-07-02 16:50:02

数字人民币微信支付宝

2021-03-11 22:58:18

数字人民币数字货币区块链
点赞
收藏

51CTO技术栈公众号