在这里把论坛里求字符串长度的帖子做一个索引,大家可以把这些方法相互做个比较,
也许你能从中提炼出精华得到更代码更简洁效率更高效的方法也不一定。
求字符串长度练习(各种方法,真是大杂烩,很多带有goto循环的和调用三方的方法)
http://www.bathome.net/viewthread.php?tid=1480
当字符串较长时不得不用的方法——二分法
http://bbs.bathome.net/viewthread.php?tid=4219
对字符串长度有限制的查表法:
(9位和40位)http://www.bathome.net/viewthread.php?tid=3136 (6楼)
(16位)http://www.bathome.net/viewthread.php?tid=1249 (15楼)
(255位和1024位)http://www.bathome.net/viewthread.php?tid=5994
关于查表法还有很多相关代码,但思想都来源于9位法,不再列举。
======================================================
下面对这些求字符串长度的典型方法做个大致的汇总(代码均来自上面的索引贴子)
带有goto循环的方法,使得效率极为低下,这里不列举。
调用三方工具求长度的方法(如findstr/o 法,vbs法,for/f +dir法,xcopy法)效率更极为低下,这里不列举
方法一:思路最直接,代码最简短,但效率最低的方法(所求字符串较长时不宜采用)
原帖:http://www.bathome.net/viewthread.php?tid=1480- set/p str=input a string:
- set StrMAX=1000
- if not defined str set num=0&goto :ok
- for /l %%a in (0,1,%StrMAX%) do if "!str:~%%a,1!"=="" set num=%%a&goto :ok
- :ok
- echo 长度=!num!
复制代码 方法二:适合求长字符串的二分法:
原帖:http://bbs.bathome.net/viewthread.php?tid=4219- set /p s=please input a string:
- 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&echo 长度:%max%
复制代码 方法2.X 改进的二分搜索法(效率提高不少)
原帖:http://www.dostips.com/forum/viewtopic.php?f=3&t=1429- set /p str=input a string
- SETLOCAL ENABLEDELAYEDEXPANSION
- set "str=A!str!"
- set len=0
- for /L %%A in (12,-1,1) do (
- set /a "len|=1<<%%A"
- for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
- ENDLOCAL&echo 长度:%len%
复制代码 方法三:查表法
当所求字符串长度小于16时,速度最快最简短的查表法:
原帖:http://www.bathome.net/viewthread.php?tid=1249 (15楼)- set str=!str!fedcba9876543210&set/a len=0x!str:~15,1!
- echo 长度%len%
复制代码 当所求字符串字符数小于256时,速度最快(和上面代码效率相当)但代码较长的查表法
(一般说来,若用较短的程序生产该512表,至少需要16次set赋值语句的执行):
原帖: http://www.bathome.net/viewthread.php?tid=5994- @echo off&setlocal enabledelayedexpansion
- set/p str=input a string:
- set "$=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff%str%%str%"
- set/a len=0x!$:~-512,2!
- echo 长度:%len%
- pause
复制代码 方法四:等长替换计算法
原帖: 见本贴13楼lllsoslll的代码
(效率低于纯查表法,仅次于二分回溯法,优势在于表的生产不是很占用时间,且代码较短)
注意注意,"SET $=123456789$" 中,等号后的空白字符不是空格符!,而是ascii码为127的那个del字符;- set/p #1=string:?
-
- SET $=123456789$&FOR /L %%a in (1 1 3)Do SET $=!$!!$!!$!!$!!$!!$!
- SET $=!#1!`$!$!&SET $=!$:~0,2376!&SET $=!$:*`$=!&SET/A"$=-1,##=2372-(!$:123456789$=11+!+!$:~-1!)"
-
- echo length=!##!
复制代码 其他方法:待续。。。
--------------------------------- 更新1 -------------------------------
下面算法思想是基于16查表法,先求出待测字符串长度对16的"倍数值",再求对16的余数值;最后相加- @echo off
- setlocal enabledelayedexpansion
- :: 要测试的字符串
- set $1=123456789012345678901234567890123456789012345670
- :: 该字符串长度不超过256且大于0
- set $2=256
- rem ----------------------------------------------
-
- rem ----------------------------------------------
- echo 长度为 %$%
- pause
复制代码 当$2指定为256,这段代码的耗时相当于10次set赋值操作的耗时,
对于短字符串求长度,效率和代码体积上,很实用(效率很高,且算法简单,容易理解记忆)
---------------------------------------------------------------------
如果把16位表换为256为表, 那么对于小于4096长度以内的字符串,由于512位的表占用了不少空间, 会影响 外部环境 赋值,取值操作效率,
关于这个问题, 有时间我再做测试,
预期这个效率兴许会比1楼代码效率高。。。
经测试, 对于长字符串,该方法较比1楼的代码 效率提高了25%左右 |