标题: [分享]批处理折半法获取变量的长度(即:字符数) [打印本页]
作者: 随风 时间: 2009-4-18 14:34 标题: [分享]批处理折半法获取变量的长度(即:字符数)
获取变量的长度(即:字符数)
目前常见的方法好像只有一种,那就是逐字判断,也就是一个一个的去数,
此种方法虽能实现但有两个最大的缺点
一、逐字判断,效率很低,速度取决于变量的长度,越长就越慢。
二、必须使用goto进行循环,若是对文本逐行进行判断时还必须用call先跳出for又一次影响效率
.
以下代码打破了此种常规,无论变量的字符数是多少,(1-8189)
for /L 都只需循环14次即可得到结果,且不用goto和call
原理很简单
首先我们知道变量的最多字符数为8192这其实是包括了变量名和等号及set后面的那个空格,所以变量的实际长度最多只允许有8189个。
首先判断变量是否为超过8189个,如果没有则把8189除以2再判断,再没有再除以2
如此经过几次循环就能得到变量字符数的上限和下限,也就是大大缩小了范围,再在此范围内重复前面的循环即可得到最终结果。
为考虑极端情况(字符数为8189个时)所以代码中变量名必须是单一字母,且不能加引号。
书写时注意别在后面误加空格。。。- @echo off&rem 判断变量长度 折半法
- ::@随风 @bbs.bathome.net @2009-04-18
- for /f "delims=" %%a in (a.txt) do (
- set s=%%a&set /a sun+=1
- setlocal enabledelayedexpansion&set "var="
- set /a n=8189*2,max=1
- for /l %%a in (1 1 14) do (
- if defined var set /a n=var
- set /a n/=2
- for %%i in (!n!) do (
- if "!s:~%%i,1!"=="" (set /a var=n) else (
- set s=!s:~%%i!&set /a max+=%%i,var-=%%i
- )))
- echo 第!sun! 行的字符数为: !max! 个
- endlocal
- )
- pause
复制代码
以下是函数封装- :loop 不能处理%号,变量字符数上限为8187个。
- ::@随风 @bbs.bathome.net @2009-04-18
- set "s=%~1"&rem 判断变量长度(封装)折半法
- setlocal enabledelayedexpansion
- set /a n=8189*2,max=1&set "var="
- for /l %%a in (1 1 14) do (
- if defined var set /a n=var
- set /a n/=2
- for %%i in (!n!) do (
- if "!s:~%%i,1!"=="" (set /a var=n) else (
- set s=!s:~%%i!&set /a max+=%%i,var-=%%i
- )))
- endlocal&set %~2=%max%&goto :EOF
复制代码
[ 本帖最后由 随风 于 2009-4-18 17:00 编辑 ]
作者: defanive 时间: 2009-4-18 15:50
计算字符串长度,这个话题经久不息啊。。。
这个算法很不错。。。
作者: 随风 时间: 2009-4-18 16:24 标题: 回复 3楼 的帖子
字符数不是字节,无论是单个汉字还是单个字母都是一个字符。
作者: 随风 时间: 2009-4-18 16:32 标题: 回复 5楼 的帖子
第一步、判断变量第8190位是否为空
第二步、若为空,则 8190/2=4095 判断变量第 4096位是否为空
第三步、若为空、则 4095/2=2047 判断变量第 2048位是否为空
。。。。。。。。。
。。。。。。。。。
直到不为空,假设第三步以不为空,则得出变量字符数上限为4095下限为2047,再在这个范围内重新判断。
作者: Batcher 时间: 2009-4-18 16:40 标题: 回复 7楼 的帖子
可以google搜索“折半查找法”,学习一下思路。
作者: 随风 时间: 2009-4-18 16:42
折半查找法 ?
原来还有专业术语?查查看。。。
作者: xxx 时间: 2009-4-18 19:16
二分法总是伟大的!
作者: xushaolong2009 时间: 2009-4-18 22:24
请问- set s=!s:~%%i!&set /a max+=%%i,var-=%%i
复制代码
是怎么执行的或是怎样理解?!
我想了很久就是得不出所以然??
作者: defanive 时间: 2009-4-18 22:28
回LS:
代码等同于
set s=!s:~%%i!
set /a max=max+%%i
set /a var=var-%%i
作者: myzwd 时间: 2009-4-19 00:12 标题: 回复 1楼 的帖子
好。这就是数学上的闭区间套定里的原理。破有点数学上的逼近的思想是味道。
作者: batman 时间: 2009-4-19 11:58
辅以小代码帮大家理解折半法:- @echo off&rem 利用折半法准确判断输入数
- set /p input=请输入一个整数:
- set /a min=1^<^<31,max=~min&rem max、min分别为cmd所能处理的最大、最小数
- :loop
- set /a pin=(max+min)/2&rem 折半
- if %input% lss %pin% set /a max=pin
- if %input% equ %pin% goto end
- if %input% gtr %pin% set /a min=pin
- set /a n+=1&goto loop
- :end
- cls&echo 循环了%n%次得出输入的数是%pin%
- pause>nul
复制代码
[ 本帖最后由 batman 于 2009-4-19 12:00 编辑 ]
作者: rat 时间: 2009-4-21 11:53
从何得知?到底是字节数还是字符数?
作者: Batcher 时间: 2009-4-21 12:00 标题: 回复 16楼 的帖子
Here we go:
http://bbs.bathome.net/viewthread.php?tid=3403#pid21569
作者: neorobin 时间: 2009-12-11 19:08 标题: "撞码" 了
http://bbs.bathome.net/thread-6677-1-1.html
作者: zcydez 时间: 2010-8-23 12:57
我还有更好的方法!- @echo off
- set /p w=请输入一些文字:
- setlocal EnableDelayedExpansion
- for /l %%b in (0 1 8192) do (
- if "!w:~%%b,1!"=="" (echo 你输入了%%b个字!&goto a))
- :a
- pause
复制代码
作者: mac007cn 时间: 2011-1-17 21:02 标题: 回复 1楼
- ……无论变量的字符数是多少,(1-8189)for /L 都只需循环14次即可得到结果,……
复制代码
为什么要进行14次循环折半?
我们知道,微软说字符串最大长度是8192个字符(实际上还要小一些),因为8192=2^13,所以13次循环折半足矣。
作者: yzlsc 时间: 2012-3-15 23:24
本帖最后由 yzlsc 于 2012-3-16 00:10 编辑
刚才测试N次总是不对,原来没看清LZ最后一句: “书写时注意别在后面误加空格。。。”,问题就出在把set s=%%a&set /a sun+=1改成了set s=%%a & set /a sun+=1,&两边各加了一个空格。新手啊,没办法。
作者: muink 时间: 2015-5-11 21:07
自己也照葫芦画瓢写了一个,满有趣的- @echo off
- rem 字符串长度上限;替换8为你想要的数值,但值必须是2的冪
- set /a nem=8
- rem 前面以2为底的冪的指数
- set /a lop=3
- setlocal enabledelayedexpansion
-
- :test
- cls
- set /p "str=输入字符串:"
- if not defined str echo. 输入为空...&goto test_end
- set /a max=%nem%,min=0
- echo max : min : length
- echo ( x + y ) / 2 = z
- echo.
- for /l %%a in (1,1,%lop%) do (
- set /a "length=(max+min)/2"
- echo ^(!max!^) + ^(!min!^) ==^> ^(!length!^)
- for /f "delims=" %%b in ("!length!") do (
- if "!str:~%%b!" equ "" (
- echo 完成折半,提取完成,字串第^(!length!+1^)位^(为^)空,继续逼近,设置max^(!max!^)为length^(!length!^)
- set /a max=length
- ) else (
- echo 完成折半,提取完成,字串第^(!length!+1^)位^(非^)空,开始远离,设置min^(!min!^)为length^(!length!^)
- set /a min=length
- ) )
- echo ^(!max!^) ^| ^(!min!^) ^<== ^(!length!^)&echo.
- )
- rem 如果提取字串不为空则+1
- if "!str:~%length%!" neq "" set /a length+=1&echo 不为空+1
- echo.
- rem 继续判断是否溢出
- if "!str:~%length%!" neq "" (echo. 字符串str超过%nem%个字符) else echo. 经计算字符串str共有!length!个字符
- :test_end
- pause>nul
- goto test
复制代码
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |