[算法题] 人民币大小写转换(阿拉伯数字和汉字转换)

在一次面试中遇到一个有意思的小算法题:要求将阿拉伯数字转为汉字显示出来(包含单位)。

当时虽然实现出来,但是代码写的有点凌乱。所以回家后,重新整理了一下。

这个算法有几个小的注意点:

1、中文字符占两个字节,所以如果用C语言实现,需要用char数组的形式保存单个汉字。

2、如果数字中出现连续的零,需要把它替换为单一的零。

3、在亿、万、元的前面一个汉字不可以为零(人民币读取方式决定)。

4、double数值可分为整数部分和小数部分。小数部分较简单,整数部分需要根据这个数字所在的位数匹配上对应的单位。

具体方法是:设置一个单位映射字符串表g_strUnit,可视为一个简单的HashTable。然后从头开始读取整数字符串的每个

字符,若这个字符在整数字符串的位置为i,这个字符后面的单位就是g_strUnit[length-1-i]。

代码如下

/*******************************************************************************
Project Code  : Account
File name     : 
Author        : Latte
Description   : 阿拉伯数字转为中文字符串
Function List :
--------------------------------------------------------------------------------
History:
Date            Author          Modification
20140703        Latte           created file.
*******************************************************************************/

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

#define MAX 100
string g_strDigit[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

string g_strUnit[] = {"圆", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", 
 "拾", "佰", "仟", "万", "拾", "佰"};

string g_strUnit2[] = {"角", "分"};

/*******************************************************************************
Func Name       : ReplaceSubStr
Date Created    : 2014-07-03
Author          : Latte
Description     : 将源字符串strOrig中第一个匹配strSub的子串部分替换为strReplace
Input           : 
                  string &strOrig, 
                  string strSub, 
                  string strReplace
Output          : 
                  string &strOrig
Return          : 
                  int
Caution         : 返回值如果为-1,则表示替换失败或未找到替换项
*******************************************************************************/
int ReplaceSubStr(string &strOrig, string strSub, string strReplace)
{
 int pos = (int)strOrig.find(strSub);
 int length = (int)strSub.length();
 
 if (pos >= 0)
    {
        strOrig.replace(pos, length, strReplace);
 return 0;
    }
 
 return -1;
}

/*******************************************************************************
Func Name       : NumToChineseStr
Date Created    : 2014-07-03
Author          : Latte
Description     : 
                  将人民币double数值转化为人民币汉字string
Input           : 
                  double money
Output          : 
Return          : 
                  string
Caution         :
*******************************************************************************/
string NumToChineseStr(double money)
{
 int i               = 0;
 int ret             = 0;
 int length          = 0;
 char *p             = NULL;
 char *pcDecimal     = NULL; //保存小数部分字符
 char czNumber[MAX]  = {0};  //保存完整数字部分字符
 string strResult;

    cout << "======================================" << endl;
    cout << money << endl;

 //判断是否为小数
 if (money < 0)
    {
        strResult = "不支持读负数";   
 return strResult;   
    }

 //将数字转为数字字符串,利用sprintf_s的正则转换
    sprintf_s(czNumber, MAX, "%.15lg", money);
    printf("[No.0]%s\n", czNumber); 

 //如果数字是太大或太小的数,因为已经转为科学计数,所以会含有e字符
    p = strchr(czNumber,'e');  
 if (NULL!=p) 
    {
        strResult = "不支持读太大或太小的数";
 return strResult;
    }
 
    p = strchr(czNumber, '.');  
 if (NULL != p) 
    {       
        p[0] = 0;    
        pcDecimal = p + 1;   
    }    
    length = (int)strlen(czNumber);  
 
 for (i = 0; i<length; i++) 
    {        
 if ('0' == czNumber[i] && 0 != ((length-1-i) % 4))
        {
            strResult += g_strDigit[czNumber[i] - '0'];
        } 
 else 
        {
            strResult += g_strDigit[czNumber[i] - '0'] + g_strUnit[length-1-i];
        }   
    }
    cout << "[No.1]把数字直接替换为汉字: \n" << strResult << endl;

 //把strResult中的所有"零零"子串替换为"零"
 while (1)
    {
        ret = ReplaceSubStr(strResult, "零零", "零");
 if (ret < 0)
        {
 break;
        }
    }
    cout << "[No.2]替换所有零零为零: \n" << strResult << endl;

    ReplaceSubStr(strResult, "零亿", "亿");
    ReplaceSubStr(strResult, "零万", "万");
 if (strResult != "零圆")    //如果整数部分全为0,则不要去除元单位前面的零
    {
        ReplaceSubStr(strResult, "零圆", "圆");
    }
 
    cout << "[No.3]去除零亿、零万、零圆前面的零: \n" << strResult << endl;

 //小数精确到两位数,即精确到单位分
 if (NULL != pcDecimal) 
    {
 //如果小数部分有数值而整数部分为0,则删除字符串中的零元
 if (strResult == "零圆")
        {
            strResult.clear();
        }
        i = 0;
 while (1) 
        {           
 if (0 == pcDecimal[i] || i >= 2) 
 break;   
            strResult += g_strDigit[pcDecimal[i] - '0'] + g_strUnit2[i];
            i++;      
        }   
    }
    cout << "[No.4]小数精确到两位数,即精确到单位分: \n" << strResult << endl;
 
 return strResult;
}

int main(void)
{
 //cout << "Result: " << NumToChineseStr(0.00) << endl;
 //cout << "Result: " << NumToChineseStr(-345.67) << endl;
 //cout << "Result: " << NumToChineseStr(1000.0) << endl;
    cout << "Result: " << NumToChineseStr(130040600090.012) << endl;

 return 0;
}

结果

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术/开源

30分钟?不需要,轻松读懂IL

先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用。到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点...

1867
来自专栏码匠的流水账

聊聊jpa的动态查询

使用springside的DynamicSpecifications,再把mvc的参数映射为SearchFilter,也可以自己实现一套端到端的动态查询。

521
来自专栏偏前端工程师的驿站

(cljs/run-at (JSVM. :browser) "简单类型可不简单啊~")

前言  每逢学习一个新的语言时总要先了解这门语言支持的数据类型,因为数据类型决定这门语言所针对的问题域,像Bash那样内置只支持字符串的脚步明显就是用于文本处理...

1817
来自专栏Seebug漏洞平台

以太坊智能合约OPCODE逆向之理论基础篇

在我们对etherscan等平台上合约进行安全审查时,常常会遇到没有公布Solidity源代码的合约,只能获取到合约的OPCODE,所以一个智能合约的反编译器对...

1333
来自专栏听雨堂

【4】通过简化的正则表达式处理字符串

阅读目录 常见字符串操作 使用正则表达式处理字符串 “前后限定”查找目标 自动处理转义字符 界定串的通用化 多个目标的匹配 进一步扩展 结论 在...

1956
来自专栏菩提树下的杨过

java与c#的反射性能比较

java与c#都支持反射,但是从网络上搜索两大阵营对于反射的态度,基本上.net开发人员都建议慎用反射,因为会有性能开销;反到是java阵营里好象在大量肆无忌惮...

1908
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-20(01)总结,递归,IO流

1:递归(理解) (1)方法定义中调用方法本身的现象 举例:老和尚给小和尚讲故事,我们学编程 (2)递归的注意事项; A:要有出口,否则就是死递归 B...

3289
来自专栏木可大大

编写优雅代码的最佳实践

Robert Martin曾说过"在代码阅读中说脏话的频率是衡量代码质量额唯一标准"。同时,代码的写法应当使别人理解它所需的时间最小化,也就是说我们写的代码是给...

41520
来自专栏智能大石头

Cortex-M3启动深度解析

Cortex-Mx启动,备忘,以免将来忘记。 中断向量表不用说,从重置中断开始吧 LDR R0, =SystemInit BLX R0 LDR ...

1726
来自专栏Brian

Scala Turtuial-基本语法

概述 Scala是将面向对象思想与函数式编程思想集一身的编程语言,特别是在大数据和流式处理方面的快速发展,基于Scala语言一些重要的开源框架随之发布,比如:S...

2564

扫码关注云+社区