将数字转换成中文大写

 

c++

转自:https://blog.csdn.net/u010944926/article/details/20783141

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/**
 * 程序目的:
 *   从命令行接收一个数,并将其转化为中文金额的大写方式(C++版)
 * 例如 123.45 --> 壹佰贰拾叁元肆角伍分
 * @author LovinChan
 *
 *   前一段时间做了个 Java 版的。突然有天心血来潮做个 C++ 版本的,实现的功能
 * 跟 Java 版本的没什么区别,不过由于我对 C++ 的了解还不是很多,还是学习阶段,
 * 写出来的东西还有很多问题和不合规范的地方,希望各位批评指出来。
 
 *   程序的注释我尽量写得详细一点,如果觉得这个程序哪里有问题或者是哪里有改进的
 * 地方欢迎随时跟我交流。
 
 *   我附上了编译以后的 .exe 文件跟 .bat 文件,还有项目源码,供大家测评。
 *
 * 工具:Microsoft Visual Studio 2005
 * 编译环境:Microsoft Visual Studio 2005
 *
 * 我的msn:egg.chenlw@gmail.com
 *    QQ:372133556(注上为什么加我就可以了)
 * 我的blog:http://hi.baidu.com/egg_chen
 * 欢迎交流
 */ 
#include <iostream> 
#include <string> 
   
using namespace std; 
   
// 表示整数部分的标志 
const int INT_ONLY = 1; 
// 表示小数部分的标志 
const int SMALL_ONLY = 2; 
   
/**
 * 从命令行接收一个数,在其中调用 checkNum() 方法对其进行
 * 验证,并返回相应的值
 * @return 如果输入合法,返回输入的这个数
 */ 
string getNum() { 
    string s; 
    cout << "请输入一个数字(精确到小数点后两位):" << endl; 
    // 从命令行输入这个浮点数 
    cin >> s; 
    // 清除输入流状态标志 
    cin.clear(); 
    return s; 
   
/**
* 判断用户输入的数据是否合法,用户只能输入大于零的数字,不能输入其它字符
* @param s string
* @return 如果用户输入数据合法,返回 true,否则返回 false
*/ 
bool checkNum(string s) { 
    // atof(s.c_str()) 方法的功能是将字符串 s 转换成一个双精度数值并返回结果 
    double d = atof(s.c_str()); 
    // 只有当用户输入一个大于0的数时,才会返回true 
    if(d > 0) { 
        return true
    
    return false
   
/**
 * 对传入的数进行四舍五入操作
 * @param s string,从命令行输入的那个数
 * @return 四舍五入后的新值
 */ 
string roundString(string s) { 
    // 将这个数转换成 double 类型,并对其进行四舍五入操作 
    // 先转换这个数的整数部分 
    // atof(s.c_str()) 方法的功能是将字符串 s 转换成一个双精度数值并返回结果 
    // c_str()函数返回一个指向正规C字符串的指针, 内容与本字符串相同 
    double d = atof(s.c_str()); 
    // 将这个数进行四舍五入,保留到小数点后两位 
    // 再将这个数转换成字符串,等待转换 
    int dec, sign;  
    // 注意:当这个数转换成字符串以后不会显示小数点,并且会以四舍五入的形式只保留小数点后两位 
    s = fcvt(d, 2, &dec, &sign); 
    // 规定数值的最大长度只能是15位(到万亿位) 
    if(s.length() > 15) { 
        cout << "输入数据过大!(整数部分最多13位!)" << endl; 
        return ""
    
    return s; 
   
/**
 * 把传入的数转换为中文金额大写形式
 * @param flag int 标志位,1 表示转换整数部分,0 表示转换小数部分
 * @param s string 要转换的字符串
 * @return 转换好的带单位的中文金额大写形式
 */ 
string formatChinese(int flag, string s) { 
    int sLength = s.length(); 
    // 货币大写形式 
    string bigLetter[] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; 
    // 货币单位 
    string unit[] = {"元", "拾", "佰", "仟", "万",  
                // 拾万位到仟万位 
                "拾", "佰", "仟"
                // 亿位到万亿位 
                "亿", "拾", "佰", "仟", "万"}; 
    string small[] = {"分", "角"}; 
    // 用来存放转换后的新字符串 
    string newS = ""
    // 逐位替换为中文大写形式 
    for(int i = 0; i < sLength; i ++) { 
        if(flag == INT_ONLY) { 
            // 转换整数部分为中文大写形式(带单位) 
            newS = newS + bigLetter[s.at(i) - 48] + unit[sLength - i - 1]; 
        } else if(flag == SMALL_ONLY) { 
            // 转换小数部分(带单位) 
            newS = newS + bigLetter[s.at(i) - 48] + small[sLength - i - 1]; 
        
    
    return newS; 
   
/**
 * 把用户输入的数以小数点为界分割开来,并调用 numFormat() 方法
 * 进行相应的中文金额大写形式的转换
 * 注:传入的这个数应该是经过 roundString() 方法进行了四舍五入操作的
 * @param s string
 * @return 转换好的中文金额大写形式的字符串
 */ 
string splitNum(string s) { 
    // 如果传入的是空串则继续返回空串 
    if("" == s) { 
        return ""
    
    // 截取输入数字的整数部分 
    string intOnly = s.substr(0, s.size() - 2); 
    string intPart = formatChinese(1, intOnly); 
   
    // 截取这个数的小数部分 
    string smallOnly = s.substr(s.size() - 2, s.size()); 
    string smallPart = formatChinese(2, smallOnly); 
   
    // 把转换好了的整数部分和小数部分重新拼凑一个新的字符串 
    string newS = intPart + smallPart; 
   
    return newS; 
   
/**
 * 使用给定的 replacement 替换此字符串所有匹配给定的 regex 的子字符串。
 * @param src - 待操作的源字符串
 * @param regex - 用来匹配此字符串的正则表达式
 * @param replacement - 用来替换每个匹配项的字符串 
 * @return 替换后的字符串 
 */ 
string replaceAll(string src, string regex, string replacement) { 
    int length = regex.length(); 
    while(src.find(regex) < src.length()) { 
        // 替换 src 字符串中从第一个匹配 regex 的字符串索引开始的 length 个字符为 replacement 字符串         
        src.replace(src.find(regex), length, replacement); 
    
    return src; 
   
/**
 * 把已经转换好的中文金额大写形式加以改进,清理这个字
 * 符串里面多余的零,让这个字符串变得更加可观
 * 注:传入的这个数应该是经过 splitNum() 方法进行处理,这个字
 * 符串应该已经是用中文金额大写形式表示的
 * @param s string 已经转换好的字符串
 * @return 改进后的字符串
 */ 
string cleanZero(string s) { 
    // 如果传入的是空串则继续返回空串 
    if("" == s) { 
        return ""
    
    // 字符串中存在多个'零'在一起的时候只读出一个'零',并省略多余的单位 
    /* 由于本人对算法的研究太菜了,只能用4个正则表达式去转换了,各位大虾别介意哈... */ 
    string regex1[] = {"零仟", "零佰", "零拾"}; 
    string regex2[] = {"零亿", "零万", "零元"}; 
    string regex3[] = {"亿", "万", "元"}; 
    string regex4[] = {"零角", "零分"}; 
   
    // 第一轮转换把 "零仟", 零佰","零拾"等字符串替换成一个"零" 
    for(int i = 0; i < 3; i ++) { 
        s = replaceAll(s, regex1[i], "零"); 
    
    // 第二轮转换考虑 "零亿","零万","零元"等情况 
    // "亿","万","元"这些单位有些情况是不能省的,需要保留下来 
    for(int i = 0; i < 3; i ++) { 
        // 当第一轮转换过后有可能有很多个零叠在一起 
        // 要把很多个重复的零变成一个零 
        s = replaceAll(s, "零零零", "零"); 
        s = replaceAll(s, "零零", "零"); 
        s = replaceAll(s, regex2[i], regex3[i]); 
    
    // 第三轮转换把"零角","零分"字符串省略 
    for(int i = 0; i < 2; i ++) { 
        s = replaceAll(s, regex4[i], ""); 
    
    // 当"万"到"亿"之间全部是"零"的时候,忽略"亿万"单位,只保留一个"亿" 
    s = replaceAll(s, "亿万", "亿"); 
    return s; 
   
int main() { 
    cout << "\n------------将数字转换成中文金额的大写形式(C++)------------\n" << endl; 
    string s = getNum(); 
    if(checkNum(s)) { 
        s = roundString(s); 
        s = splitNum(s); 
        s = cleanZero(s); 
        cout << "转换成中文后为:" << s << endl; 
    } else
        cout << "非法输入,程序即将退出" << endl; 
    
    cout << "\n--------------------------------------------------------------" << endl; 

  

qt C++

转自:https://blog.csdn.net/Kshine2017/article/details/79408807

1.期望实现:
数字 ===> 中文大写

如:  

        123.0456                      ===>                                                   壹贰叁点零肆伍陆

        12003045.678              ===>                     壹仟贰佰零万叁仟零肆拾伍点陆捌

        32012003045.678        ===>    叁佰贰拾亿壹仟贰佰零万叁仟零肆拾伍点陆捌

 

2.基本思路:
2.1 将数字分成四部分 即: 符号+整数+“点”+小数

2.2 查表拼接---将每一位的数字对应到汉字,将汉字拼接上去。

整数部分有数值单位,小数部分不需要数值单位。

 

数字表


QStringList numerical_value = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};

单位表

(这个表成员的多少 决定你能装换的最大数值范围)(这里给出的可以让你最大转换 1万亿之下的所有数字(小于1万亿,大于负1万亿))


QStringList numerical_unit = {"","拾","佰","仟","万","拾", "佰", "仟", "亿", "拾", "佰", "仟"};

3.难点:
实现查表,再拼接,这样做很简单。但是这样做的结果就是如此:

32012003045.678        ===>    叁佰贰拾零亿壹仟贰佰零拾零万叁仟零佰肆拾伍点陆捌

猛地一看,你可能觉得没什么,但这样的写法是不符合我们中国人读数字的习惯的。

3.1当出现多个连0的情况的时候,需要我们根据情况省略和跳过拼接。

 

3.2在省略零的时候,要注意分段省略,按照中国人的习惯,4位为一段。我按照 “”,“万”,“亿”将整数部分分成三段(因为我的数字范围是1万亿以下)。

如果不分段,可能会导致,“万”和“亿”的丢失。

 

4.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
const QString number_Transfer_BigChinese(const double &Fnumber)
{
  
    if(qAbs(Fnumber)<0.01)   //保留2位小数时,近似看作零的情况
        return "零";
  
  
    //判断正负号
    QString numberSign;//存储符号
    if(Fnumber<0)
        numberSign = "(负数)";
   //将数据的绝对值 转换成字符串,如-58 转成 “58.00”
   QString number = QString::number(qAbs(Fnumber),'f',2);//qAbs绝对值 ,保留两位小数
   QString Left_of_Point;//整数部分
   int length =number.length()-3;//整数部分的长度,(精确度为2,去除小数和小数点)
   if(length>12)
   {
        //qDebug()<<"输入的数值超过范围!"
        return "输入的数值超过范围!";
   }
  
   QStringList numerical_unit   =   {"","拾","佰","仟","万","拾", "佰", "仟", "亿", "拾", "佰", "仟"};
   QStringList numerical_value  =   {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
  
   //数数整数低位多少个连零
   int counter_0=0;
   for(int i =length-1;i>=0;i--)
   {
       if((number[i].toLatin1()-'0' )==0) //从个位开始,向高位走
           counter_0++;
       else
           break;
  
   }
   if(length==1 && counter_0==1) //0.x
       counter_0=0; //不进行过滤
  
   //1400  0.2
  
   for(int i=0,flag=1;i<length-counter_0;i++)
   {
        //5     8       1    2   3
        //伍 拾 捌       壹佰 贰拾 叁
       if((number[i].toLatin1()-'0')==0)
       {
           if((flag!=0 && (length-1-i)%4 != 0) || length ==1) //flag!=0  表示前一个数值 不为0
           Left_of_Point+="零"; //后面不用添加 单位
           if((length-1-i)%4 == 0) //如果0处于分段处,后面需添加单位
           Left_of_Point+=numerical_unit[length-1-i];//添加数值单位
  
           flag =0; //标记
  
       }
       else
       {
        flag =1;
        Left_of_Point+=numerical_value[number[i].toLatin1()-'0']; //'5'-'0'==5
        Left_of_Point+=numerical_unit[length-1-i];//添加数值单位
  
       }
   }
    //QString Right_of_Point;//小数点右侧,小数部分(保留两位)  xxxx.yy
    int totalLength = number.length();
    if(number[totalLength-2]=='0'&&number[totalLength-1]=='0')
    {
        QString Bigcn=numberSign+Left_of_Point+"吨";
        return Bigcn;
    }
    else if(number[totalLength-2]!='0'&&number[totalLength-1]=='0')
    {
        QString Bigcn=numberSign+Left_of_Point+"点"+numerical_value[number[totalLength-2].toLatin1()-'0']+"吨";
        return Bigcn;
    }
    else
    {
        QString Bigcn=numberSign+Left_of_Point+"点"+numerical_value[number[totalLength-2].toLatin1()-'0']+numerical_value[number[totalLength-1].toLatin1()-'0']+"吨";
        return Bigcn;
    }
  
  
    return "异常情况";
}

  

posted @   阳光下的小土豆  阅读(1235)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示