[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
版本二:
一次任务与一次“@echo off命令”耗时比=1571
一次任务与一次“@echo off命令”耗时比=1463
用了外部命令...

TOP

个人感觉纯内部命令方案的循环量太大,无法用变量替换简化,而且受所需兼容的范围影响太严重,故而没打算往那个方向去考虑。

换了一个方案,只用一个外部命令,不过结果反而更慢了...
\w范围:
一次任务与一次“@echo off命令”耗时比=2944
可打印字符范围:
一次任务与一次“@echo off命令”耗时比=3094

TOP

回复 13# powerbat


    嗯,这应该是类似情况下循环量较小的方案,当其他所有字符都被处理为数字后,! 可以用 %str:!=33% 直接替换,而等号可以利用预处理替换为空格再替换为 61,但是虽然避免了大量的循环,定义大量变量带来的效率损失也同样是很恐怖的...


回复 14# lllsoslll


    我的方案虽然看起来效率比较高,但没有算法可言...而且按楼主给出的格式计算 echo off 与代码的效率比值在不同电脑上似乎结果不同(有趣的是,方案一是2900+,方案二的值是1400+,把之前另一台机子的结果颠倒了)

TOP

本帖最后由 CrLf 于 2012-3-2 17:49 编辑

回复 17# lllsoslll


    前不久写过将空格替换为几乎任意字符的高兼容性方案:
  1. @echo off
  2. set str=bbs.bathome.net=abc=123=ABC=@#$=test========
  3. rem 设置源字符串
  4. set 要替换的字符=[#]
  5. set "空="
  6. set "k= "
  7. set "t= "   ;此处引号内的内容为 t=tab制表符
  8. rem 初始化设置
  9. setlocal enabledelayedexpansion
  10. set str=!str:"=""!
  11. rem 将引号倍增,迫使所有字符均在引号对之外
  12. for %%a in (^^ ^& ^| ^( ^) ^< ^> ";" ",") do set "str=!str:%%~a=^^^%%~a!"
  13. rem 替换特殊字符
  14. endlocal&set "str=%str:!=^^!%"
  15. rem 关闭变量延迟,同时保留 str 变量
  16. set "str=%str: =!t!%"   ;此处引号内的内容为 str:tab制表符=!t!
  17. rem 分别替换制表符为变量 !t!
  18. for /f "delims=" %%a in (""%str: =!k!%"") do set str=%%~a
  19. rem 核心语句,替换空格为变量 !k! 后,利用等号在 for 中是分隔符的性质使其被预处理为空格
  20. setlocal enabledelayedexpansion
  21. set "str=!str: =%要替换的字符%!"
  22. rem 完成替换
  23. set "str=!空!%str%"
  24. rem 完成 !k!=空格、!t!=tab制表符 以及 ^ 的消隐,!空! 变量是用于在 %str% 不含 ! 号时触发二次转义
  25. set str=!str:""="!
  26. rem 引号减半,还原现场
  27. echo !str!
  28. rem 输出结果
  29. pause
复制代码
但是因为在 powerbat 的方案中,除了 = 与 ! 之外所有字符都被处理成 asc 了,所以可以这样:
  1. @echo off&setlocal enalbedelayedexpansion
  2. rem 运行环境
  3. rem [[[[[此行代表 powerbat 的方案实现代码]]]]]
  4. endlocal&set str=%str:!=33 %
  5. rem 关闭变量延迟,替换感叹号
  6. set str=%str: =space%
  7. rem 替换空格为 space
  8. for /f "delims=" %%a in (""%str%"") do set "str=%%~a"
  9. rem 替换等号为空格
  10. set str=%str: =32 %
  11. rem 替换空格(原来是等号)为 32
  12. set str=%str:space= %
  13. rem 替换 space 为空格
  14. echo %str%
  15. pause
复制代码

TOP

本帖最后由 CrLf 于 2012-3-2 18:47 编辑

回复 19# lllsoslll


    测试了一下,xp 下也能替换,但是我之前没有注意到连续的多个等号确实被替换为单个空格了,嗯,看来还是只能老老实实逐字判断

TOP

回复 21# lllsoslll


    所以才要先对其他特殊字符进行转义处理~

TOP

回复 24# lllsoslll


    先把能替换的替换了,不方便替换的再用偏移处理也许会很快呢?反正没有宽字符干扰,判断是否字母用 if xx geq a ... 就行了

    呃,试了下纯内部命令的方案,结果跟我预想的不太一样,给出的比值貌似很不正常...

TOP

回复 26# plp626


    对长变量畏之如虎...不过这确实是一种极大节省循环量的方案,等代码

TOP

回复 29# plp626


    貌似是我电脑上的内部命令运行太慢...@echo off 效率为 20312.8HZ
"find/?"与"@echo off" 耗时比=1657
"find/?"与"set a=#4647" 耗时比=1281

另:判断是否大/小写时我更喜欢用 delims
  1. set chr=a
  2. for /f "delims=ABCDEFGHIJKLMNOPQRSTUVWXYZ" %%a in ("%chr%") do echo 小写
复制代码

TOP

我的三个方案都很老实,没有什么出彩的地方(而且还内置了你的函数),但还是贴出来吧...

com 方案:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set str= ^^!"$%%&'()*+,-./09:;<=>?@AZ[^_`az|}~
  4. set<nul>$ /p=@!str!
  5. debug asc.com<%0 >nul 2>nul
  6. asc<$>ans.txt
  7. for /f "delims=" %%a in (ans.txt) do set ans=%%a
  8. echo %ans%
  9. pause&exit
  10. e100 B4 08 CD 21 B4 00 BB 64 00 E8 23 00 B3 0A 89 C8
  11. e110 E8 1C 00 88 CA 80 C2 30 CD 21 B2 20 CD 21 B4 0B
  12. e120 CD 21 3C 00 75 DA B4 09 BA 43 01 CD 21 CD 20 F6
  13. e130 F3 88 E1 38 F8 74 0B B7 FF B4 02 88 C2 80 C2 30
  14. e140 CD 21 C3 0D 0A 24
  15. rcx
  16. 46
  17. w
  18. q
复制代码
fc 方案
  1. @echo off
  2. set str=0123_ABCDXYZabcdxyz
  3. setlocal enabledelayedexpansion
  4. set<nul>$ /p"=@!str!"
  5. fc /b $ %comspec%>#
  6. for /f "eol=F skip=2 tokens=2" %%a in (#) do set "ans=!ans!%%a "
  7. echo %ans%
  8. pause
复制代码
纯内部命令方案(0x20~0x7f 范围):
  1. @echo off&setlocal enabledelayedexpansion
  2. set str= ^^!"$%%&'()*+,-./09:;<=>?@AZ[^_`az|}~
  3. set $=!str!#
  4. set N=&for %%z in (4096 2048 1024 512 256 128 64 32 16)do if !$:~%%z!. NEQ . set/aN+=%%z&set $=!$:~%%z!
  5. set $=!$!fedcba9876543210&set/aN+=0x!$:~16,1!-1
  6. set $= ^^!"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^_`abcdefghijklmnopqrstuvwxyz{|}~
  7. set "$=                                !$!"
  8. (for /l %%a in (32 1 127) do (
  9.    for /f "delims=" %%b in (":!$:~%%a,1!") do if "!str%%b=!" neq "!str!" echo %%a !$:~%%a,1!
  10. ))>#
  11. set $=
  12. for /l %%a in (0 1 %n%) do (
  13.    for /f "tokens=1,2 delims= " %%b in (#) do (
  14.       if "!str:~%%a,1!"=="%%c" set "ans=!ans!%%b "
  15.    )
  16. )
  17. echo %ans%
  18. pause
复制代码
纯内部命令方案([a-z_A-Z] 范围),结果测试时反而没有前一个方案快:
  1. @echo off
  2. set str=0123_ABCDXYZabcdxyz
  3. setlocal enabledelayedexpansion
  4. set $=!str!
  5. set N=&for %%z in (4096 2048 1024 512 256 128 64 32 16)do if !$:~%%z!. NEQ . set/aN+=%%z&set $=!$:~%%z!
  6. set $=!$!fedcba9876543210&set/aN+=0x!$:~16,1!
  7. set $=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
  8. (for %%z in ("48 1 57" "65 1 90" "96 1 122") do (
  9.    for /l %%a in (%%~z) do (
  10.       for /f "delims=" %%b in ("!$:~,1!") do (
  11.          if "!str%%b=!" neq "!str!" echo %%a !$:~,1!
  12.          set $=!$:~1!
  13.       )
  14.    )
  15. ))>#
  16. set $=
  17. for /l %%a in (0 1 !n!) do (
  18.    for /f "tokens=1,2 delims= " %%b in (#) do (
  19.       if "!str:~%%a,1!"=="%%c" set "$=!$!%%b "
  20.    )
  21. )
  22. set ans=!$:96=95!
  23. echo %ans%
  24. pause
复制代码
1

评分人数

    • plp626: 辛苦了,PB + 10 技术 + 1

TOP

本帖最后由 CrLf 于 2012-3-6 18:21 编辑

回复 40# terse


    一直以来都极力避免使用变量索引表(生命游戏后遗症),不过看来是成见太深了...没想到,此处使用索引表所简化的流程用时竟足以弥补冗长的变量表所降低的效率。
    另:不知你在 37 楼提到的 “FC 方案 省去临时文件” 是指什么呢?如果是指可以写成 for /f "tokens=2" %%a in ('fc ...') do ... 的话,那么可以测试一下,理论上的用时会将会翻倍,因为 for /? 中提到,在 for /f  里从命令获取输出时, “该字符串会被当作命令行,传递到一个子 CMD.EXE,其输出会被捕获到内存中,并被当作文件分析。”


回复 42# plp626


    先清空变量环境再测试,这 4n:2n+3  的差异应该就会凸显出来(假设为变量名为单字符),而且在只以第一个等号为依据判断变量名的 xp 系统下估计会体现得更明显

TOP

回复 44# terse


    因为楼主要求将保存为一行,所以不考虑超过变量上限的 hex 长度
如果要兼容大文件转 hex,那就加点料...
  1. @echo off
  2. copy /y /b %0+要测试的文件  tmp.tmp
  3. fc /b 要测试的文件 tmp.tmp>#
  4. setlocal enabledelayedexpansion
  5. for /f "eol=F skip=2 tokens=2" %%a in (#) do echo %%a
  6. pause
复制代码

TOP

本帖最后由 CrLf 于 2014-10-17 20:37 编辑

回复 47# neorobin


"eol=delims=" 设置的是 eol=d,可以这样:
  1. for /F "tokens=2,3* delims=,"eol^= %%a in .....
复制代码

TOP

返回列表