中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [共同参与][挑战思路]中文数字阿拉伯化
作者:
标题: [共同参与][挑战思路]中文数字阿拉伯化 上一主题 | 下一主题
namejm
荣誉版主

batch fan


积分 5226
发帖 1737
注册 2006-3-10
来自 成都
状态 离线
『楼 主』:  [共同参与][挑战思路]中文数字阿拉伯化

  头两天,无奈何 兄提出了把小写的金额转化为大写的想法:[共同参与][挑战思路]批处理实现数字金额转大写,引来了不少高手,其中的解法让人大开眼界。

  qzwqzw 兄提出了逆向转换的想法,觉得很有意思,尝试着写了段代码,没有错误检测语句,也没有去做代码精简的工作,发出来让大家测试一下,也希望各位能提供不同的解法:
@echo off
:: Code by JM 2007-1-2~1-3 bbs.cn-dos.net CMD@XP
:: 中文形式数字转换为阿拉伯数字
:: 思路:
::   先把所有的中文数字转化为前后带空格的阿拉伯数字(零要特殊处理),
:: 然后,把阿拉伯数字从高位到低位逐一提取出来;提取的同时,对"零"做
:: 补位及替换处理,补位的具体规则为:比较"零"前后的进位,补足相应的0,
:: 比如:某个"零"的前后进位分别为"万"和"拾",则这个"零"则替换为两个
:: 连续的0。最后,把所有的空格去掉。

setlocal enabledelayedexpansion

set str=捌仟零叁拾万零柒佰零贰点零伍肆

echo.
echo           要处理的中文数值:%str%
echo --------------------------------------------------
:: 把中文数字转化为阿拉伯数字
for /f "tokens=1* delims=点" %%i in ("%str%") do set var1=%%i&set var2=%%j
call :replace_1 %var1%
set int=%var%
if not "%var2%"=="" (
    call :replace_1 %var2%
    set dec=!var:零=!
)
echo.
echo 中文数字阿拉伯化的结果1:%int%.%dec%
:: 提取阿拉伯数字
call :pickup %int%
:: 检查原始数值整数部分的最后一位是不是数字,从而决定是否继续转换
if not "%int:~-1%"==" " (
    set tmp=!last!
    call :replace_2
)
echo.
echo 中文数字阿拉伯化的结果2:%str_%%tmp%.%dec%
if not "%dec%"=="" (
    set result=%str_: =%%tmp%.%dec: =%
) else set result=%str_: =%%tmp%
echo.
echo --------------------------------------------------
echo            最终结果是:%result%
endlocal
pause>nul
goto :eof

:pickup
:: 提取阿拉伯数字,并对"零"做处理
set last=%2
if not %1 equ 0 (
    set str_=!str_! %1
) else (
    set str_=!str_! %zero%
    set tmp=
    set length=0
)
:: 对"×佰零×"之类的数要单独处理
if "%4"=="零" (
    if not "%2"=="佰" (
        call :replace %2 %6
    ) else set zero=0
)
shift
shift
if not "%1"=="" goto pickup
goto :eof

:replace
:: 对"零"做补位处理
if "%2"=="" (
    set tmp=
) else (
    set tmp=%2
    set tmp=!tmp:~0,1!
)
set tmp=%1 %tmp%
call :replace_2
for /f "tokens=1,2" %%i in ("%tmp%") do set former=%%i&set later=%%j
:: 比较字符串 %former% 和 %later% 的长短,不能用 if %former% lss %later% 语句
set flag=!former:%later%=!
if "%flag%"=="%former%" (
    set zero=%former:~1%
    set flag=
    goto :eof
)
:get_length
set /a length+=1
if not "%later%"=="" set later=%later:~0,-1%&goto get_length
set zero=!former:~%length%!
goto :eof

:replace_1
set var=%1
set num=1
for %%i in (壹 贰 叁 肆 伍 陆 柒 捌 玖) do (
    call set var=%%var:%%i= !num! %%
    set /a num+=1
)
set var=%var:零= 0 零 %
goto :eof

:replace_2
set tmp=%tmp:拾=0%
set tmp=%tmp:佰=00%
set tmp=%tmp:仟=000%
set tmp=%tmp:万=0000%
set tmp=%tmp:亿=00000000%
goto :eof
[ Last edited by namejm on 2007-1-3 at 08:18 PM ]



尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2007-1-3 12:18
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qzwqzw
银牌会员

天的白色影子


积分 2342
发帖 635
注册 2004-3-6
状态 离线
『第 2 楼』:  

你的代码用捌仟零叁万测试有问题,具体在哪自己找找吧
————————————————————————————————
另发一段完整的互转代码

测试中有意加了一些无效数字

RMB2Num段我很不满意

一者没有良好的检查,findtsr 不支持双字节字符的正则

二者没有良好的结构,算法和数据结构的设计缺陷,导致代码结构的缺陷
:: 人民币大小写互转程序 R3
:: qzwqzw http://bbs.cn-dos.net
:: 2007-01-03 11:15
@echo off
setlocal EnableDelayedExpansion

for /l %%i in (1,1,100) do (
    set /a numin=!random!*50001-50000000
    set numin=!numin:~0,-2!.!numin:~-2!
    set in=!numin!
    call :Num2RMB
    set in=!out!
    call :RMB2Num
    echo.%%i [!numin!:!in!:!out!]
    if !numin! neq !out! set /p=--- Invalid ---
    set out=
)
if "%~0"=="%~f0" pause
endlocal
goto :eof

:Num2RMB
setlocal
set num=%in%
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 :eof
)

:del_pre0
if "%num:~0,1%"=="0" (
    set num=%num:~1%
    goto del_pre0
)

:checknum
set num=%num:,=%
set /a num2=num+0
if not "%num%"=="%num2%" goto :eof
if %num% geq 1000000000000 goto :eof
if %num% leq 0 goto :eof

set tbl1=零壹贰叁肆伍陆柒捌玖
set tbl2=分角元拾佰仟万拾佰仟亿拾佰仟

:n2r_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 n2r_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:零零=整%

endlocal & set out=%rmb%
goto :eof
::Num2RMB

:RMB2Num
setlocal
set rmb=%in%
set rmb=%rmb:零=%
set rmb=%rmb:整=%

set tbl1=零壹贰叁肆伍陆柒捌玖
set tbl2=分角元拾佰仟万拾佰仟亿拾佰仟
for /l %%i in (1,1,9) do call set rmb%%tbl1:~%%i,1%%=%%i

:r2n_loop
if "%tbl2:~0,1%"=="%rmb:~-1,1%" (
    set rmb=!rmb:~0,-1!
    call set tmp=%%rmb!rmb:~-1,1!%%
    if not "!tmp!"=="" (
        set num=!tmp!!num!
        set rmb=!rmb:~0,-1!
    ) else (
        set num=0!num!
    )
) else (
    set num=0!num!
)
set tbl2=%tbl2:~1%
if not "%rmb%"=="" if not "%tbl2%"=="" goto r2n_loop

set num=%num:~0,-2%.%num:~-2%
endlocal & set out=%num%
goto :eof
::RMB2Num
[ Last edited by qzwqzw on 2007-1-3 at 11:22 AM ]

   此帖被 +20 点积分       点击查看详情   
评分人:【 namejm 分数: +20  时间:2007-1-5 03:21


2007-1-3 23:23
查看资料  发短消息 网志   编辑帖子  回复  引用回复
namejm
荣誉版主

batch fan


积分 5226
发帖 1737
注册 2006-3-10
来自 成都
状态 离线
『第 3 楼』:  

  呵呵,测试不严谨,正在查错。



尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2007-1-4 00:10
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qzwqzw
银牌会员

天的白色影子


积分 2342
发帖 635
注册 2004-3-6
状态 离线
『第 4 楼』:  

R3仅是将RMB2Num段的结构作了调整

因为算法和数据结构未变

所以一些固有缺陷仅仅转变了表现方式

比如嵌套的if、冗余的else set等

[ Last edited by qzwqzw on 2007-1-3 at 11:34 AM ]

2007-1-4 00:30
查看资料  发短消息 网志   编辑帖子  回复  引用回复
namejm
荣誉版主

batch fan


积分 5226
发帖 1737
注册 2006-3-10
来自 成都
状态 离线
『第 5 楼』:  

  经过修改,顶楼代码已经能处理形如 捌仟零叁万、捌仟零叁拾万 之类的中文数字(感谢 qzwqzw 在 2F 和 6F 指出这些问题),请各位继续测试。

