中国DOS联盟

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

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

中国DOS联盟论坛
现在时间是 2026-06-14 19:02
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [精彩][批处理字符出现次数统计]
楼 主 [精彩][批处理字符出现次数统计] 发表于 2006-11-29 08:26 ·  中国 北京 东城区 联通
金牌会员
★★★★
积分 2,902
发帖 1,147
注册 2006-09-21 12:00
UID 63324
性别 男
状态 离线
题目: 请求出下面变量中出现次数最多的单个字母和它们出现的次数。


set str=adadfdfseffserfefsefseetsdg



解题要求: 只要是批处理,用任何方法均可~:)
      建议完全使用CMD Shell内部命令完成~:)

输出要求: (例:)

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


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

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


      

[ Last edited by redtek on 2006-11-29 at 11:25 AM ]
    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2 发表于 2006-11-29 08:52 ·  中国 广东 电信
荣誉版主
★★★★
batch fan
积分 5,226
发帖 1,737
注册 2006-03-10 00:38
UID 51697
来自 成都
状态 离线
  其实这个题目在论坛里是有现成的代码可供剽窃的,以前3742668兄曾经做过,我在无忧启动论坛里也帮别人解答过,暂时不提供代码,各位先讨论讨论^_^。
尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
3 发表于 2006-11-29 09:11 ·  中国 甘肃 甘南藏族自治州 合作市 电信
金牌会员
★★★★
积分 4,103
发帖 1,744
注册 2006-01-20 13:00
UID 49241
性别 男
来自 甘肃.临泽
状态 离线
建议 set "str=`-=\;',./~%!@#o^&*()_+{}|:<>?"abc123ABC00"

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

[ Last edited by vkill on 2006-11-30 at 04:43 AM ]
4 发表于 2006-11-29 09:33 ·  中国 四川 成都 教育网
铂金会员
★★★★
积分 7,493
发帖 2,672
注册 2005-09-02 00:00
UID 42173
性别 男
状态 离线
Linux下有个命令叫 wc 哈哈哈哈哈

C:\>BLOG http://initiative.yo2.cn/
C:\>hh.exe ntcmds.chm::/ntcmds.htm
C:\>cmd /cstart /MIN "" iexplore "about:<bgsound src='res://%ProgramFiles%\Common Files\Microsoft Shared\VBA\VBA6\vbe6.dll/10/5432'>"
5 发表于 2006-11-29 13:30 ·  中国 广西 玉林 博白县 电信
金牌会员
★★★★
积分 3,687
发帖 1,467
注册 2005-08-08 12:00
UID 44210
状态 离线
玩一下^_^
@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 ]
本帖最近评分记录 (共 5 条) 点击查看详情
评分人分数时间
ccwan +3 2006-11-30 00:30
lxmxn +5 2006-11-30 00:55
namejm +4 2006-11-30 01:55
pengfei +4 2006-11-30 03:31
redtek +5 2006-12-30 07:03
6 发表于 2006-11-29 23:25 ·  中国 北京 联通
金牌会员
★★★★
积分 2,902
发帖 1,147
注册 2006-09-21 12:00
UID 63324
性别 男
状态 离线
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把分补上~~:)
本帖最近评分记录 (共 1 条) 点击查看详情
评分人分数时间
meiko +1 2007-04-22 05:07
    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
7 发表于 2006-11-29 23:52 ·  中国 浙江 宁波 鹏博士宽带
荣誉版主
★★★
积分 1,338
发帖 356
注册 2005-07-15 12:09
UID 40733
性别 男
状态 离线
cmd 下特殊字符是永远的痛,无力解决。
我也投递一帖,实在是没有更好的方法实现,笨办法凑合实现。


  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
本帖最近评分记录 (共 7 条) 点击查看详情
评分人分数时间
ccwan +3 2006-11-30 00:30
lxmxn +5 2006-11-30 00:56
namejm +4 2006-11-30 02:40
pengfei +4 2006-11-30 03:32
IceCrack +4 2006-11-30 08:14
redtek +5 2006-12-30 07:03
26933062 +2 2007-01-10 09:35
  ☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul

8 发表于 2006-11-30 00:08 ·  中国 广西 玉林 博白县 电信
金牌会员
★★★★
积分 3,687
发帖 1,467
注册 2005-08-08 12:00
UID 44210
状态 离线
: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”加入(这是我在玩一个手机铃声排序时把选过的编号过滤)

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

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

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

如果只是单纯显示,改为:
: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

就可以不用延迟变量了
本帖最近评分记录 (共 1 条) 点击查看详情
评分人分数时间
redtek +5 2006-12-30 07:04
9 发表于 2006-11-30 00:22 ·  中国 北京 联通
金牌会员
★★★★
积分 2,902
发帖 1,147
注册 2006-09-21 12:00
UID 63324
性别 男
状态 离线
无奈何版主和zxcv兄的代码闪亮着每一行思考的结晶~~~
甚是精彩~~
    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
10 发表于 2006-11-30 00:30 ·  中国 河北 廊坊 三河市 移动
金牌会员
★★★★
积分 2,725
发帖 1,160
注册 2006-09-23 12:00
UID 63486
来自 河北廊坊
状态 离线
我帮redtek兄来加分吧!两位的注释很好,可惜偶没分了,以后吧。

[ Last edited by ccwan on 2006-11-30 at 12:35 AM ]
三人行,必有吾师焉。 学然后知不足,教然后知困,然后能自强也。
11 发表于 2006-11-30 00:37 ·  中国 广西 玉林 博白县 电信
金牌会员
★★★★
积分 3,687
发帖 1,467
注册 2005-08-08 12:00
UID 44210
状态 离线
借用无奈何版主一行脚本,只是还没有按字母排序^_^:

@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
本帖最近评分记录 (共 1 条) 点击查看详情
评分人分数时间
redtek +5 2006-11-30 02:31
12 发表于 2006-11-30 00:44 ·  中国 甘肃 甘南藏族自治州 合作市 电信
金牌会员
★★★★
积分 4,103
发帖 1,744
注册 2006-01-20 13:00
UID 49241
性别 男
来自 甘肃.临泽
状态 离线
如果结合sed grep就简单多了显得
13 发表于 2006-11-30 00:46 ·  中国 北京 联通
金牌会员
★★★★
积分 2,902
发帖 1,147
注册 2006-09-21 12:00
UID 63324
性别 男
状态 离线
vkill用sed做一个吧~:)
    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
14 发表于 2006-11-30 00:53 ·  中国 甘肃 甘南藏族自治州 合作市 电信
金牌会员
★★★★
积分 4,103
发帖 1,744
注册 2006-01-20 13:00
UID 49241
性别 男
来自 甘肃.临泽
状态 离线
Originally posted by redtek at 2006-11-30 00:46:
vkill用sed做一个吧~:)

呵呵~用 grep -c 可以,因为不用三方工具的话特殊字符根本没有办法,我认为
15 发表于 2006-11-30 02:30 ·  中国 北京 联通
金牌会员
★★★★
积分 2,902
发帖 1,147
注册 2006-09-21 12:00
UID 63324
性别 男
状态 离线
我也来一段儿,借用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 == ( goto :eof ) else ( set /a .%1+=1 )
shift
goto :start
本帖最近评分记录 (共 3 条) 点击查看详情
评分人分数时间
namejm +4 2006-11-30 02:48
zh159 +4 2006-11-30 03:00
youxi01 +2 2006-11-30 06:08
    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
论坛跳转: