金額轉換為人民幣中文大寫


在網上看到不少人民幣大寫轉換的類,或多或少的總有一些問題,不放心用在企業開發上。而且每個人的思路總是天馬行空,別說面向對象的方法,就是面向過程也說不通,充斥着各種各樣的特殊情況。如果少考慮一種情況,那結果就很難預料,而且代碼的可讀性,我實在不敢恭維。

 

昨天,突然心血來潮,用結構化的思想整理了一遍,在這里就拿出來分享一下。

 

首先,數字應該分段,分成萬以下的、萬、億、兆這幾個段,並且每個段的長度固定是4個數字。比如說 123456 分為兩個段,前面一個未滿的段:12 ,后面是滿的段:3456 。

其次,每個滿段其實都是個十百千四個單位。比如:12345678 ,轉成數字大寫是:壹仟貳佰叄拾肆  萬  伍仟陸佰柒拾捌,發現什么規律了嗎?

最后,就是處理一些必須有 0 的問題了,比如說:303 ,不能說:叄佰叄,應該是:叄佰零叄,這個“零”有很多講究的。

 

針對這些規律,我有針對性的整理出來兩個方法:SingleConvert 、MultiConvert 。其中 SingleConvert 處理段內的邏輯,MultiConvert 處理段間的邏輯,在段內的數字 0 問題穿插到 SingleConvert 方法中,段間的數字 0 問題穿插到 MultiConvert 方法中。另外,小數部分的處理,只有兩位數字,可以寫死,這個最簡單了。

 

說一下數字 0 的邏輯。

 

數字【3003】轉換出來應該是【叄仟零叄】,數字【303】轉換出來應該是【叄佰零叄】,可以看到段內連續出現一個或多個數字 0 的情況下,只會出現一個漢字【零】。

數字【3000000000300】轉換出來應該是【叄兆零叄佰】,數字【300000300】轉換出來應該是【叄億零叄佰】,可以看到段間連續出現一個或多個數字 0 的情況下,只會出現一個漢字【零】。

所以,段內邏輯和段間邏輯,在連續出現多個【零】的時候,只保留一個【零】

 

數字【300】轉換出來應該是【叄佰】,數字【3000】轉換出來應該是【叄仟】,可以看到在段內最后不管連續出現多少【零】,都抹掉不提。

所以,段內邏輯中,末尾的一個或多個【零】,均不保留

 

還有兩個不值得提的規律:每個數字對應一個單位,必定是【個十百千】;每段對應一個單位,從低到高的對應是【空、萬、億、兆、……】

原諒我不知大更高的單位是什么了,這輩子沒見過那么多錢,神那~~

 

然后,然后就沒規律了,下面上代碼:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
 
namespace Lenic.Core
{
    /// <summary>
    /// 數字轉大寫漢字字符類
    /// </summary>
    [DebuggerStepThrough]
    public class NumericConvert
    {
        #region Private Fields
        /// <summary>
        /// 段的分隔字符,從低到高依次增加:空、萬、億、萬億,最高不超過萬億的數字都可以
        /// </summary>
        public static readonly string[] DefaultRangeNumeric = new string[] { string.Empty, "萬", "億", "兆" };
        /// <summary>
        /// 位的分隔字符,從低到高依次是:仟、佰、拾、空
        /// </summary>
        public static readonly char[] DefaultUnitNumeric = new char[] { '仟', '佰', '拾', char.MinValue };
        /// <summary>
        /// 數字替換的字符,從低到高依次是:零、壹、貳、叄、肆、伍、陸、柒、捌、玖
        /// </summary>
        public static readonly char[] DefaultCharNumeric = new char[] { '零', '壹', '貳', '叄', '肆', '伍', '陸', '柒', '捌', '玖' };
 
        private char[] charNumeric = DefaultCharNumeric;
        private string[] rangeNumeric = DefaultRangeNumeric;
        private char zeroNumeric = DefaultCharNumeric[0];
        private char[] unitNumeric = DefaultUnitNumeric;
        #endregion
 
        #region Business Methods
        /// <summary>
        /// 重置數字替換的字符,必須從小到大是 10 個漢字字符。
        /// </summary>
        /// <param name="data">目標字符數組</param>
        /// <returns>成功替換則返回 <c>true</c> 。</returns>
        public bool ResetCharNumeric(char[] data)
        {
            if (data == null || data.Length != 10)
                return false;
 
            charNumeric = data;
            zeroNumeric = data[0];
            return true;
        }
 
