- 論壇徽章:
- 0
|
(轉(zhuǎn))小寫金額轉(zhuǎn)換為大寫金額(C實(shí)現(xiàn))
大多的算法都是直接分析字符串生成大寫金額,即存在一個(gè)假設(shè):源字符串的格式是正確的。在我的過程中,用狀態(tài)機(jī)的方法分析源字符串,錯(cuò)誤時(shí),返回空指針(我可不敢保證傳給我的過程的都是##.##)。 分析出源字符串中整數(shù)部有多少個(gè)數(shù)字,是否有小數(shù),統(tǒng)計(jì)結(jié)果放在一個(gè)結(jié)構(gòu)體中,整數(shù)和小數(shù)部分的數(shù)字分別放在兩個(gè)整形數(shù)組里。
有了統(tǒng)計(jì)數(shù)據(jù)就可以生成大寫金額了。轉(zhuǎn)換過程有個(gè)難點(diǎn):要區(qū)分萬、億等“段”,特別是個(gè)位這個(gè)“段”,這個(gè)概念是在《小寫轉(zhuǎn)大寫金額在C++中的實(shí)現(xiàn)》文章中提到的。在下面的程序中用j=(size-i-1)&0x3,實(shí)際上是j=(size-i-1)%4取模,j==0時(shí)為段尾,需要特殊處理。所有的處理都是圍繞0來進(jìn)行的,也就是說,0才是難點(diǎn)。
特殊位置的0,按段分,段中第一個(gè)非0數(shù)字前的0,可能有多個(gè);段中兩個(gè)非0數(shù)字間的0;段尾的0;個(gè)位的0;十分位,角位置的0。
另外,轉(zhuǎn)換的一個(gè)重點(diǎn)是大寫金額的寫法,好像大多的算法都注重轉(zhuǎn)換過程而對(duì)這個(gè)問題沒有深究。我在文章后面附上轉(zhuǎn)換規(guī)則。
有一點(diǎn),從低耦合的角度說,這個(gè)過程應(yīng)該再細(xì)分一下。輸入可以是標(biāo)準(zhǔn)格式的字符串或數(shù)字,驗(yàn)證的過程可以放到另一個(gè)模塊中。我就不再分了,總體上,while語句整體是格式分析過程,可以單獨(dú)拿出來。后面的代碼是生成大寫讀法。需要的自己處理下吧,很簡(jiǎn)單。
下面是代碼
- /**
- * @brief 將源字符串中的小寫金額轉(zhuǎn)換為大寫格式
- *
- * @param dest 目的字符串
- * @param src 小寫金額字符串
- * @return
- * - NULL 源字符串的格式錯(cuò)誤,返回NULL
- * - 非NULL 目的字符串的首地址
- * @note 轉(zhuǎn)換根據(jù):中國(guó)人民銀行會(huì)計(jì)司編寫的最新《企業(yè)、銀行正確辦理支付結(jié)算
- * 指南》的第114頁-第115頁
- */
- char* chineseFee( char* dest, char* src )
- {
- enum
- {
- START, //開始
- MINUS, //負(fù)號(hào)
- ZEROINT, //0整數(shù)
- INTEGER, //整數(shù)
- DECIMAL, //小數(shù)點(diǎn)
- DECIMALfRACTION, //小數(shù)位
- END, //結(jié)束
- ERROR //錯(cuò)誤
- } status = START;
- struct
- {
- int minus; //0為正,1為負(fù)
- int sizeInt;
- int sizeDecimal;
- int integer[10];
- int decimal[10];
- } feeInfo;
- char* NumberChar[] =
- { "零", "壹", "貳", "叁", "肆", "伍", "陸", "柒", "捌", "玖" };
- char* UnitChar[] =
- { "整", "圓", "拾", "佰","仟", "萬", "拾", "佰", "仟", "億",
- "拾", "佰", "仟", "萬億", "拾", "佰", "仟", "億億",
- "角", "分", "負(fù)", "人民幣" };
-
- int i, j,size; //循環(huán)變量
- int zeroTag = 0, //0標(biāo)志
- 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位小數(shù)時(shí),設(shè)置百分位為0,使下面代碼不需要區(qū)分這兩種情況
- if ( feeInfo.sizeDecimal == 1 )
- {
- feeInfo.decimal[ 1 ] = 0;
- ++feeInfo.sizeDecimal;
- }
- //判斷是否需要打印小數(shù)部分,有小數(shù)部且十分位和百分位不都為0
- //需要打印小數(shù)部時(shí),zeroTag設(shè)為0,否則設(shè)為1
- if ( feeInfo.sizeDecimal == 0 //沒有小數(shù)
- || ( !feeInfo.decimal[ 0 ] && !feeInfo.decimal[ 1 ] ) ) //小數(shù)部都為0
- decZeroTag = 1;
- else
- decZeroTag = 0;
-
- //printf( "int size: %d decimal size: %d ", feeInfo.sizeInt, feeInfo.sizeDecimal );
-
- strcpy( pDest, UnitChar[ 21 ] ); //初始化目標(biāo)字符串-人民幣
-
- if ( feeInfo.minus ) strcat( pDest, UnitChar[ 20 ] ); //負(fù)號(hào)
-
- //處理整數(shù)部分
- size = feeInfo.sizeInt;
- for( i = 0; i < size; ++i )
- {
- j = size - i - 1 & 0x3; //j = 0時(shí)為段尾
- if ( feeInfo.integer[ i ] == 0 && j ) //處理非段尾0
- {
- zeroTag = 1;
- }
- else if ( feeInfo.integer[ i ] == 0 && !j ) //處理段尾0
- {
- if ( feeInfo.sizeInt == 1 && decZeroTag ) //特殊處理個(gè)位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; //如果是段尾,設(shè)為非標(biāo)志
- }
- }
-
- if ( decZeroTag )
- {
- strcat( pDest, UnitChar[ 0 ] );//沒有小數(shù)部,打印"整"字符
- }
- 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時(shí)
- if ( feeInfo.decimal[ 1 ] )
- {
- strcat( pDest, NumberChar[ feeInfo.decimal[ 1 ] ] );
- strcat( pDest, UnitChar[ 19 ] );
- }
- }
- return dest;
- }
復(fù)制代碼 |
|