Board logo

标题: [精彩][批处理字符出现次数统计] [打印本页]

作者: redtek     时间: 2006-11-29 08:26    标题: [精彩][批处理字符出现次数统计]

题目: 请求出下面变量中出现次数最多的单个字母和它们出现的次数。
set  str=adadfdfseffserfefsefseetsdg
解题要求: 只要是批处理,用任何方法均可~:)
      建议完全使用CMD Shell内部命令完成~:)

输出要求: (例:)

      a  --  10
      b  --  6
      ……
      出现次数最多的字母是:  g
      ……等以此类推的样式(但不限于此输出样式)


关于答题: 旨交流批处理算法与技巧,共同进步~:)

评分处理: 最后由神一样的版主点评每一位答题者,并指导。同时大家相互交流:)
      越先答题以及精彩代码的网友,给于高分奖励~:)


      

[ Last edited by redtek on 2006-11-29 at 11:25 AM ]
作者: namejm     时间: 2006-11-29 08:52
  其实这个题目在论坛里是有现成的代码可供剽窃的,以前3742668兄曾经做过,我在无忧启动论坛里也帮别人解答过,暂时不提供代码,各位先讨论讨论^_^。
作者: vkill     时间: 2006-11-29 09:11
建议  set "str=`-=[]\;',./~%!@#o^&*()_+{}|:<>?"abc123ABC00"

这样考虑特殊字符才有点难度哦

[ Last edited by vkill on 2006-11-30 at 04:43 AM ]
作者: electronixtar     时间: 2006-11-29 09:33
Linux下有个命令叫 wc 哈哈哈哈哈
作者: zh159     时间: 2006-11-29 13:30
玩一下^_^
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdg

:loop
set str$=%str$% %str:~0,1%
set str=%str:~1%
if not "%str%" == "" goto loop

for %%i in (%str$%) do call :Scan1 %%i

pause
exit

:Scan1
for %%i in (%exclude%) do if "%1"=="%%i" goto :eof
set exclude=%exclude% %1
call :Scan2 %1
goto :eof

:Scan2
for %%i in (%str$%) do if "%1"=="%%i" set /a %1+=1
echo %1 !%1!
goto :eof
[ Last edited by zxcv on 2006-11-29 at 01:31 AM ]
作者: redtek     时间: 2006-11-29 23:25
zxcv兄5楼代码有意思~~欣赏~~~
set str$=%str$% %str:~0,1%
set str=%str:~1%
……
上面先将 str 变量内的字符串 “adadfdfseffserfefsefseetsdg” “拆解” 成每个字符中间用空格隔开,为方便for单取字符传值使用~:)

(这个将连续字符串全部拆解成以空格隔开的单个字母的技巧很有意思~:)
for %%i in (%str$%) do call :Scan1 %%i
当字符串已被 “拆解” 成每个字母均用空格隔开以后,通过for依次单取读出并以call语句后面带参数方式向 :Scan1 标签代码段传递数据。

这个时候 :Scan1 标签代码段内就可以使用 %1 的方式来取得 Call 过来的数据并处理~:)

(将连续字符串拆解成以空格隔开的单个字母是为了方便for取得单个字母)
(而for取以空格为分隔符的字符串是利用了 for 的 Delims 参数的默认值)

……

其它部分代码zxcv兄讲讲思路和原理吧? 



