首页 > 编程资源分享区 > C/C++源代码共享 > 小写金额转换为大写金额(C实现)
2006
12-08

小写金额转换为大写金额(C实现)

银行、单位和个人填写的各种票据和结算凭证是办理支付结算和现金收付的重要依据,直接关系到支付结算的准确、及时和安全。票据和结算凭证是银行、单位和个人凭以记载帐务的会计凭证,是记载经济业务和明确经济责任的一种书面证明。因此,填写票据和结算凭证,必须做到标准化、规范化,要要素齐全、数字正确、字迹清晰、不错漏、不潦草,防止涂改。



  我的服务需要一个金额转换过程,本来想在网上找,但都是C++JavaScriptDelphiDemo,还没有C的。索性自己写一个。参考了其它的转换算法,对我有些启发。




  大多的算法都是直接分析字符串生成大写金额,即存在一个假设:源字符串的格式是正确的。在我的过程中,用状态机的方法分析源字符串,错误时,返回空指针(我可不敢保证传给我的过程的都是##.##)。 分析出源字符串中整数部有多少个数字,是否有小数,统计结果放在一个结构体中,整数和小数部分的数字分别放在两个整形数组里。




  有了统计数据就可以生成大写金额了。转换过程有个难点:要区分万、亿等,特别是个位这个,这个概念是在《小写转大写金额在C++中的实现》文章中提到的。在下面的程序中用j= ( size – i – 1 ) & 0×3,实际上是j = ( size - i – 1 ) % 4取模,j==0时为段尾,需要特殊处理。所有的处理都是围绕0来进行的,也就是说,0才是难点。




  特殊位置的0,按段分,段中第一个非0数字前的0,可能有多个;段中两个非0数字间的0;段尾的0;个位的0;十分位,角位置的0




  另外,转换的一个重点是大写金额的写法,好像大多的算法都注重转换过程而对这个问题没有深究。我在文章后面附上转换规则。




下面是代码







/**
 * @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\n”, 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 & 0×3;                              //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-Mailz_jingwei@163.com




参考: 小写转大写金额在C++中的实现




附:



正确填写票据和结算凭证的基本规定



银行、单位和个人填写的各种票据和结算凭证是办理支付结算和现金收付的重要依据,直接关系到支付结算的准确、及时和安全。票据和结算凭证是银行、单位和个人凭以记载帐务的会计凭证,是记载经济业务和明确经济责任的一种书面证明。因此,填写票据和结算凭证,必须做到标准化、规范化,要要素齐全、数字正确、字迹清晰、不错漏、不潦草,防止涂改。




一、 中文大写金额数字应用正楷或行书填写,如壹()、贰()、叁、肆()、伍()、陆()、柒、捌、玖、拾、伯、仟、万()、亿、元、角、分、零、整()等字样。不得用一、二()、三、四、五、六、七、八、九、十、念、毛、另(0)填写,不得自造简化字。如果金额数字书写中使用繁体字,也应受理。




二、 中文大写金额数字到为止的,在之后,应写“(“)字,在之后可以不写“(“)字。数字有的,后面不写“(“)字。




三、 中文大写金额数字前应标明人民币字样,大写金额数字应紧接人民币字样填写,不得留有空白。大写金额数字前未印人民币字样的,应加填人民币三字。在票据和结算凭证大写金额栏内不得预印固定的仟、佰、拾、万、仟、佰、拾、元、角、分字样。




四、阿拉伯小写金额数字中有“0″时,中文大写应按照汉语语言规律、金额数字构成和防止涂改的要求进行书写。举例如下:




()阿拉伯数字中间有“0″时,中文大写金额要写字。如¥140950,应写成人民币壹仟肆佰零玖元伍角。
(
)阿拉伯数字中间连续有几个“0″时,中文大写金额中间可以只写一个字。如¥600714,应写成人民币陆仟零柒元壹角肆分。
(
)阿拉伯金额数字万位或元位是“0″,或者数字中间连续有几个“0″,万位、元位也是“0″,但千位、角位不是“0″时,中文大写金额中可以只写一个零字,也可以不写字。如¥168032,应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分;又如¥10700053,应写成人民币壹拾万柒仟元零伍角叁分,或者写成人民币壹拾万零柒仟元伍角叁分。
(
)阿拉伯金额数字角位是“0″,而分位不是“0″时,中文大写金额后面应写字。如¥1640902,应写成人民币壹万陆仟肆佰零玖元零贰分;又如¥32504,应写成人民币叁佰贰拾伍元零肆分。




五、阿拉伯小写金额数字前面,均应填写人民币符号“(或草写)。阿拉伯小写金额数字要认真填写,不得连写分辨不清。




六、票据的出票日期必须使用中文大写。为防止变造票据的出票日期,在填写月、日时,月为壹、贰和壹拾的,日为壹至玖和壹拾、贰拾和叁拾的,应在其前加; 日为拾壹至拾玖的,应在其前加。如115,应写成零壹月壹拾伍日。再如1020,应写成零壹拾月零贰拾日。




七、票据出票日期使用小写填写的,银行不予受理。大写日期未按要求规范填写的,银行可予受理,但由此造成损失的,由出票人自行承担。


小写金额转换为大写金额(C实现)》有 2 条评论

  1. zouyf315 说:

    测试总是输出null

  2. VC爱好者 说:

    网上转的.如果有错误.自己修改一下吧..不保证源代码的正确性

留下一个回复