似乎没有一种简单的方法来获取批处理文件中字符串的长度。例如,
SET MY_STRING=abcdefg
SET /A MY_STRING_LEN=???如何找到MY_STRING的字符串长度?
如果string length函数处理字符串中所有可能的字符,包括转义字符,就会得到加分,比如:!%^^()^!。
发布于 2011-04-30 20:01:48
由于没有内置的字符串长度函数,您可以编写自己的函数,如下所示:
@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
)这个函数需要13个循环,而不是一个需要strlen -loop的简单strlen函数。
它可以处理所有字符。
奇怪的表达式(set^ tmp=!%~2!)是处理超长字符串所必需的,否则就不可能复制它们。
发布于 2011-12-20 02:54:30
通过将字符串写入文件,然后获取文件的长度,可以在批处理文件中完整地使用两行代码。您只需减去两个字节即可计算添加到末尾的自动CR+LF。
假设您的字符串在一个名为strvar的变量中
ECHO %strvar%> tempfile.txt
FOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 )字符串的长度现在位于一个名为strlength的变量中。
更详细地说:
FOR %%? IN (filename) DO ( ...:获取有关fileSET /A [variable]=[expression]的信息:计算表达式numerically%%~z?:特殊表达式以获取文件的长度要在一行中合并整个命令,请执行以下操作:
ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x发布于 2012-12-18 07:44:45
我更喜欢jeb's accepted answer -它是已知的最快的解决方案,也是我在自己的脚本中使用的解决方案。(实际上在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代码减去3是因为解析器会在CMD /V /C执行命令之前添加一个空格。它可以通过使用(echo(!%~1!^^^)来预防。
对于那些想要尽可能获得最快性能的人,可以采用jeb's answer作为batch "macro" with arguments。这是在DosTips上开发的一种高级批处理技术,它消除了CALLing a:子例程固有的缓慢进程。您可以获得more background on the concepts behind batch macros here,但该链接使用了更原始、更不可取的语法。
下面是一个优化的@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--示例输出--
@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 msechttps://stackoverflow.com/questions/5837418
复制相似问题