Board logo

标题: 【练习-064】批处理将自身文本乱序输出 [打印本页]

作者: batman    时间: 2011-4-20 10:24     标题: 【练习-064】批处理将自身文本乱序输出

本帖最后由 batman 于 2011-4-21 22:25 编辑

出题目的:
  考查文本处理技巧;
  复习变量赋值法;
  加深对%0参数概念的理解。
加分原则:
  满分20分,视情况加分(以思路为重)。
解题要求:
  代码简洁、高效,在本题中不应生成临时文件;
  老手们暂缓出手。
题目如下:
  1、要求编写批处理将下面五行文字置于代码中,并将这五行共40个文字乱序后仍按每行8个字输出(可先输出到a.txt);
  我们去北大踢球吧
  快上那儿等着信号
  你不能离开大门口
  生与死就在一瞬间
  青春已从身边溜走
  2、假如输出后的内容如下:
  口就间边号球在离
  吧那身大一等生大
  死不们溜走去开能
  着瞬从北青春快已
  我踢与门你上信儿
  要求编写批处理列出现在每个文字相对原始文本中的偏移量(行偏移:列偏移),具体形式如死字原始位置为4:3,现在为3:1,偏移量则为-1:-2,而口字的偏移量则为-2:-7,各偏移量的输出用空格格开,一样每行8个。
补充:
  两步可写在一个批内,也可分步写成两个批。
----------------------------------------------
由于本人的失误原始文本中出现了两个边字,现已经改正(其中一个改为了儿字)。。。
作者: CrLf    时间: 2011-4-20 13:08

个人感觉这个题目可能解法相对比较单一,并没有太多“百花齐放”的余地
作者: qzwqzw    时间: 2011-4-20 15:03

感觉batman的练习题难度越来越高
可能并不适合给新手练习
倒是可以给老鸟们活活脑子

如果不用临时文件
对自身文本进行操作
可选的方法并不多
偏移量定位及乱序排列
可能会有思路的不同
作者: batman    时间: 2011-4-20 15:58

3# qzwqzw
我承认这点,但这题的难度还是比较低的吧,也没看见新手解题,当然这个新手不包括批才入门的。。。
作者: caruko    时间: 2011-4-20 23:17

本帖最后由 batman 于 2011-4-21 08:06 编辑

MSG2输出数字,空处是TAB.
写成 #0!n!%%n= 这种八进制数,原来是考虑可能会用到,结果没用上,写成 #!n!#%n%= 则会减少几十个 set。
  1. @echo off&setlocal ENABLEDELAYEDEXPANSION
  2. set /a n=0,m=0
  3. for /f "delims=" %%i in ('more +20 %~f0') do (
  4.     set "str=%%i"
  5.     for /l %%n in (0,1,7) do set "_!RANDOM:~-1!!RANDOM:~-1!#0!n!%%n=!str:~%%n,1!"
  6.     set /a n+=1
  7. )
  8. for /f "tokens=2,3 delims=#=" %%a in ('set _') do (
  9.     set "str=%%a"
  10.     set /a y=m/8,x=m%%8,px=x-!str:~2,1!,py=y-!str:~1,1!,m+=1
  11.     set "msg1=!msg1!%%b"
  12.     set "msg2=!msg2!        !py!:!px!"
  13.     if !x! equ 7 (
  14.         set "msg1=!msg1!&echo/"
  15.         set "msg2=!msg2!&echo/"
  16.     )
  17. )
  18. echo %msg1%%msg2%
  19. goto :eof
  20. 我们去北大踢球吧
  21. 快上那儿等着信号
  22. 你不能离开大门口
  23. 生与死就在一瞬间
  24. 青春已从身边溜走
复制代码

作者: batman    时间: 2011-4-21 08:18

本帖最后由 batman 于 2011-4-21 08:20 编辑

1、more +20 %~f0的效率不如skip=20吧。

2、用tab进行简单的对齐,效果不佳。

3、pause都忘记写了。

4、set "msg1=!msg1!&echo/"这句有特色。

