似乎没有一种简单的方法可以在批处理文件中获取字符串的长度。如,
SET MY_STRING=abcdefg
SET /A MY_STRING_LEN=???
如何找到MY_STRING
的字符串长度?
如果字符串长度函数处理字符串中包含转义字符的所有可能字符,则加分:!%^^()^!
。
答案 0 :(得分:79)
由于字符串长度没有内置函数,您可以像这样编写自己的函数:
@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-loops的简单strlen函数 它处理所有字符。
答案 1 :(得分:29)
您可以通过将字符串写入文件然后获取文件的长度,在两行中完全在批处理文件中完成。你只需要减去两个字节来考虑到最后添加的自动CR + LF。
假设您的字符串位于名为strvar
的变量中:
ECHO %strvar%> tempfile.txt
FOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 )
字符串的长度现在位于名为strlength
的变量中。
稍微详细一点:
FOR %%? IN (filename) DO ( ...
:获取有关文件的信息SET /A [variable]=[expression]
:以数字方式评估表达式%%~z?
:获取文件长度的特殊表达式将整个命令混为一行:
ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x
答案 2 :(得分:20)
我更喜欢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 msec
答案 3 :(得分:8)
前几行只是为了演示: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 loop”版本中效率不高。但它更容易理解,你的3GHz计算机可以在几分之一秒内完成几千次迭代。
答案 4 :(得分:5)
是的,当然有一种简单的方法,使用vbscript(或powershell)。
WScript.Echo Len( WScript.Arguments(0) )
将其保存为strlen.vbs
并保存在命令行
c:\test> cscript //nologo strlen.vbs "abcd"
使用for循环捕获结果(或完全使用vbscript作为脚本任务)
当然需要使用批处理创建繁琐的变通方法,并且没有理由不使用它,因为vbscript可用于每个Windows发行版(以及稍后的PowerShell)。
答案 5 :(得分:3)
如果您使用的是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,这对我有用。
答案 6 :(得分:3)
刚刚找到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%
输出结果为:
string "abcdef!%^^()^!" length = 14
它处理转义字符,比上面的大多数解决方案简单一个数量级,并且不包含循环,幻数,DelayedExpansion,临时文件等。
如果在批处理脚本之外使用(意味着手动将命令发送到控制台),请将%%RESULT%%
键替换为%RESULT%
。
如果需要,可以使用任何NOP命令将%ERRORLEVEL%
变量设置为FALSE
,例如echo. >nul
答案 7 :(得分:2)
我喜欢jmh_gr的two line approach。
除非在重定向之前将()
放在命令部分周围,否则它不适用于单个数字。由于1>
是一个特殊命令,“Echo is On”将被重定向到文件。
此示例应该处理单个数字,但不能处理字符串中可能包含的<
等其他特殊字符。
(ECHO %strvar%)> tempfile.txt
答案 8 :(得分:1)
@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 =以便用户输入它。 把它放在这里供将来参考。
答案 9 :(得分:1)
如果您坚持要在纯批处理中具有这个琐碎的功能,我建议这样做:
@echo off
set x=somestring
set n=0
set m=255
:loop
if "!x:~%m%,1!" == "" (
set /a "m>>=1"
goto loop
) else (
set /a n+=%m%+1
set x=!x:~%m%!
set x=!x:~1!
if not "!x!" == "" goto loop
)
echo %n%
PS。您必须启用延迟变量扩展才能运行此功能。
编辑。现在,我做了一个改进的版本:
@echo off
set x=somestring
set n=0
for %%m in (4095 2047 1023 511 255 127 63 31 15 7 3 1 0) do (
if not "!x:~%%m,1!" == "" (
set /a n+=%%m+1
set x=!x:~%%m!
set x=!x:~1!
if "!x!" == "" goto done
)
)
:done
echo %n%
编辑2。如果您的系统上装有C编译器或其他工具,则可以创建所需的程序,如果程序不存在,则会即时丢失。此方法非常通用。以字符串长度为例:
@echo off
set x=somestring
if exist strlen.exe goto comp
echo #include "string.h" > strlen.c
echo int main(int argc, char* argv[]) { return strlen(argv[1]); } >> strlen.c
CL strlen.c
:comp
strlen "%x%"
set n=%errorlevel%
echo %n%
您必须适当地设置PATH,INCLUDE和LIB。这也可以通过批处理脚本即时完成。即使您不知道自己是否有编译器,也不知道它在哪里,也可以在脚本中搜索它。
答案 10 :(得分:1)
只是另一个批处理脚本来计算字符串的长度,只需几行。它可能不是最快的,但它很小。子程序“:len”返回第二个参数的长度。第一个参数是要分析的实际字符串。 请注意 - 必须转义特殊字符,即批处理文件中的任何字符串都是如此。
@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 /a l=%l%+1&goto :len_loop
答案 11 :(得分:0)
我想通过说我不太了解编写代码/脚本/等来预先说明这一点。但我想我会分享一个我似乎想出来的解决方案。这里的大部分回复都有点过头了,所以我很想知道我所写的内容是否具有可比性。
@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
答案 12 :(得分:0)
@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 ########################
答案 13 :(得分:0)
这是非常简单!
纯批处理溶液。没有临时文件。没有长脚本。
@echo off
setlocal enabledelayedexpansion
set String=abcde12345
for /L %%x in (1,1,1000) do ( if "!String:~%%x!"=="" set Lenght=%%x & goto Result )
:Result
echo Lenght: !Lenght!
1000
是估计的最大字符串长度。根据需要进行更改。
答案 14 :(得分:0)
我做了这个简单的函数来求字符串的长度
for /l %%a in (0,1,10000) do if not "!text:~%%a,1!" == "" set/a text_len=!text_len!+1
您需要确保先定义 !text!
和 !text_len!
变量
答案 15 :(得分:-1)
@ECHO OFF
SET string=
SET /A stringLength=0
:CheckNextLetter
REM Subtract the first letter and count up until the string="".
IF "%string%" NEQ "" (
SET string=%string:~1%
SET /A stringLength=%stringLength%+1
GOTO :CheckNextLetter
) ELSE (
GOTO :TheEnd
)
:TheEnd
ECHO There is %stringLength% character^(s^) in the string.
PAUSE
这对我有用。希望这对其他人有用。无需调整任何长度。我只是删除第一个字母,然后与“”进行比较,直到字符串等于“”为止。
答案 16 :(得分:-1)
@echo off
title String Lenght
set /p str=String:
if exist "%tmp%\STR" (del "%tmp%\STR" /q)
echo %str% > "%tmp%\STR"
cd /d "%tmp%"
for %%P in (STR) do (set STRsize=%%~zP)
set /a result=%STRsize%-3
echo String lenght: %result%
pause>nul
exit /B
用于检测字符串长度的代码。
答案 17 :(得分:-3)
@echo off
title String Lenght
set /p str=String:
if exist "%tmp%\STR" (del "%tmp%\STR" /q)
echo %str% > "%tmp%\STR"
cd /d "%tmp%"
for %%P in (STR) do (set STRsize=%%~zP)
set /a result=%STRsize%-3
echo String lenght: %result%
pause>nul
exit /B