标题: [共同参与][挑战思路]批处理实现数字金额转大写
[打印本页]
作者: 无奈何
时间: 2007-1-1 05:58
标题: [共同参与][挑战思路]批处理实现数字金额转大写
看到坛子里越来越多关于挑战批处理算法的讨论,也涌现出一批热衷于挖掘批处理潜能的兄弟,一些批处理不太适合的工作,也渐由批处理来完成,我很是高兴。
现拟一题目--数字金额转大写,这个议题在网上几乎可以找到任何流行语言的版本,唯独缺少批处理版的,这个问题当然不能指望老外来做,然后我们再借鉴 ^_^。
规则如下:
1、接收一串金额数字,转为大写,可能出现的合理格式
为 5821564130 或 5821564.130 或 5,821,564.130 等,
不会出现格式为 58.215.64.130 等小数位不明的数字或其他非金额数字字符。
2、最大位到千亿即可,最小位到分其后忽略。
3、CMD下纯批处理完成,不使用第三方工具。
4、具体转换依据见附录。
附录:
Quote: |
正确填写票据和结算凭证的基本规定
银行、单位和个人填写的各种票据和结算凭证是办理支付结算和现金收付的重要依据,直接关系到支付结算的准确、及时和安全。票据和结算凭证是银行、单位和个人凭以记载帐务的会计凭证,是记载经济业务和明确经济责任的一种书面证书。因此,填写票据和结算凭证,必须做到标准化、规范化,要要素齐全、数字正确、字迹清晰、不错漏、不潦草,防止涂改。
一、中文大写金额数字应用正楷或行书填写,如壹(壹)、贰(貳)、叁(參)、肆(肆)、伍(伍)、陆(陸)、柒、捌、玖、拾、佰、仟、万(萬)、亿、元、角、分、零、整(正)等字样。不得用一、二(两)、三、四、五、六、七、八、九、十、念、毛、另(或0)填写,不得自造简化字。如果金额数字书写中使用繁体字,如贰、陆、亿、万、圆的,也应受理。
二、中文大写金额数字到“元”为止的,在“元”之后,应写“整”(或“正”)字,在“角”之后可以不写“整”(或“正”)字。大写金额数字有“分”的,“分”后面不写“整”(或“正”)字。
三、中文大写金额数字前应标明“人民币”字样,大写金额数字有“分”的,“分”后面不写“整”(或“正”)字。
四、中文大写金额数字前应标明“人民币”字样,大写金额数字应紧接“人民币”字样填写,不得留有空白。大写金额数字前未印“人民币”字样的,应加填“人民币”三字。在票据和结算凭证大写金额栏内不得预印固定的“仟、佰、拾、万、仟、佰、拾、元、角、分”字样。
五、阿拉伯小写金额数字中有“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 │
├─┼─┼─┼───┤
│二│贰│貳│ 2 │
├─┼─┼─┼───┤
│三│叁│叄│ 3 │
├─┼─┼─┼───┤
│四│肆│肆│ 4 │
├─┼─┼─┼───┤
│五│伍│伍│ 5 │
├─┼─┼─┼───┤
│六│陆│陸│ 6 │
├─┼─┼─┼───┤
│七│柒│柒│ 7 │
├─┼─┼─┼───┤
│八│捌│捌│ 8 │
├─┼─┼─┼───┤
│九│玖│玖│ 9 │
├─┼─┼─┼───┤
│十│十│拾│ 10 │
├─┼─┼─┼───┤
│百│佰│佰│ 100 │
├─┼─┼─┼───┤
│千│仟│仟│ 1000 │
├─┼─┼─┼───┤
│万│万│萬│ 10^4 │
├─┼─┼─┼───┤
│亿│亿│億│ 10^8 │
├─┼─┼─┼───┤
│兆│兆│兆│ 10^12│
└─┴─┴─┴───┘
详见:
http://wiki.keyin.cn/index.php?t ... 7&variant=zh-cn
作者: youxi01
时间: 2007-1-1 12:02
写了一段到头来连自己都“看不懂”的代码:
::code by youxi01@cn-dos.net
::date 2006-1-1(Happy new year!best wishes to everyone!)
@echo off
setlocal enabledelayedexpansion
set /a a=0,b=0,c=0
::================================
::设置单位名称;
SET NAME0=仟
SET NAME1=佰
SET NAME2=拾
SET NAME3=
::================================
::=============================================
::设置数字对应的大写中文汉字
for %%i in (零 壹 贰 叁 肆 伍 陆 柒 捌 玖) do (
set BIG!a!=%%i
set /a a+=1)
::=============================================
::=======================================================================
::在以下“函数”的处理过程中,要用到"#"对数字进行对齐(都成四位),以便截取;
::这里设置凡是出现"#"的地方都设置为空。
set BIG#=
::=======================================================================
set EN=
::====================================================
::这里对输入的数字进行处理,分别取出整数部分和小数部分;
set /p EN=请输入金钱数(1000亿以内):
for /f "tokens=1,2* delims=." %%i in ("%EN%") do (
set "round=%%i"
set "dec=%%j00" 2>nul)
::=====================================================
set /a round=%round:,=%
set dec=%dec:~0,2%
:test
set /a b+=1
::=============================================
::每四位数字为一组,对原来的数据进行截取;
if %round% gtr 9999 (
set num!b!=!round:~-4!
set round=!round:~0,-4!
goto :test) else set num!b!=!round!
::==============================================
::=====================================================
::分别对1、2、3段数据进行处理;分别赋予单位:元、万、亿
::同时,分别将返回的数据传给str1,str2,str3(利用%3来控制)。
call :test1 %num1% 元 1
call :test1 %num2% 万 2
call :test1 %num3% 亿 3
::======================================================
::====================================================================
::去掉数字大写里多余的"零"。比如,1002,处理后读出来为:"壹千零贰元整"
::符合我们中国人一般的读数方法;同时将结果分别传入str1,str2,str3(%2控制)。
call :test2 %str1% 1
call :test2 %str2% 2
call :test2 %str3% 3
::=====================================================================
::==============================================================
::防止类似2,0000,1002.00形式出现错误(错误读为:2亿万1千零2元整)
if "!str2!"=="零万" set str2=零
::===============================================================
set str=%str3%%str2%%str1%
set str=%str:零元=元%
set str=%str:零万=万%
set str=%str:零亿=亿%
::防止整数部分为0;
if "%str%"=="元" set str=零元
::对小数部分数字进行处理;
if "%dec%"=="00" (set dec=整) else (
set /a dec1=!dec:~0,1!
set /a dec2=!dec:~1,1!
if !dec1! EQU 0 (set dec1=零) else call set dec1=%%BIG!dec1!%%角
if !dec2! EQU 0 (set dec2=) else call set dec2=%%BIG!dec2!%%分
set dec=!dec1!!dec2!
)
echo.
echo ========================
echo 你输入的金钱数目大写为:
echo.
echo %str:零零=零%%dec%
echo ========================
pause>nul
:test1
if not "%1"=="" (
set temp=####%1
set temp=!temp:~-4!
for /l %%i in (0 1 3) do (
set tmp%%i=!temp:~%%i,1!
if defined tmp%%i (
if !tmp%%i! GTR 0 (call set str%3=!str%3!%%BIG!tmp%%i!%%!NAME%%i!) else (
call set str%3=!str%3!%%BIG!tmp%%i!%%)))
set str%3=!str%3!%2
) else set str%3=
goto :eof
:test2
set tmp=%1
set tmp=%tmp:零零=零%
set str%2=%tmp:零零=零%
[
Last edited by youxi01 on 2007-1-1 at 11:04 PM ]
作者: tigerpower
时间: 2007-1-1 12:43
哈哈,厉害厉害!!!
去掉空行共63行,不是很长!!!
用纯粹的批处理能写出这样的程序,精彩!!!佩服!!!
美中不足有二:
1. "十"、"百"、"千"应为"拾"、"佰"、"仟",这是语文的问题,应该不算bug:)
2. 当输入是0.xx时好像有点问题。
作者: youxi01
时间: 2007-1-1 12:50
谢谢楼上的提醒,已更正!
作者: 无奈何
时间: 2007-1-1 12:54
RE youxi01
兄的代码转换效果非常不错。
初步测试,非常合乎规范要求,加分鼓励。
还有一点建议,帖完整功能的批处理时,推荐属上自己的名字与出处地址等,当多次转贴后,别人发现问题或想与作者交流时不因无处联系作者而苦恼,当然也会更好的保护你的劳动成果。推荐的格式为 作者@论坛 这样的形式,以上只是建议仅供参考。
RE tigerpower
零开头的数字,不为合理的金额,可以忽略,当然去除掉也不是很困难的事。
[
Last edited by 无奈何 on 2007-1-1 at 01:05 PM ]
作者: qzwqzw
时间: 2007-1-2 00:23
凑个热闹吧
采用分步替换的原则,一则简化算法,二则易于控制(比如零元——元零的替换)
特意将兆省略了,因为很少有如此多的人民币金额
而且对于京、兆之类的词汇有多种解释
很多时候一兆等于一百万(1M),也有时候一兆等于一亿亿
另外,有谁有兴趣编个反向转换算法?
以及相关的罗马数字与阿拉伯数字的相互转换?
:: 人民币金额小写转大写
:: qzwqzw@bbs.cn-dos.net
:: 2007-01-01
@echo off
setlocal EnableDelayedExpansion
set tbl1=零壹贰叁肆伍陆柒捌玖
set tbl2=分角元拾佰仟万拾佰仟亿拾佰仟
:test
setlocal
set /p num=请输入金额(小于一万亿元):
for /f "tokens=1,2 delims=." %%f in ("%num%") do (
set num2=%%g00
set num=%%f!num2:~0,2!
)
:loop
call set rmb=%%tbl1:~%num:~-1,1%,1%%%%tbl2:~%bit%,1%%%rmb%
set /a bit+=1
set num=%num:~0,-1%
if not "%num%"=="" goto loop
set rmb=%rmb:零拾=零%
set rmb=%rmb:零佰=零%
set rmb=%rmb:零仟=零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零元=元零%
set rmb=%rmb:零万=万零%
set rmb=%rmb:零亿=亿零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零分=零%
set rmb=%rmb:零角=零%
set rmb=%rmb:角零=角%
set rmb=%rmb:零零=整%
echo 人民币%rmb%
endlocal
goto test
[
Last edited by qzwqzw on 2007-1-1 at 11:29 AM ]
作者: 无奈何
时间: 2007-1-2 01:02
RE qzwqzw
兄的代码也同样非常出色,并且极其简洁。
金额中含有 “,” 时会出错,“,” 也为合理的金额字符,请稍加完善一下。
兆的概念中国传统和国际单位是不同的,中国传统为一万亿。
详情可以参考下一楼给出的链接。
[
Last edited by 无奈何 on 2007-1-2 at 01:10 AM ]
作者: qzwqzw
时间: 2007-1-2 01:28
加了一些验证代码,很影响代码的简洁,有些郁闷
可以通过带有前缀0的数字,含,的数字,以.前缀的小数
可以禁止含有非法字符的金额
-----------------------------------------------------------------
国际单位的量级是没有兆的,只有m/K/M等
最早是谁将M译为“兆”的已经很难考证
但现在已经很流行,某些会计学教材也开始采用
------------------------------------------------------------------------
至于中国传统的计数,你可以用“亿、兆、京、垓”百度一下
--------------------------------------------------------------------------
:: 人民币金额小写转大写
:: qzwqzw@bbs.cn-dos.net
:: 2007-01-01
@echo off
setlocal EnableDelayedExpansion
set tbl1=零壹贰叁肆伍陆柒捌玖
set tbl2=分角元拾佰仟万拾佰仟亿拾佰仟
:test
cls
setlocal
set /p num=请输入小写金额(小于一万亿元,直接回车退出):
if "%num%"=="" goto :eof
set num=%num:,=%
set num=0%num%
for /f "tokens=1,2,* delims=." %%f in ("%num%") do (
set num2=%%g00
set num=%%f!num2:~0,2!
if not "%%h"=="" goto :error
)
:del_pre0
if not "%num:~0,1%"=="0" goto checknum
set num=%num:~1%
goto del_pre0
:checknum
set /a num2=num+0
if "%num%"=="%num2%" goto loop
:error
echo.
echo 输入小写金额无效!
echo.
pause
goto test
:loop
call set rmb=%%tbl1:~%num:~-1,1%,1%%%%tbl2:~%bit%,1%%%rmb%
set /a bit+=1
set num=%num:~0,-1%
if not "%num%"=="" goto loop
set rmb=%rmb:零拾=零%
set rmb=%rmb:零佰=零%
set rmb=%rmb:零仟=零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零元=元零%
set rmb=%rmb:零万=万零%
set rmb=%rmb:零亿=亿零%
set rmb=%rmb:零零=零%
set rmb=%rmb:零分=零%
set rmb=%rmb:零角=零%
set rmb=%rmb:角零=角%
set rmb=%rmb:零零=整%
echo.
echo 人民币%rmb%
echo.
pause
endlocal
goto test
[
Last edited by qzwqzw on 2007-1-1 at 12:36 PM ]
作者: 无奈何
时间: 2007-1-2 12:54
RE qzwqzw
简单了解一下,传统的计数以十进制的。上面的表格称作现行通常用的好像比较合适。超大的数字也不太常用,仅当作趣闻知识吧。
作者: qzwqzw
时间: 2007-1-3 01:54
做了一个简单的阿拉伯数字转罗马数字的例子
考虑到规则的不统一和算法的复杂性,没有支持49->IL之类的转化
也没有支持超过4000的数字
反向转换相对困难一些
不过一旦建立了良好的数据结构,算法也就很清晰了
:: Arab2Roman 阿拉伯数字转为罗马数字
:: qzwqzw @ http://bbs.cn-dos.net
:: 2007-01-02 Revision 3
@echo off
setlocal EnableDelayedExpansion
:test
if "%~0"=="%~f0" cls
setlocal
set /p num=请输入阿拉伯数字num("0<num<4000",直接回车退出):
if "%num%"=="" goto :eof
:checknum
set /a tmp=num+0
if "%num%"=="%tmp%" if %num% lss 4000 if %num% gtr 0 goto Arab2Roman
:error
echo.
echo 无效的数字
echo.
if "%~0"=="%~f0" pause
endlocal
goto test
:Arab2Roman
set i=0
for %%v in (1000 900 500 400 100 90 50 40 10 9 5 4 1) do (
set /a i+=1
set arab!i!=%%v
)
set i=0
for %%v in (M CM D CD C XC L CL X IX V IV I) do (
set /a i+=1
set roman!i!=%%v
)
set i=1
:loop
call set tmp=%%arab%i%%%
if 1%num% lss 1%tmp% (
set /a i+=1
) else (
call set rom=%rom%%%roman%i%%%
set /a num-=tmp
)
if 1%num% gtr 10 goto loop
::Arab2Roman
echo.
echo %rom%
echo.
if "%~0"=="%~f0" pause
endlocal
goto test
[
Last edited by qzwqzw on 2007-1-2 at 01:17 PM ]
作者: HUNRYBECKY
时间: 2007-1-3 02:05
欣赏大作。
作者: tghksj
时间: 2007-1-3 03:26
怎么又是 qzwqzw
我现在快成了你的FANS了.
你出一段代码,就够我看个一两天的....
老样子加上两分,拿回家看...
作者: flamey
时间: 2007-1-3 04:51
qzwqzw~~~~利害!!!!!
作者: qzwqzw
时间: 2007-1-3 23:40
:: 阿拉伯与罗马数字互转程序
:: qzwqzw http://bbs.cn-dos.net
:: 2007-01-03 Revision 2
@echo off
setlocal EnableDelayedExpansion
for /l %%i in (1,1,100) do (
set /a numin=!random!*4200/32768-100
set in=!numin!
set out=
call :Arab2Roman
set in=!out!
call :Roman2Arab
echo.%%i [!numin!:!in!:!out!]
if !numin! neq !out! set /p=--- Invalid ---
)
pause
endlocal
goto :eof
:Arab2Roman
setlocal EnableDelayedExpansion
set num=%in%
set /a tmp=num+0
if not "%num%"=="%tmp%" goto :eof
if %num% geq 4000 goto :eof
if %num% leq 0 goto :eof
set i=0
for %%v in (1000 900 500 400 100 90 50 40 10 9 5 4 1) do (
set /a i+=1
set arab!i!=%%v
)
set i=0
for %%v in (M CM D CD C XC L XL X IX V IV I) do (
set /a i+=1
set roman!i!=%%v
)
set i=1
:a2r_loop
call set tmp=%%arab%i%%%
if 1%num% lss 1%tmp% (
set /a i+=1
) else (
call set rom=%rom%%%roman%i%%%
set /a num-=tmp
)
if 1%num% gtr 10 goto a2r_loop
endlocal & set out=%rom%
goto :eof
::Arab2Roman
:Roman2Arab
setlocal EnableDelayedExpansion
echo.%in%|findstr /r "[^IVXLCDMivxlcdm]">nul && goto :eof
set i=0
for %%v in (1000 900 500 400 100 90 50 40 10 9 5 4 1) do (
set /a i+=1
set arab!i!=%%v
)
set i=0
for %%v in (M 1 D 2 C 3 L 4 X 5 V 6 I) do (
set /a i+=1
set roman!i!=%%v
)
set in=%in:m=M%
set in=%in:d=D%
set in=%in:c=C%
set in=%in:l=L%
set in=%in:x=X%
set in=%in:v=V%
set in=%in:i=I%
set in=%in:CM=1%
set in=%in:CD=2%
set in=%in:XC=3%
set in=%in:XL=4%
set in=%in:IX=5%
set in=%in:IV=6%
set i=1
set num=0
:r2a_loop
set tmp=%in:~0,1%
call set rom1=%%roman%i%%%
if "%tmp%"=="%rom1%" (
call set /a num+=arab%i%
set in=%in:~1%
) else (
set /a i+=1
)
if %i% gtr 13 goto :eof
if not "%in%"=="" goto r2a_loop
endlocal & set out=%num%
goto :eof
::Roman2Arab
作者: namejm
时间: 2007-1-3 23:47
呵呵,qzwqzw 厉害。建议把各种类型的转换开成专帖发表,做到专帖专用,这样有利于日后的深入讨论和论坛的检索。
作者: vkill
时间: 2007-1-4 00:10
qzwqzw 兄的代码很好好
作者: 无奈何
时间: 2007-1-4 00:34
此主题的回帖越来越精彩了!
RE namejm
将相关的主题合并为一个帖子怎么样?然后修改一下标题,做一个集大成的超精彩的帖子,当然精彩部分不是来自楼主,而是一个强过一个的回帖。
作者: namejm
时间: 2007-1-4 00:51
RE 无奈何:
我觉得先做成分开的专题作深入的讨论,等待时机成熟之后,再行合并,然后,在顶楼对分类内容做个楼层索引,这样可能比较好一点,免得各个楼层的回帖内容缺乏连贯性,不方便后来者的深入探索——即使是这样,合并之后的主题仍有可能被后来者继续探讨下去,还是有缺乏连贯性的隐忧。
能不能这样:还是新开若干专帖,专帖专用,不合并帖子,只是在所有专帖的顶楼提供其他相关专帖的链接,不定期进行更新。如果讨论者觉得其他某些帖子和他的回帖相关,也可以提供链接。这样既保持了各个专题内容的连贯性,也能迅速找到相关的论题,有利于探讨的深入。
作者: 无奈何
时间: 2007-1-4 02:12
RE namejm
每种整理方案都不能尽善,合并会使主题大而杂不便检索;分割会使内容缺乏连贯性;新开专帖会造成冗余,并且打开后不能直观的看到帖子精彩讨论内容。
要不就按兄所说,新开帖做一下索引吧,等帖子冷却了再细化整理。麻烦兄辛苦一下了。
作者: caucfeiyu
时间: 2007-4-15 12:20
真的是很厉害啊,真是牛人啊!
作者: richercdw
时间: 2007-5-3 10:18
好爽的一个贴子...
作者: hxmupdata
时间: 2007-7-30 04:55
有意思哦
看了很多帖,这个有意思
作者: rockdong
时间: 2007-8-22 17:11
实在是太精彩了!
作者: bob1989
时间: 2007-8-25 22:39
完全没什么利用价值`
作者: finrod
时间: 2007-8-25 22:44
关注