RE qzwqzw:

  如果能把解题思路放在代码里的话,就能让别人容易理解你的算法了——开始硬着头皮看你的代码-_-||。

[ Last edited by namejm on 2007-1-3 at 03:10 PM ]



尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2007-1-4 01:58
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qzwqzw
银牌会员

天的白色影子


积分 2342
发帖 635
注册 2004-3-6
状态 离线
『第 6 楼』:  

继续用捌仟零叁拾万测试出现问题

————————————————————————————————

在我的代码里

:Num2RMB 段比较简单,直接按位替换数字和进位后,再针对零整问题分步替换

:RMB2Num 段比较麻烦,因为算法上并不成熟,所以不想多做说明

主要是对tbl2与rmb进行同步扫描

两者对齐时进行数字替换并同步移位

否则单独移位%tbl2%使之对齐,同时用0补空位

代码本身已大体反映了算法的轮廓

可能我的注释反而会加大阅读上的障碍,所以一概略去

一句清晰的代码胜过十句模糊的注释

2007-1-4 02:32
查看资料  发短消息 网志   编辑帖子  回复  引用回复
namejm
荣誉版主

batch fan


积分 5226
发帖 1737
注册 2006-3-10
来自 成都
状态 离线
『第 7 楼』:  

RE qzwqzw:

  一段代码确实不需要过多的注释,但是,如果能把思路一并附上的话,则效果更好,因为思路的说明信息能让人从一开始就知道这个代码的大致流程,当代码过多的时候,不至于跳转得晕头转向而忘记了每节代码的目的。

  当然,提供思路说明信息只是为了能让别人更好地理解代码,是为了方便他人,不是必需的内容。



尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2007-1-4 04:07
查看资料  发短消息 网志   编辑帖子  回复  引用回复
youxi01
高级用户




积分 846
发帖 247
注册 2006-10-27
来自 湖南==》广东
状态 离线
『第 8 楼』:  

来个"另类"点的吧,目前只支持1亿以内的数字,欢迎测试!
@echo off
setlocal enabledelayedexpansion
set str=捌仟贰佰叁拾万零柒佰零贰点零伍肆
set /a 仟=1000,佰=100,拾=10,个=1

for %%i in (壹 贰 叁 肆 伍 陆 柒 捌 玖) do (
   set/a a+=1
   call set str=%%str:%%i=!a!%%)
for /f "tokens=1* delims=点" %%i in ("%str%") do set rnd=%%i&set dec=%%j
for /f "tokens=1* delims=万" %%i in ("%rnd:零=%") do (
    if "%%j"=="" (
        set/a num1_=0
        call :test %%i 2
        ) else (call :test %%i 1 &call :test %%j 2))
for /f "tokens=2 delims==" %%i in ('set num1_') do set /a Res1+=%%i
for /f "tokens=2 delims==" %%i in ('set num2_') do set /a Res2+=%%i
set /a Res=%Res1%*10000+%Res2%

if "%dec%"=="" (echo !Res!) else echo !Res!.!dec:零=0!

pause>nul
:test
   set tmp=%1
   for /l %%i in (0 2 8) do (
       set tmp_=!tmp:~%%i,2!
       if not "!tmp_!"=="" (
           set tmp1=!tmp_:~0,1!
           set tmp2=!tmp_:~1,1!
           if "!tmp2!"=="" set tmp2=个
           call set /a num%2_%%i=!tmp1!*%%!tmp2!%%) else goto :eof)


   此帖被 +12 点积分      点击查看详情   
评分人:【 namejm 分数: +12  时间:2007-1-5 03:21


2007-1-4 07:45
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
tigerpower
中级用户

大师兄


积分 377
发帖 99
注册 2005-8-26
状态 离线
『第 9 楼』:  