        /// <summary>
        /// 重置位的分隔字符,必須從小到大是 4 個漢字字符。
        /// </summary>
        /// <param name="data">目標字符數組</param>
        /// <returns>成功替換則返回 <c>true</c> 。</returns>
        public bool ResetUnitNumeric(char[] data)
        {
            if (data == null || data.Length != 4)
                return false;
 
            unitNumeric = data;
            return true;
        }
 
        /// <summary>
        /// 重置段的分隔字符。
        /// </summary>
        /// <param name="data">目標字符數組</param>
        public void ResetRangeNumeric(string[] data)
        {
            rangeNumeric = data ?? DefaultRangeNumeric;
        }
 
        /// <summary>
        /// 執行數字轉大寫漢字字符的操作。
        /// </summary>
        /// <param name="obj">待轉換的數字</param>
        /// <returns>轉換完成的大寫漢字字符串。</returns>
        public string Convert(decimal obj)
        {
            if (obj > 9999999999999999.99M)
                throw new ApplicationException("The numeric too big!");
 
            var data = obj.ToString("#.##");
 
            var list = data.Split('.');
 
            var result = MultiConvert(list[0]);
            if (list.Length > 1)
                result += DecimalConvert(list[1]);
 
            return result;
        }
        #endregion
 
        #region Private Methods
        private string MultiConvert(string data)
        {
            var list = Split(data).ToArray();
 
            var results = new List<string>();
            foreach (var item in list)
                results.Add(SingleConvert(item));
 
            var sbResult = new StringBuilder();
            var len = results.Count;
            var index = len - 1;
 
            for (int i = 0; i < len; i++)
            {
                var item = results[i];
                if ((i + 2 < len) && item == zeroNumeric.ToString() && results[i + 1].StartsWith(zeroNumeric.ToString()))
                    continue;
 
                if (!(i == (len - 1) && item == zeroNumeric.ToString()))
                    sbResult.Append(item);
 
                var unit = rangeNumeric[index - i];
                if (unit != string.Empty && item != zeroNumeric.ToString())
                    sbResult.Append(unit);
            }
 
            if (sbResult[sbResult.Length - 1] == zeroNumeric)
                sbResult.Remove(sbResult.Length - 1, 1);
            sbResult.Append("元");
 
            return sbResult.ToString();
        }
 
        private string SingleConvert(string data)
        {
            var len = data.Length;
            var result = new List<char>();
            var previousChar = char.MinValue;
            var unitIndex = len == 4 ? 0 : (4 - len);
 
            for (int i = 0; i < len; i++)
            {
                var item = CharToInt(data[i]);
                var currentChineseChar = charNumeric[item];
                if (currentChineseChar == previousChar && previousChar == zeroNumeric && currentChineseChar == zeroNumeric)
                    continue;
                else
                {
                    result.Add(previousChar = currentChineseChar);
 
                    var currentUnit = unitNumeric[unitIndex + i];
                    if (currentChineseChar != zeroNumeric && currentUnit != char.MinValue)
                        result.Add(currentUnit);
                }
            }
 
            if (result.Count != 1 && result.Last() == zeroNumeric)
                result.RemoveAt(result.Count - 1);
 
            return new string(result.ToArray());
        }
 
        private string DecimalConvert(string data)
        {
            StringBuilder sbResult = new StringBuilder();
            if (data[0] != '0')
            {
                sbResult.Append(charNumeric[CharToInt(data[0])]);
                sbResult.Append("角");
            }
            if (data[1] != '0')
            {
                sbResult.Append(charNumeric[CharToInt(data[1])]);
                sbResult.Append("分");
            }
            return sbResult.ToString();
        }
 
        private IEnumerable<string> Split(string data)
        {
            var len = data.Length / 4;
            var mod = data.Length % 4;
            if (mod != 0)
                len += 1;
 
            var startIndex = 0;
            var blockLength = mod != 0 ? mod : 4;
 
            for (int i = 0; i < len; i++)
            {
                yield return data.Substring(startIndex, blockLength);
                startIndex += blockLength;
                blockLength = 4;
            }
        }
 
        private int CharToInt(char obj)
        {
            return ((int)obj) - 48;
        }
        #endregion
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM