如何获得batch file中的string长度?

似乎没有一种简单的方法来获取batch file中string的长度。 例如,

SET MY_STRING=abcdefg SET /A MY_STRING_LEN=??? 

我如何findMY_STRING的string长度?

如果string长度函数处理包括转义字符的string中的所有可能字符,则为加分: !%^^()^!

由于没有内置函数的string长度,你可以编写你自己的函数,如下所示:

 @echo off setlocal set "myString=abcdef!%%^^()^!" call :strlen result myString echo %result% goto :eof :strlen <resultVar> <stringVar> ( setlocal EnableDelayedExpansion set "s=!%~2!#" set "len=0" for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%%P,1!" NEQ "" ( set /a "len+=%%P" set "s=!s:~%%P!" ) ) ) ( endlocal set "%~1=%len%" exit /b ) 

这个函数总是需要13个循环,而不是一个简单的需要strlen循环的strlen函数。
它处理所有的字符。

你可以在两行内完成一个batch file,把这个string写入一个文件,然后获取文件的长度。 你只需要减去两个字节来考虑添加到最后的自动CR + LF。

假设您的string位于名为strvar的variables中:

 ECHO %strvar%> tempfile.txt FOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 ) 

string的长度现在在一个名为strlength的variables中。

稍微更详细些:

  • FOR %%? IN (filename) DO ( ... FOR %%? IN (filename) DO ( ... :获取关于文件的信息
  • SET /A [variable]=[expression] :以数字方式评估expression式
  • %%~z? :特殊expression式来获取文件的长度

把整个命令捣碎成一行:

 ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x 

我更喜欢jeb接受的答案 – 这是最快的已知解决scheme,我用我自己的脚本。 (实际上DosTips还有一些额外的优化,但我不认为它们是值得的)

但是提出新的高效algorithm是很有趣的。 这是一个使用FINDSTR / O选项的新algorithm:

 @echo off setlocal set "test=Hello world!" :: Echo the length of TEST call :strLen test :: Store the length of TEST in LEN call :strLen test len echo len=%len% exit /b :strLen strVar [rtnVar] setlocal disableDelayedExpansion set len=0 if defined %~1 for /f "delims=:" %%N in ( '"(cmd /v:on /c echo(!%~1!&echo()|findstr /o ^^"' ) do set /a "len=%%N-3" endlocal & if "%~2" neq "" (set %~2=%len%) else echo %len% exit /b 

该代码将减去3,因为parsing器处理该命令,并在CMD / V / C执行之前添加一个空格。 可以通过使用(echo(!%~1!^^^)来防止。


对于那些想要获得绝对最快performance的人来说, jeb的答案可以作为批量“macros观”的参数来使用 。 这是在DosTips上开发的一种先进的批处理技术,它消除了CALLing a:子程序固有的缓慢过程。 您可以在这里获得有关批处理macros后面概念的更多背景信息 ,但该链接使用更原始的,不太理想的语法。

下面是一个优化的@strLenmacros,其中的例子显示了macros和子程序的使用情况,以及性能的差异。

 @echo off setlocal disableDelayedExpansion :: -------- Begin macro definitions ---------- set ^"LF=^ %= This creates a variable containing a single linefeed (0x0A) character =% ^" :: Define %\n% to effectively issue a newline with line continuation set ^"\n=^^^%LF%%LF%^%LF%%LF%^^" :: @strLen StrVar [RtnVar] :: :: Computes the length of string in variable StrVar :: and stores the result in variable RtnVar. :: If RtnVar is is not specified, then prints the length to stdout. :: set @strLen=for %%. in (1 2) do if %%.==2 (%\n% for /f "tokens=1,2 delims=, " %%1 in ("!argv!") do ( endlocal%\n% set "s=A!%%~1!"%\n% set "len=0"%\n% for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (%\n% if "!s:~%%P,1!" neq "" (%\n% set /a "len+=%%P"%\n% set "s=!s:~%%P!"%\n% )%\n% )%\n% for %%V in (!len!) do endlocal^&if "%%~2" neq "" (set "%%~2=%%V") else echo %%V%\n% )%\n% ) else setlocal enableDelayedExpansion^&setlocal^&set argv=, :: -------- End macro definitions ---------- :: Print out definition of macro set @strLen :: Demonstrate usage set "testString=this has a length of 23" echo( echo Testing %%@strLen%% testString %@strLen% testString echo( echo Testing call :strLen testString call :strLen testString echo( echo Testing %%@strLen%% testString rtn set "rtn=" %@strLen% testString rtn echo rtn=%rtn% echo( echo Testing call :strLen testString rtn set "rtn=" call :strLen testString rtn echo rtn=%rtn% echo( echo Measuring %%@strLen%% time: set "t0=%time%" for /l %%N in (1 1 1000) do %@strlen% testString testLength set "t1=%time%" call :printTime echo( echo Measuring CALL :strLen time: set "t0=%time%" for /l %%N in (1 1 1000) do call :strLen testString testLength set "t1=%time%" call :printTime exit /b :strlen StrVar [RtnVar] :: :: Computes the length of string in variable StrVar :: and stores the result in variable RtnVar. :: If RtnVar is is not specified, then prints the length to stdout. :: ( setlocal EnableDelayedExpansion set "s=A!%~1!" set "len=0" for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%%P,1!" neq "" ( set /a "len+=%%P" set "s=!s:~%%P!" ) ) ) ( endlocal if "%~2" equ "" (echo %len%) else set "%~2=%len%" exit /b ) :printTime setlocal for /f "tokens=1-4 delims=:.," %%a in ("%t0: =0%") do set /a "t0=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100 for /f "tokens=1-4 delims=:.," %%a in ("%t1: =0%") do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100 set /a tm=t1-t0 if %tm% lss 0 set /a tm+=24*60*60*100 echo %tm:~0,-2%.%tm:~-2% msec exit /b 

– 样本输出 –

 @strLen=for %. in (1 2) do if %.==2 ( for /f "tokens=1,2 delims=, " %1 in ("!argv!") do ( endlocal set "s=A!%~1!" set "len=0" for %P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%P,1!" neq "" ( set /a "len+=%P" set "s=!s:~%P!" ) ) for %V in (!len!) do endlocal&if "%~2" neq "" (set "%~2=%V") else echo %V ) ) else setlocal enableDelayedExpansion&setlocal&set argv=, Testing %@strLen% testString 23 Testing call :strLen testString 23 Testing %@strLen% testString rtn rtn=23 Testing call :strLen testString rtn rtn=23 Measuring %@strLen% time: 1.93 msec Measuring CALL :strLen time: 7.08 msec 

前几行仅仅是为了演示:strLen函数。

 @echo off set "strToMeasure=This is a string" call :strLen strToMeasure strlen echo.String is %strlen% characters long exit /b :strLen setlocal enabledelayedexpansion :strLen_Loop if not "!%1:~%len%!"=="" set /A len+=1 & goto :strLen_Loop (endlocal & set %2=%len%) goto :eof 

当然,这在jeb提供的“13循环”版本上效率不高。 但是它更容易理解,3GHz的计算机可以在几秒钟内通过几千次迭代。

是的,当然有一个简单的方法,使用VBScript(或PowerShell)。

 WScript.Echo Len( WScript.Arguments(0) ) 

保存为strlen.vbs和命令行

 c:\test> cscript //nologo strlen.vbs "abcd" 

使用for循环来捕获结果(或者完全用你的脚本任务使用vbscript)

当然,不得不使用批量创build麻烦的解决方法,并且没有理由不使用它,因为每个Windows发行版(以及后面的PowerShell)都提供了vbscript。

我喜欢jmh_gr的两行方法 。

除非在redirect之前在命令的部分放置() ,否则它将不能使用单个数字的数字。 因为1>是一个特殊的命令“Echo is On”将被redirect到文件。

这个例子应该照顾单个数字的数字,但不包括其他特殊字符,如<可能在string中。

 (ECHO %strvar%)> tempfile.txt 

如果您在Windows Vista +上,请尝试以下Powershell方法:

 For /F %%L in ('Powershell $Env:MY_STRING.Length') do ( Set MY_STRING_LEN=%%L ) 

或者可选地:

 Powershell $Env:MY_STRING.Length > %Temp%\TmpFile.txt Set /p MY_STRING_LEN = < %Temp%\TmpFile.txt Del %Temp%\TmpFile.txt 

我在Windows 7 x64上,这是为我工作。

只需要另一个批处理脚本来计算一个string的长度,只需要几行。 它可能不是最快的,但是很小。 子程序“:len”返回第二个参数的长度。 第一个参数是正在分析的实际string。 请注意 – 必须转义特殊字符,batch file中的任何string都是如此。

 @echo off setlocal call :len "Sample text" a echo The string has %a% characters. endlocal goto :eof :len <string> <length_variable> - note: string must be quoted because it may have spaces setlocal enabledelayedexpansion&set l=0&set str=%~1 :len_loop set x=!str:~%l%,1!&if not defined x (endlocal&set "%~2=%l%"&goto :eof) set /al=%l%+1&goto :len_loop 
 @echo off :: warning doesn't like * ( in mystring setlocal enabledelayedexpansion set mystring=this is my string to be counted forty one call :getsize %mystring% echo count=%count% of "%mystring%" set mystring=this is my string to be counted call :getsize %mystring% echo count=%count% of "%mystring%" set mystring=this is my string call :getsize %mystring% echo count=%count% of "%mystring%" echo. pause goto :eof :: Get length of mystring line ######### subroutine getsize ######## :getsize set count=0 for /l %%n in (0,1,2000) do ( set chars= set chars=!mystring:~%%n! if defined chars set /a count+=1 ) goto :eof :: ############## end of subroutine getsize ######################## 
 @echo off & setlocal EnableDelayedExpansion set Var=finding the length of strings for /l %%A in (0,1,10000) do if not "%Var%"=="!Var:~0,%%A!" (set /a Length+=1) else (echo !Length! & pause & exit /b) 

将var设置为你想要查找的长度,或者将其改为设置/ p var =,以便用户input它。 把这个放在这里供将来参考。

我想通过说我不太了解编写代码/脚本/等等来作为序言。 但认为我会分享一个我似乎已经提出的解决scheme。 这里的回应大部分都是我的头脑,所以我很想知道我写的是否可比。

 @echo off set stringLength=0 call:stringEater "It counts most characters" echo %stringLength% echo.&pause&goto:eof :stringEater set var=%~1 :subString set n=%var:~0,1% if "%n%"=="" ( goto:eof ) else if "%n%"==" " ( set /a stringLength=%stringLength%+1 ) else ( set /a stringLength=%stringLength%+1 ) set var=%var:~1,1000% if "%var%"=="" ( goto:eof ) else ( goto subString ) goto:eof 

刚发现ULTIMATE解决scheme:

 set "MYSTRING=abcdef!%%^^()^!" (echo "%MYSTRING%" & echo.) | findstr /O . | more +1 | (set /P RESULT= & call exit /B %%RESULT%%) set /A STRLENGTH=%ERRORLEVEL%-5 echo string "%MYSTRING%" length = %STRLENGTH% 

输出是:

 string "abcdef!%^^()^!" length = 14 

它可以处理转义字符,比上面大多数解决scheme简单一个数量级,并且不包含循环,幻数,DelayedExpansion,临时文件等。

如果在批处理脚本之外使用(意思是将命令手动放入控制台), %%RESULT%%键replace为%RESULT%

如果需要,可以使用任何NOP命令(例如echo. >nul%ERRORLEVEL%variables设置为FALSE echo. >nul echo. >nul