zoukankan      html  css  js  c++  java
  • 我来写个人民币金额转大写的例子

    最近找段转换人民币金额大写的代码,结果放 google 一搜基本上都是些文盲写的垃圾代码,大概看了下他们都是先把数字转成字符串再各种操作的,恶心的不行,就跟看见用循环计算等差数列的和一样。所以,最后趁着放假花了点时间实现了一个比较科学的版本。

    为什么我写的这个版本特别科学呢?因为这个版本除了最终输出用了 StringBuilder 以外,在运行的时候不需要任何的动态内存操作,包括字符串操作和容器,只有栈操作和纯粹的运算,性能杠杠的。

    /** 中文互联网上迄今为止实现最正确、代码最漂亮且效率最高的大写人民币金额转换代码 
     * 作者:李维 <oldrev@gmail.com>
     * 版权所有 (c) 2013 昆明维智众源企业管理咨询有限公司。保留所有权利。
     * 本代码基于 BSD License 授权。
     * */
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    
    namespace Sandwych.RmbConverter {
    
        public static class RmbUpperConverter {
    
            private static readonly Char[] RmbDigits = {
                '', '', '', '', '', '', '', '', '', '' };
    
            private static readonly string[] SectionChars = {
                 string.Empty, "", "", "", "" };
    
            public static string ToRmbUpper(this decimal price) {
                if (price < 0M || price >= 9999999999999999.99M) {
                    throw new ArgumentOutOfRangeException("price");
                }
    
                price = Math.Round(price, 2);
                var sb = new StringBuilder();
    
                var integerPart = (long)price;
                var wanyiPart = integerPart / 1000000000000L;
                var yiPart = integerPart % 1000000000000L / 100000000L;
                var wanPart = integerPart % 100000000L / 10000L;
                var qianPart = integerPart % 10000L;
                var decPart = (long)(price * 100) % 100;
    
                int zeroCount = 0;
                //处理万亿以上的部分
                if (integerPart >= 1000000000000L && wanyiPart > 0) {
                    zeroCount = ParseInteger(sb, wanyiPart, true, zeroCount);
                    sb.Append("");
                }
    
                //处理亿到千亿的部分
                if (integerPart >= 100000000L && yiPart > 0) {
                    var isFirstSection = integerPart >= 100000000L && integerPart < 1000000000000L;
                    zeroCount = ParseInteger(sb, yiPart, isFirstSection, zeroCount);
                    sb.Append("亿");
                }
    
                //处理万的部分
                if (integerPart >= 10000L && wanPart > 0) {
                    var isFirstSection = integerPart >= 1000L && integerPart < 10000000L;
                    zeroCount = ParseInteger(sb, wanPart, isFirstSection, zeroCount);
                    sb.Append("");
                }
    
                //处理千及以后的部分
                if (qianPart > 0) {
                    var isFirstSection = integerPart < 1000L;
                    zeroCount = ParseInteger(sb, qianPart, isFirstSection, zeroCount);
                }
                else {
                    zeroCount += 1;
                }
    
                if (integerPart > 0) {
                    sb.Append("");
                }
    
                //处理小数
                if (decPart > 0) {
                    ParseDecimal(sb, integerPart, decPart, zeroCount);
                }
                else if (decPart <= 0 && integerPart > 0) {
                    sb.Append("");
                }
                else {
                    sb.Append("零元整");
                }
    
                return sb.ToString();
            }
    
            private static void ParseDecimal(StringBuilder sb, long integerPart, long decPart, int zeroCount) {
                Debug.Assert(decPart > 0 && decPart <= 99);
                var jiao = decPart / 10;
                var fen = decPart % 10;
    
                if (zeroCount > 0 && (jiao > 0 || fen > 0) && integerPart > 0) {
                    sb.Append("");
                }
    
                if (jiao > 0) {
                    sb.Append(RmbDigits[jiao]);
                    sb.Append("");
                }
                if (zeroCount == 0 && jiao == 0 && fen > 0 && integerPart > 0) {
                    sb.Append("");
                }
                if (fen > 0) {
                    sb.Append(RmbDigits[fen]);
                    sb.Append("");
                }
                else {
                    sb.Append("");
                }
            }
    
            private static int ParseInteger(StringBuilder sb, long integer, bool isFirstSection, int zeroCount) {
                Debug.Assert(integer > 0 && integer <= 9999);
                int nDigits = (int)Math.Floor(Math.Log10(integer)) + 1;
                if (!isFirstSection && integer < 1000) {
                    zeroCount++;
                }
                for (var i = 0; i < nDigits; i++) {
                    var factor = (long)Math.Pow(10, nDigits - 1 - i);
                    var digit = integer / factor;
    
                    if (digit != 0) {
                        if (zeroCount > 0) {
                            sb.Append("");
                        }
                        sb.Append(RmbDigits[digit]);
                        sb.Append(SectionChars[nDigits - i - 1]);
                        zeroCount = 0;
                    }
                    else {
                        zeroCount++;
                    }
                    integer -= integer / factor * factor;
                }
                return zeroCount;
            }
    
        }
    
    }

    单元测试,及 Python(嗯,我就是这么好心,又用 Python 重新实现了一遍) 实现版本什么的都放在 GitHub 上了:https://github.com/Sandwych/rmb_converter

    以后写程序动动脑子,你们可长点心吧!

  • 相关阅读:
    Bitnami 2015
    knowledgeroot
    远程管理服务 Windows Remote Management (WS-Management)
    Composer 安装
    开源知识库管理系统选型 centos6.4 搭建knowlededgeroot-1.0.4知识库平台
    两个IP实现IIS和Apache公用80端口的设置方法
    Solidworks工程图如何使用,替换图纸格式模板文件
    Solidworks工程图 如何绘制向视图,辅助视图
    Solidworks打印工程图超出范围了怎么办
    Solidworks 如何绘制投影曲线
  • 原文地址:https://www.cnblogs.com/oldrev/p/3330558.html
Copyright © 2011-2022 走看看