5、帮你修改了第一个边字为儿字。
作者: terse    时间: 2011-4-21 11:06

已知行数和字符数 是否可以再简化点 个人感觉 乱序排列的SET效率并不很理想
两个边字的问题 可以放入的吧 因乱序后还是可以对应的哦
作者: batman    时间: 2011-4-21 11:37

本帖最后由 batman 于 2011-4-21 11:41 编辑

乱序思路:
  因为原始文本是5行共40个汉字,所以设置一个code变量,其值为010203...383940。然后每读取一个汉字随机取一次值(初始是对40随机取位置的值),同时将根据随机取得的位置值查找code中对应的值并将汉字存进这个值变量,再从code中删除这个值并将总数值减一,最后所有的汉字都被乱序并储存到了01-40的变量中。
作者: terse    时间: 2011-4-21 17:33

已知的  我直接40个  ECHO
作者: CrLf    时间: 2011-4-21 18:32

特殊情况有特殊解法:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "skip=11 useback" %%a in ("%~0") do set str=!str!%%a
  3. for /l %%a in (40 -1 1) do (
  4. set /a ra=!random!%%%%a,m=~-%%a%%8
  5. for %%b in (!ra!) do (
  6. set /p=!str:~%%b,1!<nul
  7. for %%c in (!str:~%%b,1!) do set str=!str:%%c=!
  8. )
  9. if !m!==0 echo;
  10. )
  11. pause>nul&exit
  12. 我们去北大踢球吧
  13. 快上那儿等着信号
  14. 你不能离开大门口
  15. 生与死就在一瞬间
  16. 青春已从身边溜走
复制代码

作者: batman    时间: 2011-4-21 18:40

难道题意不是已知的。。。
作者: batman    时间: 2011-4-21 18:59

10# zm900612
下面是阁下代码的一次运行结果:
就死门离们上吧间
死生就着们踢离大
开我不离儿去去儿
快等北快北我去快
我大大们去们们我
作者: batman    时间: 2011-4-21 22:15

本帖最后由 batman 于 2011-4-21 22:34 编辑

期待更多的解。。。。
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (101,1,140) do set "a=%%a"&set "code=!code!#!a:~1!#"
  3. set /a num=40&set "#0=&echo,"
  4. for /f "skip=23" %%a in (%~0) do (
  5.     set "str=%%a"&set /a h+=1
  6.     for /l %%a in (0,1,7) do (
  7.         set /a a=!random!%%num,num-=1,a*=4
  8.         for %%b in (!a!) do (
  9.             for %%b in ("!code:~%%b,4!") do (
  10.                 set "a=%%~b"&set "a=!a:#=!"&set "code=!code:%%~b=!"
  11.                 set /a a=1!a!%%100,hm=a/8+1-h,"lm=(a-1)%%8-%%a"
  12.                 for %%b in (h l) do if "!%%bm:-=!" equ "!%%bm!" set "%%bm= !%%bm!"
  13.                 set "_!a!=!str:~%%a,1!"&set ".!a!=!hm!:!lm!"            
  14.             )
  15.         )
  16.     )
  17. )
  18. for /l %%a in (1,1,40) do (
  19.     set "a=      !.%%a!"&set /a b=%%a%%8
  20.     for %%b in (!b!) do set "var=!var!!_%%a!!#%%b!"&set "var1=!var1!!a:~-6!!#%%b!"
  21. )
  22. echo %var%&echo %var1%
  23. pause>nul&goto :eof
  24. 我们去北大踢球吧
  25. 快上那儿等着信号
  26. 你不能离开大门口
  27. 生与死就在一瞬间
  28. 青春已从身边溜走
复制代码

作者: CrLf    时间: 2011-4-21 22:23

本帖最后由 zm900612 于 2011-4-23 22:24 编辑
10# zm900612
下面是阁下代码的一次运行结果:
就死门离们上吧间
死生就着们踢离大
开我不离儿去去儿
快等北快北我去快
我大大们去们们我
batman 发表于 2011-4-21 18:59

