找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 26530|回复: 14

[分享]批处理分段法计算字符串长度

[复制链接]
发表于 2009-4-23 01:05:20 | 显示全部楼层 |阅读模式
受到拆半算法的启发,突然想到这种分段法。与大家分亨,不知道是否已有先例。
此方法无论是通用性和速度,都具有很大的优越性。

  1. @echo off&setlocal enabledelayedexpansion
  2. set str=
  3. :rep

  4. :::::串长度计算代码:::::::::
  5. set/a end=8189,add=end
  6. :lp
  7. if %add%==1 goto :ok
  8. set /a ben=end-add,add=^(end-ben^)/30+1
  9. for /l %%a in (%ben%,%add%,%end%) do (if "!str:~%%a,1!"=="" set end=%%a&goto :lp)
  10. set end=0
  11. :ok
  12. :::::::::::::::::::::::::::::::


  13. ::测试用代码
  14. echo %end%
  15. set str=!str!a
  16. pause
  17. goto :rep
复制代码

评分

参与人数 1PB +11 收起 理由
随风 + 11 非常不错!

查看全部评分

发表于 2009-4-23 01:08:36 | 显示全部楼层

何必这么复杂呢

  1. @echo off
  2. SETLOCAL ENABLEDELAYEDEXPANSION
  3. set /p a=请输入要计算长度的字符串:
  4. for /l %%a in (1,1,100000) do (
  5. set k=!a:~%%a,1!
  6. if not defined k (
  7. echo 字符串长度:%%a
  8. pause>nul
  9. exit
  10. )
  11. )
复制代码

[ 本帖最后由 lxzzr 于 2009-4-23 03:14 编辑 ]
发表于 2009-4-23 02:04:29 | 显示全部楼层

回复 2楼 的帖子

lxzzr 版主想简单了吧。
你的代码1000000000000000000已经超出了cmd的最大数字范围,cmd把他当作字符串处理,所以很快,但%%a不可能得到最终的值,改为一百万再试试?
并且代码获取字符串长度后,如果还需要继续运行怎么办?
  1. @echo off
  2. SETLOCAL ENABLEDELAYEDEXPANSION
  3. set /p a=请输入要计算长度的字符串:
  4. for /l %%a in (1,1,1000000) do (
  5.    set k=!a:~%%a,1!
  6.    if not defined k (
  7.    echo 字符串长度:%%a
  8.    goto loop
  9. ))
  10. :loop
  11. echo 这里还需要对字符串进行处理。
  12. pause
复制代码
发表于 2009-4-23 03:15:19 | 显示全部楼层
随风版主说的是,我想的有点简单了....
 楼主| 发表于 2009-4-23 17:49:32 | 显示全部楼层
改了一下,减少了一次goto :lp循环,并且for /l 次数也从30降为21,速度有所提升
  1. @echo off&setlocal enabledelayedexpansion
  2. set str=
  3. :rep


  4. set/a end=8189,add=end
  5. :lp
  6. if %add%==1 goto :ok
  7. set /a ben=end-add,add=^(end-ben+20^)/21
  8. for /l %%a in (%ben%,%add%,%end%) do (if "!str:~%%a,1!"=="" set end=%%a&goto :lp)
  9. set end=0
  10. :ok
  11. echo %end%



  12. set str=!str!a
  13. pause
  14. goto :rep
复制代码
二楼说的最简单的方法应该是这个吧:
str 为字符串变量

  1. if not defined str set num=0&goto :ok
  2. for /l %%a in (0,1,8189) do (if "!str:~%%a,1!"=="" set num=%%a&goto :ok)
  3. :ok
复制代码
此法并非不可用,只是效率一般,串越长越慢
虽然只有一个for ,并且for /l的速度很快,但是也需要时间的
因为在系统在解释for /l时已经分配了8189次if "!str...命令行

[ 本帖最后由 netbenton 于 2009-4-23 17:56 编辑 ]
发表于 2009-4-23 17:57:29 | 显示全部楼层

回复 5楼 的帖子

是否考虑写成 “函数”
 楼主| 发表于 2009-4-23 18:30:14 | 显示全部楼层
又改了一下,把8189改成了8190,否则最后一段取不到结果
写成函数如下:
  1. :::::::::::::::::::::::::::::::::::::::::
  2. :getstrlen  分段法取字符串长度
  3. ::  用法用途:
  4. ::  把代码放到批处理中作为函数使用
  5. ::  取指定字答串的长度
  6. ::  调用方法:
  7. ::  call :getstrlen 字符串变量名 结果变量名
  8. ::::::::::::::::::::::::::::::::::::::::::

  9. setlocal enabledelayedexpansion
  10. set "str=!%1!"
  11. :rep
  12. set/a end=8190,add=end
  13. :lp
  14. if %add%==1 goto :ok
  15. set /a ben=end-add,add=^(end-ben+20^)/21
  16. for /l %%a in (%ben%,%add%,%end%) do (if "!str:~%%a,1!"=="" set end=%%a&goto :lp)
  17. set end=0
  18. :ok
  19. endlocal&set %2=%end%&goto :eof
复制代码
 楼主| 发表于 2009-4-24 00:53:20 | 显示全部楼层

没有goto :lp也可以了


  1. @echo off&setlocal enabledelayedexpansion
  2. set str=
  3. :rep

  4. ::变量ds用来指定分段数,可随意指定(2到8190)都可以。
  5. set/a ds=4,ds1=ds-1

  6. if not defined str set end=-1&goto :ok
  7. set/a end=0,add=8190
  8. for /l %%a in (0,1,14) do (
  9. if !add!==1 goto :ok
  10. set /a end+=add,ben=end-add,add=^(end-ben+ds1^)/ds
  11. for /l %%b in (!ben!,!add!,!end!) do (if not "!str:~%%b,1!"=="" set end=%%b)
  12. )
  13. :ok
  14. set /a end+=1
  15. echo !end! !str!

  16. set str=!str!a
  17. pause
  18. goto :rep
复制代码

可以做到随意n分段,分为2段时,就像随风版主的拆半法了,到底分多少段才是最快速的呢?
发表于 2011-12-12 21:00:58 | 显示全部楼层
回复 8# netbenton


请问可以解释一下何为“折半算法”吗?我看了半天头都晕了都不明白啊~
发表于 2011-12-12 21:07:40 | 显示全部楼层
回复 9# raymai97


你的折半法是指 搜索 还是?
发表于 2011-12-12 21:15:13 | 显示全部楼层
回复 10# garyng


    这个帖子的折半算法~ 效率高很多,问题是我不明白啊~
发表于 2011-12-12 21:49:35 | 显示全部楼层
回复 11# raymai97

具体我也不清楚啦。。
可是效率极高!!
发表于 2011-12-12 22:08:22 | 显示全部楼层
回复 11# raymai97


回复 12# garyng


    十进制8191=4096+2048+1024+512+256+128+64+32+16+8+4+2+1=二进制的1111111111111
用二进制来理解可能比较简单,先判断第一位(从左至右)的状态,大于则标记相应位为 1,小于则标记为 0。
发表于 2011-12-12 23:23:57 | 显示全部楼层
回复 13# CrLf


OMG你们这群数学天才,汇编对你们来说肯定是小意思了……
我真的很好奇你们的头脑是怎样练出来的,难道你们在学校数学都是拿第一的?
真的很佩服你们,你们几年前的帖子比我现在的水平还要高,恐怕外国人也没这么强……

ok切入正题,我还是不太明白这段:
  1. set /a ben=end-add,add=^(end-ben^)/30+1
  2. for /l %%a in (%ben%,%add%,%end%) do (if "!str:~%%a,1!"=="" set end=%%a&goto :lp)
复制代码
先说上面那段:
ben=end-add(8189-8189)?
add=(end-ben)/30+1 (8189-0)/30+1
为何要除30+1呢?
发表于 2011-12-13 08:17:24 | 显示全部楼层
回复 14# raymai97


    这跟数学好有什么关系...
    那个代码中先除 30 再加 1 是用无限逼近的办法,类似于 batman 发过的开方算法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-18 13:19 , Processed in 0.023665 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表