ind*_*div 63 windows string batch-file
似乎没有一种简单的方法来获取批处理文件中字符串的长度.例如,
SET MY_STRING=abcdefg
SET /A MY_STRING_LEN=???
Run Code Online (Sandbox Code Playgroud)
我怎样才能找到字符串的长度MY_STRING
?
如果字符串长度函数处理包括转义字符在内的字符串中的所有可能字符,则奖励积分如下:!%^^()^!
.
jeb*_*jeb 83
由于字符串长度没有内置函数,您可以编写自己的函数,如下所示:
@echo off
setlocal
REM *** Some tests, to check the functionality ***
REM *** An emptyStr has the length 0
set "emptyString="
call :strlen result emptyString
echo %result%
REM *** This string has the length 14
set "myString=abcdef!%%^^()^!"
call :strlen result myString
echo %result%
REM *** This string has the maximum length of 8191
setlocal EnableDelayedExpansion
set "long=."
FOR /L %%n in (1 1 13) DO set "long=!long:~-4000!!long:~-4000!"
(set^ longString=!long!!long:~-191!)
call :strlen result longString
echo %result%
goto :eof
REM ********* function *****************************
:strlen <resultVar> <stringVar>
(
setlocal EnableDelayedExpansion
(set^ tmp=!%~2!)
if defined tmp (
set "len=1"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!tmp:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "tmp=!tmp:~%%P!"
)
)
) ELSE (
set len=0
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
Run Code Online (Sandbox Code Playgroud)
这个函数总是需要13个循环,而不是需要strlen循环的简单strlen函数.
它处理所有角色.
Jos*_*nig 32
您可以通过将字符串写入文件然后获取文件的长度,在两行中完全在批处理文件中完成.您只需要减去两个字节来考虑添加到结尾的自动CR + LF.
假设您的字符串位于一个名为的变量中strvar
:
ECHO %strvar%> tempfile.txt
FOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 )
Run Code Online (Sandbox Code Playgroud)
字符串的长度现在位于一个名为的变量中strlength
.
稍微详细一点:
FOR %%? IN (filename) DO ( ...
:获取有关文件的信息SET /A [variable]=[expression]
:用数字方式评估表达式%%~z?
:获取文件长度的特殊表达式 将整个命令混为一行:
ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x
Run Code Online (Sandbox Code Playgroud)
dbe*_*ham 23
我更喜欢jeb接受的答案 - 它是最快的已知解决方案,也是我在自己的脚本中使用的解决方案.(实际上在DosTips上还有一些额外的优化,但我认为它们不值得)
但是提出新的高效算法很有趣.这是一个使用FINDSTR/O选项的新算法:
@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
Run Code Online (Sandbox Code Playgroud)
代码减去3,因为解析器在CMD/V/C执行它之前调整命令并添加空格.它可以通过使用来防止(echo(!%~1!^^^)
.
对于那些希望获得绝对最快性能的人来说,可以采用jeb的答案作为带参数的批量"宏".这是一种在DosTips中开发的高级批处理技术,它消除了CALLing a:子例程的固有缓慢过程.您可以在此处获得有关批处理宏背后的概念的更多背景知识,但该链接使用更原始,不太理想的语法.
下面是一个优化的@strLen宏,其中的示例显示了宏和子例程使用之间的差异,以及性能差异.
@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
Run Code Online (Sandbox Code Playgroud)
- 样品输出 -
@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
Run Code Online (Sandbox Code Playgroud)
Cod*_*nes 10
前几行只是为了演示: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
Run Code Online (Sandbox Code Playgroud)
当然,这在jeb提供的"13 loop"版本中效率不高.但它更容易理解,你的3GHz计算机可以在几分之一秒内完成几千次迭代.
是的,当然有一种简单的方法,使用vbscript(或powershell).
WScript.Echo Len( WScript.Arguments(0) )
Run Code Online (Sandbox Code Playgroud)
将其保存为strlen.vbs
命令行
c:\test> cscript //nologo strlen.vbs "abcd"
Run Code Online (Sandbox Code Playgroud)
使用for循环捕获结果(或完全使用vbscript进行脚本编写任务)
当然需要使用批处理创建繁琐的变通方法,没有理由不使用它,因为vbscript可用于每个Windows发行版(以及后面的PowerShell).
刚刚找到的ULTIMATE解决方案:
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%
Run Code Online (Sandbox Code Playgroud)
输出为:
string "abcdef!%^^()^!" length = 14
Run Code Online (Sandbox Code Playgroud)
它处理转义字符,比上面的大多数解决方案简单一个数量级,并且不包含循环,幻数,DelayedExpansion,临时文件等。
如果在批处理脚本之外使用(意味着手动将命令放入控制台),请用替换%%RESULT%%
key %RESULT%
。
如果需要,%ERRORLEVEL%
可以FALSE
使用任何NOP命令将变量设置为例如echo. >nul