关键字:C、金额转换、小写、大写、中文大写金额数字
作者:张经纬 2005-08-02
小写金额转换为大写金额(C实现)
用C实现的小写金额转换大写金额的方法。网上C实现的转换很少,其它的实现也很少有做到分析源字符串格式的功能。另附《正确填写票据和结算凭证的基本规定》
银行、单位和个人填写的各种票据和结算凭证是办理支付结算和现金收付的重要依据,直接关系到支付结算的准确、及时和安全。票据和结算凭证是银行、单位和个人凭以记载帐务的会计凭证,是记载经济业务和明确经济责任的一种书面证明。因此,填写票据和结算凭证,必须做到标准化、规范化,要要素齐全、数字正确、字迹清晰、不错漏、不潦草,防止涂改。
我的服务需要一个金额转换过程,在网上找了一些,都是C++、JavaScript、Delphi的Demo,还没有C的。索性自己写一个。参考了其它的转换算法,对我有些启发。
大多的算法都是直接分析字符串生成大写金额,即存在一个假设:源字符串的格式是正确的。在我的过程中,用状态机的方法分析源字符串,错误时,返回空指针(我可不敢保证传给我的过程的都是##.##)。 分析出源字符串中整数部有多少个数字,是否有小数,统计结果放在一个结构体中,整数和小数部分的数字分别放在两个整形数组里。
有了统计数据就可以生成大写金额了。转换过程有个难点:要区分万、亿等“段”,特别是个位这个“段”,这个概念是在《小写转大写金额在C++中的实现》文章中提到的。在下面的程序中用j=(size-i-1)&0x3,实际上是j=(size-i-1)%4取模,j==0时为段尾,需要特殊处理。所有的处理都是围绕0来进行的,也就是说,0才是难点。
特殊位置的0,按段分,段中第一个非0数字前的0,可能有多个;段中两个非0数字间的0;段尾的0;个位的0;十分位,角位置的0。
另外,转换的一个重点是大写金额的写法,好像大多的算法都注重转换过程而对这个问题没有深究。我在文章后面附上转换规则。
有一点,从低耦合的角度说,这个过程应该再细分一下。输入可以是标准格式的字符串或数字,验证的过程可以放到另一个模块中。我就不再分了,总体上,while语句整体是格式分析过程,可以单独拿出来。后面的代码是生成大写读法。需要的自己处理下吧,很简单。
下面是代码
/** * @brief 将源字符串中的小写金额转换为大写格式 * * @param dest 目的字符串 * @param src 小写金额字符串 * @return * - NULL 源字符串的格式错误,返回NULL * - 非NULL 目的字符串的首地址 * @note 转换根据:中国人民银行会计司编写的最新《企业、银行正确办理支付结算 * 指南》的第114页-第115页 */ char* chineseFee( char* dest, char* src ) { enum { START, //开始 MINUS, //负号 ZEROINT, //0整数 INTEGER, //整数 DECIMAL, //小数点 DECIMALfRACTION, //小数位 END, //结束 ERROR //错误 } status = START; struct { int minus; //0为正,1为负 int sizeInt; int sizeDecimal; int integer[10]; int decimal[10]; } feeInfo; char* NumberChar[] = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; char* UnitChar[] = { "整", "圆", "拾", "佰","仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万亿", "拾", "佰", "仟", "亿亿", "角", "分", "负", "人民币" }; int i, j,size; //循环变量 int zeroTag = 0, //0标志 decZeroTag = 0; char* pDest = dest; char* pSrc = src; int* pInt = feeInfo.integer; int* pDec = feeInfo.decimal; //初始化 feeInfo.sizeInt = 0; feeInfo.sizeDecimal = 0; feeInfo.minus = 0; //分析字符串 while( 1 ) { switch ( *pSrc ) { case '-' : status = ( status == START ) ? MINUS : ERROR; feeInfo.minus = ( status == MINUS ) ? 1 : 0; break; case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : case '0' : if ( *pSrc == '0' && status == ZEROINT )//|| status == START ) ) { status = ERROR; break; } if ( status == MINUS || status == START || status == INTEGER ) { if ( *pSrc == '0' && ( status == MINUS || status == START ) ) status = ZEROINT; else status = INTEGER; *pInt = (*pSrc) - 48; ++pInt; ++feeInfo.sizeInt; } else if ( status == DECIMAL || status == DECIMALfRACTION ) { status = DECIMALfRACTION; *pDec = (*pSrc) - 48; ++pDec; ++feeInfo.sizeDecimal; } else { status =ERROR; } break; case '.' : status = ( status == INTEGER || status == ZEROINT ) ? DECIMAL : ERROR; break; case '' : status = ( status == INTEGER || status == DECIMALfRACTION || status == ZEROINT ) ? END : ERROR; break; default : status = ERROR; } if ( status == END ) break; else if ( status == ERROR ) return NULL; ++pSrc; } //只有1位小数时,设置百分位为0,使下面代码不需要区分这两种情况 if ( feeInfo.sizeDecimal == 1 ) { feeInfo.decimal[ 1 ] = 0; ++feeInfo.sizeDecimal; } //判断是否需要打印小数部分,有小数部且十分位和百分位不都为0 //需要打印小数部时,zeroTag设为0,否则设为1 if ( feeInfo.sizeDecimal == 0 //没有小数 || ( !feeInfo.decimal[ 0 ] && !feeInfo.decimal[ 1 ] ) ) //小数部都为0 decZeroTag = 1; else decZeroTag = 0; //printf( "int size: %d decimal size: %d ", feeInfo.sizeInt, feeInfo.sizeDecimal ); strcpy( pDest, UnitChar[ 21 ] ); //初始化目标字符串-人民币 if ( feeInfo.minus ) strcat( pDest, UnitChar[ 20 ] ); //负号 //处理整数部分 size = feeInfo.sizeInt; for( i = 0; i < size; ++i ) { j = size - i - 1 & 0x3; //j = 0时为段尾 if ( feeInfo.integer[ i ] == 0 && j ) //处理非段尾0 { zeroTag = 1; } else if ( feeInfo.integer[ i ] == 0 && !j ) //处理段尾0 { if ( feeInfo.sizeInt == 1 && decZeroTag ) //特殊处理个位0 strcat( pDest, NumberChar[ feeInfo.integer[ i ] ] ); if ( feeInfo.sizeInt != 1 || decZeroTag ) strcat( pDest, UnitChar[ size - i ] ); zeroTag = 0; } else //处理非0 { if ( zeroTag ) { strcat( pDest, NumberChar[ 0 ] ); zeroTag = 0; } strcat( pDest, NumberChar[ feeInfo.integer[ i ] ] ); strcat( pDest, UnitChar[ size - i ] ); if ( !j ) zeroTag = 0; //如果是段尾,设为非标志 } } if ( decZeroTag ) { strcat( pDest, UnitChar[ 0 ] );//没有小数部,打印"整"字符 } else { //十分位 if ( feeInfo.decimal[ 0 ] ) { strcat( pDest, NumberChar[ feeInfo.decimal[ 0 ] ] ); strcat( pDest, UnitChar[ 18 ] ); } else if ( feeInfo.sizeInt != 1 || feeInfo.integer[ 0 ] ) { strcat( pDest, NumberChar[ feeInfo.decimal[ 0 ] ] ); } //百分位不为0时 if ( feeInfo.decimal[ 1 ] ) { strcat( pDest, NumberChar[ feeInfo.decimal[ 1 ] ] ); strcat( pDest, UnitChar[ 19 ] ); } } return dest; } |
代码中有些地方没有注释清楚,要是有不明白的可以E-Mail我z_jingwei@163.com。
参考:
小写转大写金额在C++中的实现
附:
正确填写票据和结算凭证的基本规定
银行、单位和个人填写的各种票据和结算凭证是办理支付结算和现金收付的重要依据,直接关系到支付结算的准确、及时和安全。票据和结算凭证是银行、单位和个人凭以记载帐务的会计凭证,是记载经济业务和明确经济责任的一种书面证明。因此,填写票据和结算凭证,必须做到标准化、规范化,要要素齐全、数字正确、字迹清晰、不错漏、不潦草,防止涂改。
一、 中文大写金额数字应用正楷或行书填写,如壹(壹)、贰(贰)、叁、肆(肆)、伍(伍)、陆(陆)、柒、捌、玖、拾、伯、仟、万(万)、亿、元、角、分、零、整(正)等字样。不得用一、二(两)、三、四、五、六、七、八、九、十、念、毛、另(或0)填写,不得自造简化字。如果金额数字书写中使用繁体字,也应受理。
二、 中文大写金额数字到"元"为止的,在"元"之后,应写"整"(或"正")字,在"角"之后可以不写"整"(或"正")字。数字有"分"的,"分"后面不写"整"(或"正")字。
三、 中文大写金额数字前应标明"人民币"字样,大写金额数字应紧接"人民币"字样填写,不得留有空白。大写金额数字前未印"人民币"字样的,应加填"人民币"三字。在票据和结算凭证大写金额栏内不得预印固定的"仟、佰、拾、万、仟、佰、拾、元、角、?quot;字样。
四、阿拉伯小写金额数字中有"0"时,中文大写应按照汉语语言规律、金额数字构成和防止涂改的要求进行书写。举例如下:
(一)阿拉伯数字中间有"0"时,中文大写金额要写"零"字。如¥1,409.50,应写成人民币壹仟肆佰零玖元伍角。
(二)阿拉伯数字中间连续有几个"0"时,中文大写金额中间可以只写一个"零"字。如¥6,007.14,应写成人民币陆仟零柒元壹角肆分。
(三)阿拉伯金额数字万位或元位是"0",或者数字中间连续有几个"0",万位、元位也是"0",但千位、角位不是"0"时,中文大写金额中可以只写一个零字,也可以不写"零"字。如¥1,680.32,应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分;又如¥107,000.53,应写成人民币壹拾万柒仟元零伍角叁分,或者写成人民币壹拾万零柒仟元伍角叁分。
(四)阿拉伯金额数字角位是"0",而分位不是"0"时,中文大写金额"元"后面应写"零"字。如¥16,409.02,应写成人民币壹万陆仟肆佰零玖元零贰分;又如¥325.04,应写成人民币叁佰贰拾伍元零肆分。
五、阿拉伯小写金额数字前面,均应填写人民币符号"¥"(或草写)。阿拉伯小写金额数字要认真填写,不得连写分辨不清。
六、票据的出票日期必须使用中文大写。为防止变造票据的出票日期,在填写月、日时,月为壹、贰和壹拾的,日为壹至玖和壹拾、贰拾和叁拾的,应在其前加"零"; 日为拾壹至拾玖的,应在其前加"壹"。如 1月 15日 ,应写成零壹月壹拾伍日。再如 10月 20日 ,应写成零壹拾月零贰拾日。
七、票据出票日期使用小写填写的,银行不予受理。大写日期未按要求规范填写的,银行可予受理,但由此造成损失的,由出票人自行承担。
引自中国人民银行会计司编写的最新《企业、银行正确办理支付结算指南》的第114页-第115页
阅读(2322) | 评论(2) | 转发(0) |
0 上一篇:Pro*C介绍-内嵌SQL
下一篇:TUXEDO与ORACLE数据库的互连
相关热门文章
- OA办公系统的设计与实现...
- TCP状态转变即FSM模拟实现...
- 零费用学习网络营销,小伙伴们...
- diamond专题(四)—— 容灾机...
- TDDL动态数据源基本说明...
- test123
- 编写安全代码——小心有符号数...
- 使用openssl api进行加密解密...
- 一段自己打印自己的c程序...
- sql relay的c++接口
- 最近要做web图表开发,涉及美...
- PHP扩展编译错误 如何解决...
- memcache客户端报错
- 如何对关系型数据库进行性能优...
- 请教数据库的性能测试一般主要...
给主人留下些什么吧!~~
z_jingwei2011-09-01 18:28:55
这段是05年写的,刚毕业没多久~~所以难免有点问题,见谅!
这几年不断有朋友反馈给我信息,现在知道的是超大金额(超过10亿)的处理上有BUG,所以使用的朋友需要小心。当时可能是没考虑到
另外,当时想用状态机的方法去实现,但在理解上有点偏差,所以...希望能提供一个思路吧
不知道什么时候能有机会把这段代码完善一下,有朋友提些建议也好,或者发一个新版本出来
回复 | 举报
chinaunix网友2011-06-18 00:30:44
话说哥们,你这代码写得很难懂,其实处理处理非小数部分可以0-10000来处理,只是每段的单位不一样,比如元,万元,亿元。整个函数那么大,实在看得头大.....
回复 | 举报 评论热议
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!