(最难得的是当 “远离” 了高级语言中可以随时调用的各种函数以后,(如字符串截取专用函数、统计等……)
(这样情况下,在批处理中使用内部命令与简单的语句同样可以完成思想的“传递”。)

(几乎一切都象是原始的操作,几个简单的语句分隔,几个Goto,几个SET……照样可以象模拟“底层”一样完成思想)

(这样的思考过程中,一切都是在没有现成函数支持的情况下,使用这些简单的命令复现这复杂的过程与梦想的实现)
(在这种过程中,可以体会并感受到“原始”与最接近“所能控置的最直接”的方式来复现批处理的美~~)


(昨天分都加光了,下午给zxcv把分补上~~:)
作者: 无奈何     时间: 2006-11-29 23:52
cmd 下特殊字符是永远的痛,无力解决。
我也投递一帖,实在是没有更好的方法实现,笨办法凑合实现。

  Quote:

  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set str=adadfdfseffserfefsefseetsdg
  4. set /a m=0,n=0,l=0
  5. call :loop
  6. for /f "tokens=1,2 delims==" %%i in ('set 字符:') do (
  7.         echo %%i=%%j
  8.         if %%j GTR !l! set l=%%j & set m=%%i
  9. )
  10. echo.出现次数最多的%m%=%l%
  11. pause
  12. goto :EOF
  13. :loop
  14. call set m=%%str:~%n%,1%%
  15. if not defined m goto :EOF
  16. set /a "字符:%m%+=1"
  17. set /a n+=1
  18. goto loop
        无奈何发表于    2006-11-29  10:50


作者: zh159     时间: 2006-11-30 00:08


  Quote:
:Scan1
for %%i in (%exclude%) do if "%1"=="%%i" goto :eof
set exclude=%exclude% %1
call :Scan2 %1
goto :eof

利用“for %%i in (%exclude%) do if "%1"=="%%i" goto :eof”作为过滤相同的字符,有相同的返回“for %%i in (%str$%) do call :Scan1 %%i”进行下一个字符过滤,%exclude%里没有的新字符用“set exclude=%exclude% %1”加入(这是我在玩一个手机铃声排序时把选过的编号过滤)

  Quote:
:Scan2
for %%i in (%str$%) do if "%1"=="%%i" set /a %1+=1
echo %1 !%1!
goto :eof

过滤出来所用的字符逐一计算出现次数,用自身完成计算后“!%1!”延迟变量显示次数

之所以用“set /a %1+=1”,可以给后面单独为某个字符提供使用

如果只是单纯显示,改为:

  Quote:
:Scan1
for %%i in (%exclude%) do if "%1"=="%%i" goto :eof
set exclude=%exclude% %1
set N=
call :Scan2 %1
goto :eof

:Scan2
for %%i in (%str$%) do if "%1"=="%%i" set /a N+=1
echo %1 %N%
goto :eof

就可以不用延迟变量了
作者: redtek     时间: 2006-11-30 00:22
无奈何版主和zxcv兄的代码闪亮着每一行思考的结晶~~~
甚是精彩~~
作者: ccwan     时间: 2006-11-30 00:30
我帮redtek兄来加分吧!两位的注释很好,可惜偶没分了,以后吧。

[ Last edited by ccwan on 2006-11-30 at 12:35 AM ]
作者: zh159     时间: 2006-11-30 00:37
借用无奈何版主一行脚本,只是还没有按字母排序^_^:

  Quote:
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdg

:loop
set str$=%str$% %str:~0,1%
set str=%str:~1%
if not "%str%" == "" goto loop

for %%i in (%str$%) do call :Scan1 %%i
echo 出现次数最多的:%max%=%maxN%
pause
exit

:Scan1
for %%i in (%exclude%) do if "%1"=="%%i" goto :eof
set exclude=%exclude% %1
call :Scan2 %1
goto :eof

:Scan2
for %%i in (%str$%) do if "%1"=="%%i" set /a %1+=1
if !%1! GTR !maxN! set maxN=!%1! & set max=%1
echo 字符:%1=!%1!
goto :eof


作者: vkill     时间: 2006-11-30 00:44
如果结合sed grep就简单多了显得
作者: redtek     时间: 2006-11-30 00:46
vkill用sed做一个吧~:)
作者: vkill     时间: 2006-11-30 00:53


  Quote:
Originally posted by redtek at 2006-11-30 00:46:
vkill用sed做一个吧~:)

呵呵~用 grep -c 可以,因为不用三方工具的话特殊字符根本没有办法,我认为
作者: redtek     时间: 2006-11-30 02:30
我也来一段儿,借用zxcv兄的 :loop 空格间隔字母的代码段一用~:)
@echo off
set str=adadfdfseffserfefsefseetsdg

:loop
        set str$=%str$% %str:~0,1% && set str=%str:~1%
        if not "%str%" == "" goto loop

call :start %str$%
set . & goto :eof

:start
        if [%1]==[] ( goto :eof ) else ( set /a  .%1+=1 )
        shift
        goto :start

作者: namejm     时间: 2006-11-30 02:49
  各位的代码都很精彩,比起我的 sort 方案来,高明了很多,给各位加分!
作者: namejm     时间: 2006-11-30 02:53
  我做的方案在这里
作者: zh159     时间: 2006-11-30 02:58
redtek的利用shift移位,set .的按顺序显示特性

增加出现次数最多的显示^_^
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdg

:loop
        set str$=%str$% %str:~0,1% && set str=%str:~1%
        if not "%str%" == "" goto loop

call :start %str$%
set .
echo 出现次数最多的:%max%=%maxN%
pause
exit

:start
        if [%1]==[] ( goto :eof ) else ( set /a  .%1+=1 )
if !.%1! GTR !maxN! set maxN=!.%1!&&set max=.%1
        shift
        goto :start
修改了BUG

[ Last edited by zxcv on 2006-11-29 at 08:27 PM ]
作者: redtek     时间: 2006-11-30 03:14
namejm兄17楼的方案 “做一个文本中关于内容统计的批处理” 正在欣赏,里面的代码真是有意思,太精彩了~~:)))

回zxcv兄:我15楼代码没有做出现次数最多的那部分是因为我不会做(偷偷的说~)
真是精彩~~跟namejm、zxcv兄学习了~:)))
作者: zh159     时间: 2006-11-30 03:18
俺是现学现用
都是学习好榜样
作者: pengfei     时间: 2006-11-30 03:33
厉害, 各位加油^_^
作者: redtek     时间: 2006-11-30 03:48
if !.%1! GTR !maxN! set maxN=!.%1! && set max=.%1
if %%j GTR !l! set l=%%j & set m=%%i

namejm和zxcv兄的这句有意思~~

找出最大的一个数,如果取到的值大于 “存储最大值的变量” ,则说明取到的数更大,则让它来代替原 “存储最大值的变量” 内,
当数据全“走”过一遍以后,“存储最大值的变量” 内的值自然是最大的值~:)

欣赏加狂顶!!!
又学到很多东东,交流碰撞出很多灵感~~
作者: lxmxn     时间: 2006-11-30 04:13

  刚才测试了一下18楼的代码,在18楼代码的基础上,我增加了str变量的值,把它设置为:set str=adadfdfseffserfefsefseetsdgdsfjkljdsklfjdsfdsgdsafdsaf,然后运行批处理,结果:

  Quote:
.a=4
.d=10
.e=6
.f=12
.g=2
.j=3
.k=2
.l=2
.r=1
.s=11
.t=1
出现次数最多的:.f=9
请按任意键继续. . .


作者: 无奈何     时间: 2006-11-30 04:31
后面的越来越精彩了,这样的交流大家收获都不少,学习的还快,还有趣味。
建议以后大家多发现一些这样的问题,要求不要太难,重在参与。
大家讨论一下以后可不可以每期增加一些名誉性的奖项,比如:
代码最短
速度最快
稳定性最强
创意最好
还有一种谁都看不明白,但是能完成功能。

从这几个角度充分发挥大家的发散思维。不过,类似这样的名字怎么取...
作者: vkill     时间: 2006-11-30 04:49
还有一种谁都看不明白,但是能完成功能

呵呵,这个非无奈何斑竹你魔术了
作者: redtek     时间: 2006-11-30 05:08
那版主的名字就是 “空前绝后” 这名字棒吧~~
作者: tao0610     时间: 2006-11-30 05:20
MS出现次数最多的结果都不太对,问题出在那里?
作者: youxi01     时间: 2006-11-30 05:23
也贴一段不成熟的代码,统计各字符出现的次数:
思路:先用“函数”test取得变量str的长度,保存为OSlen;
然后取得变量的第一个字符,保存为str0,然后将变量str中的str0全部替换为空,再获取str的长度,保存为%num%,那么第一个出现的字符为:%str0%,长度为:%OSlen%-%num%,依次类推.....
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdg
call :test %str%

for /l %%i in (0 1 100) do (
   set /a OSlen=!num!  
   set str%%i=!str:~0,1!
   call :test1 !str! !str%%i! %%i)

:exit
    pause>nul
    exit

:test
    set /a num=0
    set var=%1
    for /l %%i in (1 1 100) do (
       set var_=!var:~%%i,1!
       if "!var_!"=="" set /a num=%%i &&goto :eof)
    goto :eof

:test1
    set var=%1
    set var_=%2
    set num_=%3
    set str=!var:%var_%=!
    if "%str%"=="" goto :exit
    call :test %str%

    set /a len%num_%=!OSlen!-!num!
    echo 字符 %2 出现的次数 !len%num_%!
[ Last edited by youxi01 on 2006-11-30 at 06:47 AM ]
作者: tao0610     时间: 2006-11-30 05:29
用for /l 的我也贴一个!
@echo off&setlocal enabledelayedexpansion
set  str=adadfdfseffserfefsefseetsdgdsfjkljdsklfjdsfdsgdsafdsaf

for /l %%i in (0,1,100) do (
if "!str:~%%i,1!"=="" goto end
call :define !str:~%%i,1!
set/a !str:~%%i,1!+=1
)

:end
for /l %%x in (1,1,%num%) do (
call set exchang=%%!%%x!%%
call echo !%%x!--%%!%%x!%%个
if  !exchang! gtr !max! call set max=%%!%%x!%%&set maxstr=!%%x!)
echo.&echo.出现次数最多的是%maxstr%=%max%次
pause>nul&goto :eof

:define
if not defined %1 set/a num+=1&&set !num!=%1

作者: youxi01     时间: 2006-11-30 06:10
欣赏15、18楼的代码,学习了!对以上代码稍做了改动,灵魂不变!
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdg

for /l %%i in (0 1 100) do (
   if "!str:~%%i,1!"=="" goto :exit
   set /a .!str:~%%i,1!+=1)
:exit
    set.
    for /f "delims== tokens=1,2" %%i in ('set.') do (
        if %%j GTR !maxl! set /a maxl=%%j && set max=%%i)
    echo 出现最多的是 %max:.=% 字符,共 %maxl% 个
pause

作者: redtek     时间: 2006-11-30 06:14
youxi01兄能否讲讲简单的实现原理和想法?
这样既方便学习又可以更好的理解与阅读代码~:)
作者: ccwan     时间: 2006-11-30 07:03
redtek兄,我运行你15楼的代码,总是一闪而过,不知为何。郁闷……
作者: redtek     时间: 2006-11-30 07:32
没加Pause,哈哈……
我命令行上操作的:)
作者: ccwan     时间: 2006-11-30 07:38
什么命令行那么牛?
作者: redtek     时间: 2006-11-30 07:48
哈哈……
总是一闪而过是你用记事本存到(可能存到桌面了),
那个批处理代码中没有运行完后 pause 等待按任意键再退出,
结果直接鼠标双击那个批处理文件就一闪运行完了就自动退出并关上了CMD Shell窗口了:)

先进入 CMD Shell 命令窗口,在那里面键入 ...BAt再运行:)
作者: namejm     时间: 2006-11-30 08:18
Re lxmxn 『第 23 楼』:  

  无奈何兄7F的代码也存在类似问题,原因出在if %%j GTR !l! set l=%%j & set m=%%i 和 if !.%1! GTR !maxN! set maxN=!.%1! && set max=.%1 这两句上,都是同样的问题:&和&&前都多了一个空格。把这个空格去掉就可以了。
作者: zh159     时间: 2006-11-30 08:23
15楼的在“set . & goto :eof”改为“set . &pause& goto :eof”即可

最简单的^_^
@echo off
setlocal EnableDelayedExpansion
set str=adadfdfseffserfefsefseetsdgadadfdfseffserfefsefseetsdga

:loop
set str$=%str$% %str:~0,1%&set str=%str:~1%
if not "%str%" == "" goto loop

for %%n in (%str$%) do (
  set /a .%%n+=1
if !.%%n! GTR !maxN! set maxN=!.%%n!&&set max=%%n)
set .
echo 出现次数最多的:%max%=%maxN%
pause
exit

作者: zh159     时间: 2006-11-30 08:26


  Quote:
Originally posted by namejm at 2006-11-29 20:18:
Re lxmxn 『第 23 楼』:  

  无奈何兄7F的代码也存在类似问题,原因出在if %%j GTR !l! set l=%%j & set m=%%i 和 if !.%1! GTR !maxN! set maxN=!.%1! && set max=. ...

确实如此,我在 18 楼改的也是,一般建议用&、&&连接的最好不要有空格
作者: tao0610     时间: 2006-11-30 08:27
看来格式规范很重要.
作者: kennylam     时间: 2007-1-8 22:11


  Quote:
Originally posted by tao0610 at 2006-11-29 04:29 PM:
用for /l 的我也贴一个!
[code]@echo off&setlocal enabledelayedexpansion
set  str=adadfdfseffserfefsefseetsdgdsfjkljdsklfjdsfdsgdsafdsaf

for /l %%i in (0,1,100) do (
if "!str:~% ...

看了这么久...还是这位朋友写得比较好!
作者: tyh     时间: 2007-4-22 05:04
if !%1! GTR !maxN! set maxN=!%1! & set max=%1

什么意思啊~~~
作者: yaohaixu     时间: 2008-1-8 02:02    标题: 谢谢大家了哈

谢谢大家了哈,
  作为新人我很想看到这么的好代码,  够好好学习的了。

   很是受用````
   
   就是想问问斑竹以后能不能多一些这样的活动,好给我们新人一个好的学习的机会???/



   代表新人向大家说声谢谢