当时只是为了表达思路,几分钟搞出来也没测试就回了,所以没发现这个问题...出错原因是漏了"",而且后来发现给定的文字中有重字,所以不能用变量替换取巧。
原帖就不改了,发一下新代码,这回是调试过无误的:
  1. @echo off&setlocal enabledelayedexpansion&echo %time%
  2. for /f "skip=14 useback" %%a in ("%~0") do set str=!str!%%a
  3. for /l %%a in (1 1 39) do set .!str:~%%a,1!=%%a
  4. for /l %%a in (40 -1 1) do (
  5. set /a "ra=!random!%%%%a","m=~-%%a%%8",n=ra+1
  6. for %%b in ("str:~!ra!,1") do (
  7. set /a "p=(40-%%a)-.!%%~b!","x=(40-%%a)%%8-.!%%~b!%%8","y=(40-%%a)/8-.!%%~b!/8"
  8. set "echo=!echo!!%%~b!"&set "xy=!xy!   !x!: !y!   "
  9. for /f "tokens=1* delims=@" %%c in ("!ra!@!n!") do set str=!str:~0,%%~c!!str:~%%~d!
  10. )
  11. )
  12. for /l %%a in (0 8 32) do echo !echo:~%%a,8!
  13. echo %xy: -=-%
  14. echo %time%&pause>nul&exit
  15. 我们去北大踢球吧
  16. 快上那儿等着信号
  17. 你不能离开大门口
  18. 生与死就在一瞬间
  19. 青春已从身边溜走
复制代码
优化了一下,用时减少一半
作者: CrLf    时间: 2011-4-21 22:31

其实我本意只是想提出一个随机取值的思路,因为常规思路要定义大量变量,很容易影响P的整体性能,不过话说回来,估计那个办法大概早有人发明了吧...
作者: batman    时间: 2011-4-22 09:49

14楼的思路是比较巧妙,但美中不足就是set/p输出影响了效率。。。

下面给出一种乱序的方法(先替换a为#,再替换b为a,最后替换#为b从而达到a、b互换的效果):
  1. @echo off&setlocal enabledelayedexpansion
  2. set "#0=&echo,"
  3. for /f "skip=22" %%a in (%~0) do set "str=!str!%%a"
  4. for /l %%a in (0,1,39) do (
  5.     set /a a=!random!%%40
  6.     for %%b in (!a!) do (
  7.         set "a=!str:~%%b,1!"
  8.         for %%b in ("!str:~%%a,1!") do (
  9.             for %%c in (!a!) do (
  10.                 set "str=!str:%%c=#!"
  11.                 set "str=!str:%%~b=%%c!"
  12.                 set "str=!str:#=%%~b!"
  13.             )
  14.         )
  15.     )
  16. )
  17. for /l %%a in (0,1,39) do (
  18.     set /a "a=(%%a+1)%%8"
  19.     for %%b in (!a!) do set "var=!var!!str:~%%a,1!!#%%b!"
  20. )
  21. echo %var%
  22. pause>nul&goto :eof
  23. 我们去北大踢球吧
  24. 快上那儿等着信号
  25. 你不能离开大门口
  26. 生与死就在一瞬间
  27. 青春已从身边溜走
复制代码
 注:因为每次都是两个汉字互换位置(有时可能是自己换自己),所以偏移量的计算会要借助临时文件来实现。
作者: CrLf    时间: 2011-4-22 12:43

另一种乱序输出思路:
  1. @echo off&setlocal enabledelayedexpansion&2>nul 3>nul echo %time%
  2. for /f "skip=14 useback" %%a in ("%~0") do set str=!str!%%a
  3. if "%1"==":" (
  4. for /l %%a in (0 1 39) do echo !random!@!str:~%%a,1!@%%a
  5. exit /b
  6. )
  7. for /f "tokens=2,3 delims=@" %%a in ('%0 : ^|sort') do (
  8. set echo=!echo!%%a
  9. set /a x=n%%8-%%b%%8,y=n/8-%%b/8,n+=1,m=n%%8,1/m||set echo=!echo!,
  10. set "xy=!xy!   !x!: !y!   "
  11. )
  12. for %%a in (!echo!) do echo %%a
  13. echo %xy: -=-%
  14. echo %time%&pause>nul&exit
  15. 我们去北大踢球吧
  16. 快上那儿等着信号
  17. 你不能离开大门口
  18. 生与死就在一瞬间
  19. 青春已从身边溜走
复制代码

作者: caruko    时间: 2011-4-22 12:59

楼上这个,方法跟我那个差不多吧,只是我用set 排序,你用sort。

最早的时候,我想过一种类似洗扑克牌的乱序方法。

1:随机将后一个字符放在前一个字符的前面或者后面,组合成新的字符串。
2:将新字符串再一次洗牌,循环随机20-40次。(估计了一下40个字符20次差不多能做到足够乱序了)

只是思路的一种吧,细想了一下,发现效率不怎么高,就没继续了。
作者: CrLf    时间: 2011-4-22 13:18

本帖最后由 zm900612 于 2011-4-22 13:21 编辑

不一样吧,我的思路是直接分析自身输出,不需要定义大量变量
要不是字数已经超过31,用tokens+random来截取估计是最快的办法了
作者: caruko    时间: 2011-4-22 14:03

本帖最后由 caruko 于 2011-4-22 14:07 编辑

这个在随机排序大量文本的时候是不错,没有临时,没有大量变量,但是效率有点低。

1:echo更耗时,增加了echo次数。
2:sort 本身也是很耗内存的,sort /? 帮助命令看一下就能了解。N个排序对象,在SORT里,产生N个变量用来存放是至少的。set的机制不了解,但似乎在变量存放的时候就是有序的。
3:“ | sort + for”,echo完所有内容进入管道后,SORT才开始排序,SORT排序完并输出所有内容后,FOR开始读取。 所以耗时成倍增加。
作者: CrLf    时间: 2011-4-22 14:13

这只是另一种思路而已,总有适合它的背景。上次生命游戏给我的教训是变量越多速度越慢,以至于后来一个循环耗时前后居然相差了十几倍,所以现在写代码时总会考虑变量的增加对效率的影响
作者: caruko    时间: 2011-4-22 14:19

的确,变量的增加让批处理速度变慢,但好像变慢的是变量读取速度,在频繁读取变量的时候差距就越大。

原因猜想:
可能真的是因为变量有序存放的原因?类似数据库?
不像一般的程序语言机制,只是增加内存消耗,没有明显增加读取耗时。
作者: caruko    时间: 2011-4-22 14:26

我写了这个测试代码
  1. @echo off&setlocal ENABLEDELAYEDEXPANSION
  2. for /l %%i in (1,1,10000) do set /a _%%i=%%i
  3. echo !time!
  4. for /l %%i in (1,1,10000) do set /a _1+=2
  5. echo !time!
  6. for /l %%i in (1,1,10000) do set /a _%%i+=2
  7. echo !time!
复制代码
同样是1万个变量
1:只读取一个变量进行计算,耗时6秒。
2:所有变量都读取进行计算,耗时16秒。
作者: terse    时间: 2011-4-22 15:06

前面回复直接 40 个ECHO 其实和17楼900612兄一样思路
  1. @echo off&setlocal enabledelayedexpansion
  2. if "%1"=="" (
  3.    set N=0
  4.    for /f "skip=15 useback" %%i in ("%~0") do set str!n!=%%i&set/a n+=1
  5.    for /f "tokens=2-4" %%a in ('%0 $^|sort') do (
  6.        set /a "N=L/8,M=L%%8,X=%%b-N,Y=%%c-M,L+=1"
  7.        for %%j in (!N!) do (
  8.            set _%%j=!_%%j! !X!:!Y!
  9.            if !M! equ 7 (echo !#%%j!%%a) else set #%%j=!#%%j!%%a
  10.        )
  11.    )
  12.        for /l %%i in (0 1 4) do echo!_%%i!
  13.        pause&exit
  14. ) else for /l %%i in (0 1 4) do for /l %%j in (0 1 7) do echo !random!!random! !str%%i:~%%j,1! %%i %%j
  15.   exit
  16. 我们去北大踢球吧
  17. 快上那边等着信号
  18. 你不能离开大门口
  19. 生与死就在一瞬间
  20. 青春已从身边溜走
复制代码

作者: CrLf    时间: 2011-4-22 15:36

16# batman


原先我也用了一点变量替换,但是总是莫名其妙少掉一个字,后来发现给定的文本中含有两个“大”,所以变量替换会出错
作者: terse    时间: 2011-4-22 17:50

本帖最后由 terse 于 2011-4-22 17:51 编辑

变量太多影响效率  练手了
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f %%i in ('"find /c /v "" < %0"') do set/a n=%%i-5
  3. for /f "skip=%n% useback" %%i in ("%~0") do set str=!str!%%i
  4. for /l %%i in (0 1 39) do set i=10%%i&set var=!var!#!i:~-2!&set #!i:~-2!=%%i
  5. for /l %%i in (40 -1 1) do (
  6.     set /a "R=!random!%%%%i*3,N=(40-%%i)/8,M=(40-%%i)%%8"
  7.     for /f "tokens=1-3" %%a in ("!R! !N! !M!") do (
  8.         for %%j in ("!var:~%%a,3!") do for %%k in (!%%~j!) do (
  9.             set "var=!var:%%~j=!"
  10.             set /a "AN=%%k/8-%%b,AM=%%k%%8-%%c"
  11.             if %%c equ 7 (echo !#b!!str:~%%k,1!&set #b=) else set #b=!#b!!str:~%%k,1!
  12.             set _%%b=!_%%b! !AN!:!AM!
  13.         )
  14.     )
  15. )
  16. for /l %%i in (0 1 4) do echo!_%%i!
  17. pause&exit
  18. 我们去北大踢球吧
  19. 快上那边等着信号
  20. 你不能离开大门口
  21. 生与死就在一瞬间
  22. 青春已从身边溜走
复制代码

作者: neorobin    时间: 2011-4-23 00:45

测试环境中文编码未处理好, 以下用40个英文字母替代中文文本:
  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set nl=^
  4. for /l %%i in (0x100 1 0x127) do set nums=!nums!%%i,
  5. for /l %%i in (40 -1 1) do (
  6.   set /a rad=!random!%%%%i*4
  7.   for %%p in (!rad!) do (
  8.     set get=!nums:~%%p,3!
  9.     set /a val=get"&0xff
  10.     set ind=!ind!!val!,
  11.     for %%a in (!get!) do set nums=!nums:%%a,=!
  12.   )
  13. )
  14. for /f "usebackq delims=" %%l in ("%~0") do (
  15.   if /i "%%l"==":endText" set getText=0
  16.   if $!getText!==$1 set str=!str!%%l
  17.   if /i "%%l"==":text" set getText=1
  18. )
  19. for %%i in (!ind!) do (
  20.   set new=!new!!str:~%%i,1!
  21.   set /a lineOffs=cnt/8-%%i/8,colOffs=cnt%%8-%%i%%8
  22.   set "offs=!offs!!lineOffs!:!colOffs! "
  23.   if #!rem!==#7 set new=!new!!nl!& set offs=!offs!!nl!
  24.   set /a cnt+=1,rem=cnt%%8
  25. )
  26. echo !new!
  27. echo !offs!
  28. pause
  29. exit
  30. :text
  31. abcdefgh
  32. ijklmnop
  33. qrstuvwx
  34. yzABCDEF
  35. GHIJKLMN
  36. :endText
复制代码

作者: CrLf    时间: 2011-4-23 11:31

本帖最后由 zm900612 于 2011-4-23 22:23 编辑

16# batman

纯粹用变量替换存在重字bug(有两个“大”),我改进了下,但是用太多call,效率恐怕很低,感叹一下,要是for的参数能带变量该多好啊...
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "useback skip=10" %%a in ("%~0") do set "str=!str!%%a"
  3. set str=@!str!
  4. for /l %%a in (0,1,39) do (
  5.     for %%b in (!random:~-1!) do call :str !str:~%%b,1!
  6. )
  7. for /l %%a in (1 8 33) do echo !str:~%%a,8!
  8. pause>nul
  9. :str
  10. for /f "tokens=1* delims=%1" %%a in ("!str!") do set "str=%%a!str:*%1=!%1"&exit /b
  11. 我们去北大踢球吧
  12. 快上那儿等着信号
  13. 你不能离开大门口
  14. 生与死就在一瞬间
  15. 青春已从身边溜走
复制代码
修改了下漏洞
作者: CrLf    时间: 2011-4-23 12:02

本帖最后由 zm900612 于 2011-4-24 11:29 编辑

若给定文本中不存在重字,这样比原始的40次变量替换更快,而且random的范围更加合理:
  1. @echo off&setlocal enabledelayedexpansion&echo %time%
  2. for /f "useback skip=11" %%a in ("%~0") do set "str=!str!%%a"
  3. set str=@!str!
  4. for /l %%a in (0,1,16) do (
  5.     set /a a=!random!%%12+1
  6.     for %%b in (!a!) do call :str !str:~%%b,5!
  7. )
  8. for /l %%a in (1 8 33) do echo !str:~%%a,8!
  9. echo %time%&pause>nul
  10. :str
  11. for /f "tokens=1* delims=%1" %%a in ("!str!") do set "str=%%a!str:*%1=!%1"&exit /b
  12. 我们去北京踢球吧
  13. 快上那儿等着信号
  14. 你不能离开大门口
  15. 生与死就在一瞬间
  16. 青春已从身边溜走
复制代码
修改了“北大”为“北京”,16次call*5个字符的偏移范围,至少能把这40个字符循环两遍,保证随机性,同时random的取值范围降低,保证各部分字符串被随机选中的概率分布更为合理。
总之在效率和合理性上做了比较大的改进,相比原算法,最大的缺点就在于不支持重复字


现在发现,这似乎就是caruko说的“洗牌”算法,而且terse兄指出我绕弯了,其实只需要优化batman的代码就可以了...纯随机输出无重字文本时,这个大概是极限了(简化后的batman变量替换算法):
  1. @echo off&setlocal enabledelayedexpansion&echo %time%
  2. for /f "skip=9 useback" %%a in ("%~0") do set "str=!str!%%a"
  3. for /l %%a in (0,1,40) do (
  4. for %%b in (!random:~-1!) do (
  5. for /f %%c in ("!str:~%%b,1!") do set str=!str:%%c=!%%c
  6. )
  7. )
  8. for /l %%a in (0 8 32) do echo !str:~%%a,8!
  9. echo %time%&pause>nul
  10. 我们去北京踢球吧
  11. 快上那儿等着信号
  12. 你不能离开大门口
  13. 生与死就在一瞬间
  14. 青春已从身边溜走
复制代码
另有简化后的变量偏移的算法,效率和变量替换相差无几,支持重复字,但是代码多了两行:
  1. ;@echo off&setlocal enabledelayedexpansion&echo %time%
  2. ;for /f "useback" %%a in ("%~0") do set str=!str!%%a
  3. ;for /l %%a in (40 -1 1) do (
  4. ;        set /a "ra=!random!%%%%a",n=ra+1
  5. ;        for /f "tokens=1* delims=@" %%b in ("!ra!@!n!") do (
  6. ; set echo=!echo!!str:~%%b,1!
  7. ; set "str=!str:~0,%%b!!str:~%%c!"
  8. ; )
  9. ;)
  10. ;for /l %%a in (0 8 32) do echo !echo:~%%a,8!
  11. ;echo %time%&pause>nul&exit
  12. 我们去北大踢球吧
  13. 快上那儿等着信号
  14. 你不能离开大门口
  15. 生与死就在一瞬间
  16. 青春已从身边溜走走
复制代码
caruko提出的洗牌法,优点是可以轻易控制复杂程度和用时,缺点是经常洗不干净:
  1. ;@echo off&setlocal enabledelayedexpansion&echo %time%
  2. ;for /f "useback" %%a in ("%~0") do set str=!str!%%a
  3. ;for /l %%a in (1 1 40) do (
  4. ; set /a ra=!random:~-1!+5
  5. ; for %%b in ("!ra!") do (
  6. ; set str=!str:~-%%~b!!str:~5,-%%~b!!str:~0,5!
  7. ; )
  8. ;)
  9. ;for /l %%a in (0 8 32) do echo !str:~%%a,8!
  10. ;echo %time%&pause>nul&exit
  11. 我们去北大踢球吧
  12. 快上那儿等着信号
  13. 你不能离开大门口
  14. 生与死就在一瞬间
  15. 青春已从身边溜走
复制代码
以上几种算法都存在不易计算偏移量的先天缺陷,单独乱序输出时表现不错,但是若要同时计算偏移量,耗时将暴涨,此贴中另外三种在这方面则有优势:
常规算法就不提了,效率一般,也没什么艺术性。
读取自身输出作为输入的方案感觉已经无法再改进了,请见24楼terse代码。
最牛的应该是27楼neorobin的算法了,干净利落,浑然天成。
作者: CrLf    时间: 2011-4-23 12:08

偏移量我就不计算了,那个与上述代码八字不合,写进来比较影响效率和美观
作者: terse    时间: 2011-4-23 15:01

若给定文本中不存在重字 还是一个FOR里处理就好了 过多CALL 效率有问题
当然 作为另一思路则别论
作者: CrLf    时间: 2011-4-23 15:10

本帖最后由 zm900612 于 2011-4-23 15:13 编辑

31# terse


算法问题,用call的初衷是解决for参数中不能使用变量的弊端。
不过刚刚想起来,如果不存在重复字符,就可以直接用变量替换而无需用for截取了
作者: terse    时间: 2011-4-23 23:46

29# zm900612
zm900612兄简化后的代码 可以再减少个FOR  两个并一个既可
作者: CrLf    时间: 2011-4-24 10:50

33# terse
确实,忽略了


27# neorobin

测试环境中文编码未处理好, 以下用40个英文字母替代中文文本echo off
setlocal enableDelayedExpansion
set nl=^


for /l %%i in (0x100 1 0x127) do set nums=!nums!%%i,
for /l %%i in (40 -1 1) do (
  ...
neorobin 发表于 2011-4-23 00:45

那天测试的时候出错,后来发现是我不小心删了最后一个字符...
今天仔细研究了一下,虽然代码长,但是效率呱呱的,原因是通过将待随机取值的可用序号定义为一条长变量(这招太漂亮了),进而将输出的文字、偏移量各自定为一个长变量,创造出其他算法所无法做到的“干净环境”。而且在for /l 中以八进制、十六进制表示数字的用法我以前想都没想过,真是长见识了,这个新鲜技巧稍加磨砺,必定又是一柄利器。
作者: neorobin    时间: 2011-4-25 00:25

本帖最后由 neorobin 于 2011-4-25 01:47 编辑

各位的算法, 我没有仔细研究, 粗略看了下发现大家都用了些一样的技巧或方法,
我写的有些长, 想了下, 下面两段
  1. for /l %%i in (40 -1 1) ...
  2. for %%i in (!ind!) ...
复制代码
可以整合在一起, ind 和 cnt 两个变量省去了, (另外用位运算对 8 求商和余数只是看起来酷点呵, 没什么实质):
  1. for /l %%i in (0 1 39) do (
  2.   set /a "rem=%%i&7, rand=!random!%%(40-%%i)*4
  3.   for %%p in (!rand!) do set get=!nums:~%%p,3!
  4.   set /a "val=get&0xff, lineOffs=(%%i>>3)-(val>>3), colOffs=(%%i&7)-(val&7)
  5.   set "offs=!offs!!lineOffs!:!colOffs! "
  6.   for %%v in (!val!) do set new=!new!!str:~%%v,1!
  7.   if #!rem!==#7 set new=!new!!nl!& set offs=!offs!!nl!
  8.   for %%a in (!get!) do set nums=!nums:%%a,=!
  9. )
复制代码





欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2