string 如何获取批处理文件中的字符串长度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5837418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 01:05:03  来源:igfitidea点击:

How do you get the string length in a batch file?

windowsstringbatch-file

提问by indiv

There doesn't appear to be an easy way to get the length of a string in a batch file. E.g.,

似乎没有一种简单的方法来获取批处理文件中字符串的长度。例如,

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

How would I find the string length of MY_STRING?

我如何找到 的字符串长度MY_STRING

Bonus points if the string length function handles all possible characters in strings including escape characters, like this: !%^^()^!.

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

回答by jeb

As there is no built in function for string length, you can write your own function like this one:

由于没有用于字符串长度的内置函数,您可以像这样编写自己的函数:

@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
)

This function needs always 13 loops, instead of a simple strlen function which needs strlen-loops.
It handles all characters.

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

The strange expression (set^ tmp=!%~2!)is necessary to handle ultra long strings, else it's not possible to copy them.

奇怪的表达式(set^ tmp=!%~2!)是处理超长字符串所必需的,否则无法复制它们。

回答by Joshua Honig

You can do it in two lines, fully in a batch file, by writing the string to a file and then getting the length of the file. You just have to subtract two bytes to account for the automatic CR+LF added to the end.

您可以在两行中完成,完全在批处理文件中,通过将字符串写入文件然后获取文件的长度。您只需要减去两个字节即可考虑添加到末尾的自动 CR+LF。

Let's say your string is in a variable called strvar:

假设您的字符串位于一个名为 的变量中strvar

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

The length of the string is now in a variable called strlength.

字符串的长度现在在一个名为 的变量中strlength

In slightly more detail:

稍微详细一点:

  • FOR %%? IN (filename) DO ( ...: gets info about a file
  • SET /A [variable]=[expression]: evaluate the expression numerically
  • %%~z?: Special expression to get the length of the file
  • FOR %%? IN (filename) DO ( ...: 获取有关文件的信息
  • SET /A [variable]=[expression]: 以数字方式计算表达式
  • %%~z?: 获取文件长度的特殊表达式

To mash the whole command in one line:

要在一行中混合整个命令:

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

回答by dbenham

I prefer jeb's accepted answer- it is the fastest known solution and the one I use in my own scripts. (Actually there are a few additional optimizations bandied about on DosTips, but I don't think they are worth it)

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

But it is fun to come up with new efficient algorithms. Here is a new algorithm that uses the FINDSTR /O option:

但是提出新的高效算法很有趣。这是一个使用 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

The code subtracts 3 because the parser juggles the command and adds a space before CMD /V /C executes it. It can be prevented by using (echo(!%~1!^^^).

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



For those that want the absolute fastest performance possible, jeb's answercan be adopted for use as a batch "macro" with arguments. This is an advanced batch technique devloped over at DosTips that eliminates the inherently slow process of CALLing a :subroutine. You can get more background on the concepts behind batch macros here, but that link uses a more primitive, less desirable syntax.

对于那些希望获得绝对最快性能的人,可以采用jeb 的答案作为带参数批处理“宏”。这是 DosTips 开发的高级批处理技术,它消除了调用 :subroutine 固有的缓慢过程。您可以在此处获得有关批处理宏背后概念的更多背景知识,但该链接使用了更原始、不太理想的语法。

Below is an optimized @strLen macro, with examples showing differences between the macro and :subroutine usage, as well as differences in performance.

下面是一个优化的 @strLen 宏,示例显示了宏和 :subroutine 用法之间的差异,以及性能上的差异。

@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

-- Sample Output --

-- 示例输出 --

@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

回答by Cody Barnes

The first few lines are simply to demonstrate the :strLen function.

前几行只是为了演示 :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

Of course, this is not quite as efficient at the "13 loop" version provided by jeb. But it is easier to understand, and your 3GHz computer can slip through a few thousand iterations in a small fraction of a second.

当然,这在 jeb 提供的“13 循环”版本中效率不高。但它更容易理解,您的 3GHz 计算机可以在几分之一秒内完成几千次迭代。

回答by ghostdog74

Yes, of course there's an easy way, using vbscript (or powershell).

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

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

save this as strlen.vbsand on command line

将此另存为strlen.vbs并在命令行上

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

Use a for loop to capture the result ( or use vbscript entirely for your scripting task)

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

Certainly beats having to create cumbersome workarounds using batch and there's no excuse not to use it since vbscript is available with each Windows distribution ( and powershell in later).

当然,必须使用批处理来创建繁琐的解决方法,并且没有理由不使用它,因为每个 Windows 发行版(以及稍后的 powershell)都提供 vbscript。

回答by Alexander

Just found ULTIMATE solution:

刚刚找到终极解决方案:

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%

The output is:

输出是:

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

It handles escape characters, an order of magnitude simpler then most solutions above, and contains no loops, magic numbers, DelayedExpansion, temp files, etc.

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

In case usage outside batch script (mean putting commands to console manually), replace %%RESULT%%key with %RESULT%.

如果在批处理脚本之外使用(意味着手动将命令放入控制台),请将%%RESULT%%key替换为%RESULT%.

If needed, %ERRORLEVEL%variable could be set to FALSEusing any NOP command, e.g. echo. >nul

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

回答by Farrukh Waheed

If you are on Windows Vista +, then try this Powershell method:

如果你使用的是 Windows Vista +,那么试试这个 Powershell 方法:

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

or alternatively:

或者:

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

I'm on Windows 7 x64 and this is working for me.

我在 Windows 7 x64 上,这对我有用。

回答by OnlineOverHere

I like the two line approachof jmh_gr.

我喜欢jmh_gr的两行方法

It won't work with single digit numbers unless you put ()around the portion of the command before the redirect. since 1>is a special command "Echo is On" will be redirected to the file.

除非您()在重定向之前放置命令部分,否则它不适用于个位数。因为1>是一个特殊命令“Echo is On”将被重定向到该文件。

This example should take care of single digit numbers but not the other special characters such as <that may be in the string.

此示例应处理单个数字,而不是其他特殊字符,例如<可能在字符串中的字符。

(ECHO %strvar%)> tempfile.txt

回答by Silkworm

Just another batch script to calculate the length of a string, in just a few lines. It may not be the fastest, but it's pretty small. The subroutine ":len" returns the length in the second parameter. The first parameter is the actual string being analysed. Please note - special characters must be escaped, that is the case with any string in the batch file.

只是另一个批处理脚本来计算字符串的长度,只需几行。它可能不是最快的,但它非常小。子程序 ":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

回答by unpredictubl

@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)

set the var to whatever you want to find the length of it or change it to set /p var= so that the user inputs it. Putting this here for future reference.

将 var 设置为您想要查找它的长度的任何值或将其更改为 set /p var= 以便用户输入它。将其放在这里以供将来参考。