Board logo

标题: 批处理函数的高效另类应用(免call的哦!) [打印本页]

作者: netbenton    时间: 2009-9-21 22:46     标题: 批处理函数的高效另类应用(免call的哦!)

高速的真正的批处理函数应用方法!
并非调用子过程。。。

我想这次应该可以把批处理编程推向一个新的台阶。
目前只支持一个参数,
欢迎大家加入讨论。。。
  1. @echo off
  2. ::定义函数
  3. set "d-h=setlocal enabledelayedexpansion&set/a dx=#a#&set xs=0123456789abcdef&(for /l %%z in (1,1,4) do set /a x%%z=dx%%16,dx=dx/16)&(for /f "tokens=1-4" %%1 in ("!x1! !x2! !x3! !x4!") do set hx=!xs:~%%4,1!!xs:~%%3,1!&(if !hx!==00 set hx=)&(for %%z in ("!hx!!xs:~%%2,1!!xs:~%%1,1!") do endlocal&set #a#=%%~z))"
  4. ::10进制转为16进制的函数,参数入口#a#
  5. ::要在开启变量延迟之前定义
  6. setlocal enabledelayedexpansion
  7. for /l %%a in (1,7,1024) do (
  8.     set abc=%%a
  9.    
  10. (%d-h:#a#=abc%)
  11. rem 函数调用
  12. echo !abc!
  13. )
  14. pause
复制代码

[ 本帖最后由 netbenton 于 2009-9-22 13:10 编辑 ]
作者: wnc1988    时间: 2009-9-22 00:23

真是够强大的啊。佩服
作者: pusofalse    时间: 2009-9-22 02:08

变量即是语句,楼主的思维太强悍。
作者: netbenton    时间: 2009-9-22 08:03

可以支持多参数了
len函数为两个参数,
  1. @echo off
  2. ::定义函数
  3. set "d-h=setlocal enabledelayedexpansion&set/a dx=#a#&set xs=0123456789abcdef&(for /l %%z in (1,1,4) do set /a x%%z=dx%%16,dx=dx/16)&(for /f "tokens=1-4" %%1 in ("!x1! !x2! !x3! !x4!") do set hx=!xs:~%%4,1!!xs:~%%3,1!&(if !hx!==00 set hx=)&(for %%z in ("!hx!!xs:~%%2,1!!xs:~%%1,1!") do endlocal&set #a#=%%~z))"
  4. ::10进制转为16进制的函数,调用方法:%d-h:#a#=变量名%
  5. set "len=for /f "tokens=1-3" %%1 in ("#a#") do setlocal enabledelayedexpansion&(if defined %%2 (set /a z=8180,x=0&(for /l %%a in (1,1,14) do set/a "y=(z-x)/2+x"&(for %%b in (!y!) do if "!%%2:~%%b,1!" equ "" (set/a z=y) else (set/a x=y)))) else (set z=0))&(for %%z in ("!z!") do endlocal&set %%1=%%~z)"
  6. ::取字符串长度函数,调用方法:%len:#a#=结果变量名 字符串变量名%
  7. setlocal enabledelayedexpansion
  8. for /l %%a in (1,7,1024) do (
  9.     set abc=%%a
  10.         (%len:#a#=slen abc%)
  11.         (%d-h:#a#=abc%)
  12.         (%len:#a#=dlen abc%)
  13.         rem 函数调用
  14.         
  15.         echo %%a转成16进制为:!abc!   转换前字符数:!slen!  转换后字符数:!dlen!
  16. )
  17. pause
复制代码

[ 本帖最后由 netbenton 于 2009-9-22 13:10 编辑 ]
作者: qzwqzw    时间: 2009-9-22 10:44

思路确实够新
但是因为两个原因不建议推广
代码的可阅读性降低
环境变量的过分使用也会影响效率

对于函数的效率问题
我觉得还是传统的”goto对“来得更加简单、自由和高效

通常情况下
应该避免在组合语句(括号对中的语句)中使用函数
如果综合权衡后还是要使用
那么就需要保证组合语句的循环和递归级数满足设计要求
作者: netbenton    时间: 2009-9-22 12:02

这种方法,对于函数的内部结构,可读性是很差,但是对于主程序的可读性却表现得非常好

看:
(%len:#a#=slen abc%)
调用用函数len,作用是,计算变量abc中字符串的长度,把结果存到变量slen中

使用函数的作用不就是为了简化主程序吗?
而对于函数,通常都是引用前人或者自己常用的功能代码,只要根据注释使用就可以了,
根本就不必去理会函数的内部做了什么。就像其它编程语言调用api和dos中断一样,难道还要去了解其内部是怎么运行的吗?

有了这种函数,就算是批处理新手,也可以轻松写出高效的批处理来,
就算是老手要写较大型的批程序时,这些可是很好的砖瓦啊。
这种函数定义只要一行就可以了,不足处是要占用一个变量名,和环境变量空间,但是这对于效率来说,这点是微小的,因为一个call :sub子过程用时相当于30层的call,及执行300次的set var=n,当然有一点,call  sub.bat这种用法,要比call :sub 批处理内部子过程要快一半,但也是比用%len:#a#=var%多出来的时间,效率可想而知了。


经过这样封装的函数,是不可能会破坏主程序的结构的,4楼对len函数的使用,主程序和函数同进使用了同一个for令牌%%a却一样可以得到正确的结果。函数内部的变量使用完全是临时的,在函数结束时已经用endlocal清场,只保存返回结果。
作者: zqz0012005    时间: 2009-9-23 12:38

标题应该叫做:批处理另类的高效函数

其实是对预处理的一种灵活应用。
作者: qzwqzw    时间: 2009-9-23 15:26

是这样
需求是技术的动力
技术是需求的体现
既然出现这样的技术
自然就有其存在的意义
这一点毋庸置疑

但是技术的发展总是曲折反复的
它受到多方面的制约
效率
界面
标准
健壮
以及时机
能想到这些
说明你的技术已经登堂入室了

最后
感谢你对我回复的加分
感谢你为技术创新所做的努力
作者: zhouyongjun    时间: 2009-9-28 10:01

感谢楼主,看你帖子学到很多东西
你那定义大量变量的方法好用极了,这个就是它的延伸了
我现在去试着用这办法优化下我以前那反复call的代码
作者: Seter    时间: 2009-9-30 18:44

一般来说能实现函数就应该能实现递归把?不知道现不现实...
作者: cjiabing    时间: 2011-8-13 21:42

想说些赞美的话,不好说出口。在一次创作中,突然想起netbenton这种函数的用法,于是也山寨了一个,呵呵。确实如楼主所言,发展一些高效的、正确的、常用的函数很有必要,能够充分扩展批处理的功能,使得批处理累积起更大的功能,从而实现更高的跨越式的发展。

对于重复命令调用处理的方法和技术,目前看来有几种:
1、复制粘贴,重复出现。这种模式在执行任务与命令比较少的情况下可以使用,比如使用echo产生两三行空行,总比使用for产生的划算吧?这种模式的结果是造成大量重复代码,缺乏效率。
2、使用标签,GOTO跳转。把那些反复使用的同一功能段的代码做成一个标签,然后使用goto跳转,这是最基本的模式。但goto只负责跳出去而不跳回来,要想代码自动回来则需要再跳一次。
3、使用标签,Call调用。call的好处是跳到其他标签后能够自动跳回来。之所以能够自动跳回来,因为call在原来代码后面使用了标记,可能使用了更多的内存存储来暂停原来的进程。所以,相对而言,会显得较慢一些。但Call对参数有很好的支持,使得人们对其无法割舍。
4、使用FOR命令,化繁为简。将那些符合FOR特性的命令融合到FOR当中,即可减少必要的重复操作。
5、使用函数,扩大变量。将一些命令组合赋值到某一个特定的变量中,变成通用函数,支持参数,它不需要重新建立标签,但它占据了一个变量空间。这种模式适用于所赋值的命令组合比较简短,占用空间不大的变量函数中。可以方便封装以用于不同的批处理程序中。
作者: szjwxn    时间: 2011-11-25 18:29

在下菜鸟看的是云里雾里
作者: daols    时间: 2012-2-3 07:01

强势围观下...好强大...
作者: caruko    时间: 2012-3-15 12:55

总的来说吧,封装函数在写大型程序时,可以提高可读性,提高效率,但是参数及自由度不高。

而批处理擅长的简短程序来说,用处不大,复制粘贴几次重复代码也不会影响效率和可读性。

只适合高手挑战极限用。
作者: lgwindows    时间: 2012-4-10 08:55

刚学,真的看不懂,看大家讨论的氛围,顶一个
作者: breakme    时间: 2012-7-30 18:15

看不懂啊,看不懂@!高手!
作者: huzhiqiang91    时间: 2013-7-5 00:24

思路很新颖,之前我真没想到可以把一个语句定义成一个变量,在这学习一下,不过我觉得封装函数对于批处理脚本来说能带来多大方便。总之先自己尝试一下写一个吧
作者: PowerShell    时间: 2013-7-5 11:18

1 挺牛
2 简直是天书!
3 用了powershell就可以避免上述问题。呵呵,请叫我王婆,我最爱卖powershelllll
作者: liu888mi    时间: 2013-12-2 21:25

看不懂啊,看不懂@!高手!简直是天书!
作者: zx317582225    时间: 2014-4-20 15:35

好好学习!
作者: amwfjhh    时间: 2014-11-5 14:42

“登堂入室”,这个形容楼主真太贴切不过了。看这段代码眼睛都看花了……
作者: HOPE2021    时间: 2023-1-30 18:20

本帖最后由 HOPE2021 于 2023-1-30 18:39 编辑

回复 1# netbenton
您的D-H函数似乎不能很好地处理有符号的数字,而且会忽略数字的高十六位。我写了一个支持有符号数并支持直接传递参数的CHex函数,请您看看?
(P.S. 最近 VB 写多了,写出来的批处理代码又慢又长)
  1. @Echo Off & @Goto :Main
  2. :Main
  3. @Call :LoadFunctions
  4. SetLocal EnableExtensions EnableDelayedExpansion
  5. For /L %%I in (-64,1,63) Do (
  6. Set i=%%I
  7. %CHex:pReturn:lngDec=strHex:!i!%
  8. Echo.!i! 的十六进制形式是 !strHex!
  9. )
  10. EndLocal
  11. %CHex:pReturn:lngDec=strHex:-1%
  12. Echo.-1 的十六进制形式是 %strHex%
  13. %CHex:pReturn:lngDec=strHex:05347%
  14. Echo.05347(八进制) 的十六进制形式是 %strHex%
  15. @Pause > Nul
  16. @Exit /B
  17. :LoadFunctions
  18. Set "CHex=(For /F "Tokens=1,2 Delims=:" %%_ in ('Echo.pReturn:lngDec') Do (Set %%_=0 & SetLocal EnableExtensions EnableDelayedExpansion & Set "pRes=%%_" & Set /A lngTemp=%%`)) & Set "Hex=0123456789ABCDEF" & Set "strTemp=" & If !lngTemp!==0 ((For /F %%_ in ('Echo.!pRes!') Do (EndLocal & Set %%_=0))) Else ((For /L %%_ in (0,1,7) Do (If !lngTemp! Neq 0 (Set /A "bytTemp=lngTemp^&0x0000000F","lngTemp=(lngTemp^>^>4)^&0x0FFFFFFF" & (For /F %%` in ('Echo.!bytTemp!') Do (Set strTemp=!Hex:~%%`,1!!strTemp!))))) & (For /F "Tokens=1,2 Delims=:" %%_ in ('Echo.!pRes!:!strTemp!') Do (EndLocal & Set %%_=%%`)))"
  19. @Goto :Eof
复制代码





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