哈哈,偶难得写这么长的纯批处理:)
@echo off
set USAGE=USAGE: %0 hanzi
setlocal enabledelayedexpansion
set daxie=零壹贰叁肆伍陆柒捌玖
for /l %%a in (0,1,9) do (set Arabic_poi!daxie:~%%a,1!=%%a)
for /l %%a in (0,1,9) do (set Arabic_int!daxie:~%%a,1!=+%%a)
set Arabic_poi点=.
set Arabic_int拾=*10
set Arabic_int佰=*100
set Arabic_int仟=*1000
set Arabic_int万=)*10000
set Arabic_int亿=)*100000000+(0

if "%1"=="" echo %USAGE%&&goto :eof
set input=%1。

set point=0
:loop
if not "!input!"=="" (
set chr=!input:~,1!
if "!chr!"=="点" set point=1
if "!chr!"=="万" set wan=1
if "!chr!"=="亿" set yi=1
if %point%==0 (set int=!int!!Arabic_int%chr%!) else (set poi=!poi!!Arabic_poi%chr%!)
set input=!input:~1!
goto loop)

if not defined int set int=0
if defined wan set int=(!int!
if defined yi (if not defined wan set int=(!int!^)) else set /a int=!int!&&goto end

set int_re=!int:*100000000+=!
set /a int_yi=!int:100000000+%int_re%=1!
set /a int_re=%int_re%
for /l %%i in (0,1,7) do (if "!int_re:~%%i!"=="" set int_re=0!int_re!)
set int=!int_yi!!int_re!

:end
echo %int%%poi%


[ Last edited by tigerpower on 2007-1-6 at 12:24 PM ]

   此帖被 +16 点积分      点击查看详情   
评分人:【 namejm 分数: +16  时间:2007-1-5 03:25


2007-1-4 10:48
查看资料  发短消息 网志   编辑帖子  回复  引用回复
tao0610
高级用户

朦胧的世界


积分 579
发帖 218
注册 2006-10-24
状态 离线
『第 10 楼』:  

发一个算术法算出来的.
要小于2147483648,只能是整型
@echo off&setlocal enabledelayedexpansion
set str0=*一二三四五六七八九零壹贰叁肆伍陆柒捌玖&set b=1
color fc&mode con:cols=60 lines=15
:start
cls&echo\&echo/&echo=&echo+&echo\&echo/
setlocal
set/p str1=请输入中文数字:
if "%str1:~0,1%"=="十" set str1=%str1:*十=1十%
set str1=%str1:零=%
for %%a in (十拾 百佰 千仟) do (
set a=!a!0&&set n0=%%a
call set str1=%%str1:!n0:~0,1!=!a!+%%
call set str1=%%str1:!n0:~-1!=!a!+%%
)
:num1
if "!str1:~%nstr1%,1!"=="万" if not defined y (
set str1=(%str1%&&set/a nstr1+=1) else set str1=%str1:亿=亿(%&&set/a nstr1+=1
if "!str1:~%nstr1%,1!"=="亿" set str1=(%str1%&&set/a nstr1+=1&&set/a y+=1
if "!str1:~%nstr1%,1!"=="" goto next
set/a nstr1+=1
goto num1
:next
for %%i in (万 亿) do set/a b*=10000&&call set str1=%%str1:%%i=+0)*!b!+%%
for /l %%a in (1,1,19) do (
set n1=%%a&&call set str1=%%str1:!str0:~%%a,1!=!n1:~-1!%%)
2>nul set/a str1=%str1%+0||goto false
if %str1%==0 goto false
echo\&echo/&echo 转化为阿拉伯数字为:%str1%&goto end
:false
echo 输入有错误,请重新输入.
:end
endlocal
pause>nul&goto start





认识自己,降伏自己,改变自己
,才能改变别人!
2007-1-5 08:28
查看资料  发短消息 网志   编辑帖子  回复  引用回复
vipchenlang
新手上路





积分 6
发帖 3
注册 2007-11-30
状态 离线
『第 11 楼』:  

又长见识了!!!!!!!!!!!!!!!!!!!!!

2007-11-30 23:51
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
new999
新手上路





积分 1
发帖 1
注册 2008-11-25
状态 离线
『第 12 楼』:  



  Quote:
Originally posted by youxi01 at 2007-1-4 07:45:
来个"另类"点的吧,目前只支持1亿以内的数字,欢迎测试!

[code]
@echo off
setlocal enabledelayedexpansion
set str=捌仟贰佰叁拾万零柒佰零贰点零伍肆
s ...

有点问题,壹万会转成1

2008-12-3 18:42
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: