1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【C语言】小写数字金额转换成中文大写金额

【C语言】小写数字金额转换成中文大写金额

时间:2023-10-02 04:59:25

相关推荐

【C语言】小写数字金额转换成中文大写金额

1. 更新说明

添加与 “零圆整” 等价的预先判断 (0/0./0.0/0.00/./.0/.00)修复了因使用函数strdup导致的内存泄漏除去输入串多余的空白符(空格/Tab制表符)

2. 代码如下面所示

//=================================================================// CPSTR: Copyright (c) By Abodu, All Rights Reserved.// FNAME: arabToChinese.c// AUTHR: abodu,abodu@// CREAT: -06-14 14:56:23// ENCOD: UTF-8 Without BOM// VERNO: 1.0.3// LUPTS: -10-21 22:18:50//=================================================================#include <stdio.h>#include <stdlib.h>#include <string.h>/***** 阿拉伯数字表示的金额串转换成中文大写金额*** 转换成功,则输出转换后的大写金额*** 转换失败,则返回NULL**/char *arabToChinese(const char *aInput);#define JINER_MAX_SIZE 1 << 5#define CNFEE_MAX_SIZE 1 << 8static char a_src[JINER_MAX_SIZE] = {0};static char o_chn[CNFEE_MAX_SIZE] = {0};static char *spo = o_chn;char *CU_INT[] = {"整", "圆", //"拾", "佰", "仟", "萬", //"拾", "佰", "仟", "億", //"拾", "佰", "仟", "兆", //"拾", "佰", "仟", "京", //"拾", "佰", "仟", "垓" //};char *CU_DEC[] = {"负", "角", "份", "厘", "钱", "毫"};char *CN[] = {"零", "壹", "贰", "叁", "肆", //"伍", "陆", "柒", "捌", "玖"};char *CZ_ERR[] = {"[ERR]格式错误,负号(-)出现在金额串的不正确位置处","[ERR]格式错误,小数点(.)只能出现一次","[ERR]格式错误,除-0.XX和0.XX外,不允许出现前置零(0XXX)","[ERR]格式错误,输入的串内含有不属于十进制金额的其他字符",};static char *apd1(char *npr) {int t = strlen(o_chn);snprintf(o_chn + t, sizeof(o_chn) - t, "%s", npr);return o_chn;}static char *apd2(char *N1, char *N2) { return apd1(N1), apd1(N2); }/***** 删除字符串中所有的逗号和空格**/char *trim_casp_all(char *p) {int i = 0, j = 0;while (p[i]) {if (p[i] != ',' && p[i] != ' ' && p[i] != '\t') {p[j++] = p[i];}i++;}p[j] = '\0';// printf("%s\n", p);return p;}int main(int argc, char *argv[]) {int i = 1;char *p = NULL;fprintf(stderr, "-- 阿拉伯数字转化成中文金额字符串(小数部分仅保留到分) --\n");do {memset(a_src, 0, JINER_MAX_SIZE);memset(o_chn, 0, CNFEE_MAX_SIZE);if (argc == 1) {//后面没有参数,需要手动输入一个小写金额printf("请输入(阿拉伯数字表示的)小写金额:>");scanf("%s", a_src);} else {sprintf(a_src, "%s", argv[i++]);}printf("%s --> %s\n", a_src, arabToChinese(trim_casp_all(a_src)));} while (i < argc);return 0;}char *arabToChinese(const char *aInput) {#define check_zero_yuan(X) \!strcmp((X), "0.0") || !strcmp((X), "0.00") || !strcmp((X), "0") ||\!strcmp((X), ".0") || !strcmp((X), ".00") || !strcmp((X), "0.") || \!strcmp((X), ".")if (check_zero_yuan(aInput)) {apd1("零圆整");return o_chn;}// PART0 ==== 准备阶段 ====enum {//定义FSM(有限状态机)的状态BEGIN = 0, //起始位MINUS,//负号位ZEROPRE, //前缀零(格式 0.XX 或 -0.XX)INTEGER, //整数位FST_MAX} state = BEGIN;/*** 下面的变量定义初始化成NULL至关重要* 关系着某些位置是否存在,若是一直是NULL则表示某个位置是不存在的**/typedef char *pos_t;pos_t szInput = strdup(aInput);pos_t pDecBgn = NULL;pos_t pMinus = NULL;/** 将it 与 pIntBgn 同时指向输入的金额串的开头 */pos_t pIntBgn = szInput;pos_t it = szInput; //(it是遍历指针,iterator的缩写)// PART1 ====使用状态机解析金额串,若是有格式错误 则会报错并返回 ====do {int ecode = -1;switch (*it) {case '-': // CLASS0: 当前字符是负号(-)/**负号在最开头才算是合法的*/if (BEGIN == state) {pMinus = it;/**将整数部分的开头后移一位(以保证整数部分只包含数字)*/pIntBgn++;/** 状态更新为 MINUS */state = MINUS;} else {/**说明在非开头位置又遇见了负号,格式错误序号设置成*/ecode = 0;}break;case '.': // CLASS1: 当前字符是小数点if (NULL == pDecBgn) {/**后面的一位就是小数部分的起始位置当前置为 \0 以保证整数部分结束了 */pDecBgn = it + 1, *it = '\0';/**负号位状态(-.XXX) 或 起始位状态(.XXX) 时 优化掉整数转换部分 */if (MINUS == state || BEGIN == state) {pIntBgn = NULL; //更新 pIntBgn 为 NULL}} else {/**已经在小数位状态, 再一次遇见小数点*/ecode = 1;}break;case '0' ... '9': // CLASS2: 当前字符是数字符号if (it[0] == '0') {switch (state) {case ZEROPRE:/** 在处于有前缀0的状态下又碰见一个0字符 */ecode = 2;break;case BEGIN:/** 起始位置状态下 进入 前缀零模式 */state = ZEROPRE;break;default:state = INTEGER;}} else { //其他均转化为 数字符号状态state = INTEGER;}break;default:// CLASS3: 当前字符是除 负号,小数点,数字字符 之外的其他字符ecode = 3;}if (ecode != -1) {free(szInput);return CZ_ERR[ecode];}// it后移一位,为进行下一轮判断做准备it++;} while (*it); // 当it到达szInput的末尾就退出循环// PART2 ==== 进行转换 ====//有负号if (pMinus) {apd1(CU_DEC[0]);}//====转换整数部分 ====if (pIntBgn && pIntBgn[0] != '0') {char *t_ops = o_chn;it = pIntBgn; //将it重置到整数部分的开头#define chkback1 (it - pIntBgn > 1 && it[-1] == '0')#define chkback2 \(it - pIntBgn > 2 && (it[-1] == '0' || 0 == strncmp(it - 2, "00", 2)))#define chkback3 \(it - pIntBgn > 3 && (it[-1] == '0' || 0 == strncmp(it - 2, "00", 2) ||\0 == strncmp(it - 3, "000", 3)))//有整数部分并且以非零开头才需要进行转换int w = strlen(it);int an = 0, r = 0;pos_t cu = NULL;do {r = w % 4;cu = CU_INT[w];an = it[0] & 0xF; //<==> it[0] - '0', 输入的数字字符转换成对应的数字//根据位数判断if (an) {// value is none-zeroswitch (r) {case 0:if (0 == strncmp(it - 4, "0000", 4)) {apd1(CN[0]);}apd2(CN[an], cu);break;case 3:if (chkback1) {apd1(CN[0]);}apd2(CN[an], cu);break;case 2:if (chkback2) {apd1(CN[0]);}apd2(CN[an], cu);break;case 1:// printf("@@@ AAA @@@\n");if (chkback3) {apd1(CN[0]);}apd2(CN[an], cu);break;}} else {//只判断 r==1 时的场景if (r == 1) {if (w == 1) {apd1(cu);} else {if (strncmp(it - 3, "0000", 4)) {apd1(cu);}}}}// printf("w:%2d, r:%d, i_cur:%s, out:%s,\n", w, r, it, o_chn);// it每向后移一位,权位降一级it++, w--;} while (*it);}//====转换小数部分 ====#define check_no_dec \!pDecBgn || *pDecBgn == '\0' ||\(pDecBgn[0] == '0' && (pDecBgn[1] == '0' || pDecBgn[1] == '\0'))if (check_no_dec) {//直接打印"XX圆整"apd1(CU_INT[0]);} else { //至少有一位小数int nJiao = pDecBgn[0] & 0xF;int nFen = -1;if (pDecBgn[1] != '\0') {nFen = pDecBgn[1] & 0xF;}apd1(CN[nJiao]);if (nJiao) {apd1(CU_DEC[1]);}if (nFen >= 1) {apd1(CN[nFen]);apd1(CU_DEC[2]);}}free(szInput);return o_chn;}

3. 测试结果

截图1:

# ./a2c 1001000088080.01 8049307164110.12 12---- 阿拉伯数字转化成中文金额字符串(小数部分仅保留到分) ----1001000088080.01 --> 壹兆零壹拾億零捌萬捌仟零捌拾圆零壹分8049307164110.12 --> 捌兆零肆佰玖拾叁億零柒佰壹拾陆萬肆仟壹佰壹拾圆壹角贰分1000000000 --> 壹拾億圆整

截图2

# ./a2c 1,0010,0008,8080.01 80,493,071,641,101.12 12.10 332.00 | awk '{printf("%20s --> %s\n",$1,$3)}'---- 阿拉伯数字转化成中文金额字符串(小数部分仅保留到分) ----1001000088080.01 --> 壹兆零壹拾億零捌萬捌仟零捌拾圆零壹分80493071641101.12 --> 捌拾兆肆仟玖佰叁拾億柒仟壹佰陆拾肆萬壹仟壹佰零壹圆壹角贰分12.10 --> 壹拾贰圆壹角332.00 --> 叁佰叁拾贰圆整

截图3

# ./a2c -.12 0.0 .00 .0 -0.20 9.0 .19 | awk '{printf("%10s --> %s\n",$1,$3)}'-- 阿拉伯数字转化成中文金额字符串(小数部分仅保留到分) ---.12 --> 负壹角贰份0.0 --> 零圆整.00 --> 零圆整.0 --> 零圆整-0.20 --> 负贰角9.0 --> 玖圆整.19 --> 壹角玖份

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。