Como você obtém o tamanho da string em um arquivo de lote?

Não parece ser uma maneira fácil de obter o tamanho de uma string em um arquivo de lote. Por exemplo,

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

Como eu encontraria o comprimento da string MY_STRING ?

Pontos de bônus se a function de comprimento de seqüência de caracteres manipular todos os caracteres possíveis em seqüências de caracteres, incluindo caracteres de escape, como este: !%^^()^! .

Como não existe uma function incorporada para comprimento de string, você pode escrever sua própria function da seguinte forma:

 @echo off setlocal set "myString=abcdef!%%^^()^!" call :strlen result myString echo %result% goto :eof :strlen   ( 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 ) 

Essa function precisa sempre de 13 loops, em vez de uma function strlen simples que precisa de strlen-loops.
Ele lida com todos os personagens.

Você pode fazer isso em duas linhas, totalmente em um arquivo de lote, gravando a seqüência em um arquivo e, em seguida, obtendo o tamanho do arquivo. Você apenas tem que subtrair dois bytes para contabilizar o CR + LF automático adicionado ao final.

Digamos que sua string esteja em uma variável chamada strvar :

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

O comprimento da string agora está em uma variável chamada strlength .

Em um pouco mais de detalhe:

  • FOR %%? IN (filename) DO ( ... FOR %%? IN (filename) DO ( ... : obtém informações sobre um arquivo
  • SET /A [variable]=[expression] : avalia a expressão numericamente
  • %%~z? : Expressão especial para obter o comprimento do arquivo

Para mash o comando inteiro em uma linha:

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

Eu prefiro a resposta aceita de jeb – é a solução mais rápida e a que eu uso em meus próprios scripts. (Na verdade, há algumas otimizações adicionais relacionadas ao DosTips, mas não acho que valham a pena)

Mas é divertido criar novos algoritmos eficientes. Aqui está um novo algoritmo que usa a opção 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 

O código subtrai 3 porque o analisador manipula o comando e adiciona um espaço antes que o CMD / V / C o execute. Isso pode ser evitado usando (echo(!%~1!^^^) .


Para aqueles que querem o desempenho mais rápido possível, a resposta do jeb pode ser adotada para uso como um lote “macro” com argumentos . Essa é uma técnica em lote avançada desenvolvida em DosTips que elimina o processo inerentemente lento de chamar uma: sub-rotina. Você pode obter mais informações sobre os conceitos por trás das macros em lote aqui , mas esse link usa uma syntax menos primitiva e menos desejável.

Abaixo está uma macro @strLen otimizada, com exemplos mostrando diferenças entre o uso de macro e: sub-rotina, bem como diferenças de desempenho.

 @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 

– Saída de amostra –

 @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 

As primeiras poucas linhas são simplesmente para demonstrar a 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 

Claro, isso não é tão eficiente na versão “13 loop” fornecida por jeb. Mas é mais fácil de entender, e seu computador 3GHz pode passar por alguns milhares de iterações em uma pequena fração de segundo.

Sim, claro que há uma maneira fácil, usando vbscript (ou powershell).

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

salve isso como strlen.vbs e na linha de comando

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

Use um loop for para capturar o resultado (ou use vbscript inteiramente para sua tarefa de script)

Certamente é melhor ter que criar soluções complicadas usando lote e não há desculpa para não usá-lo, pois o vbscript está disponível em cada distribuição do Windows (e no PowerShell posteriormente).

Se você estiver no Windows Vista +, tente este método Powershell:

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

ou alternativamente:

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

Estou no Windows 7 x64 e isso está funcionando para mim.

Eu gosto da abordagem de duas linhas de jmh_gr.

Ele não funcionará com números de dígito único, a menos que você coloque () ao redor da parte do comando antes do redirecionamento. desde 1> é um comando especial “Echo is On” será redirecionado para o arquivo.

Este exemplo deve cuidar de números de dígitos únicos, mas não de outros caracteres especiais, como < que pode estar na string.

 (ECHO %strvar%)> tempfile.txt 

Acabou de encontrar solução 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% 

A saída é:

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

Ele lida com caracteres de escape, uma ordem de magnitude mais simples do que a maioria das soluções acima, e não contém loops, números mágicos, DelayedExpansion, arquivos temporários, etc.

No caso de uso fora do script em lote (significa colocar comandos para o console manualmente), substitua a chave %%RESULT%% por %RESULT% .

Se necessário, a variável %ERRORLEVEL% pode ser definida como FALSE usando qualquer comando NOP, por exemplo, echo. >nul echo. >nul

Apenas outro script em lote para calcular o tamanho de uma string, em apenas algumas linhas. Pode não ser o mais rápido, mas é bem pequeno. A sub-rotina “: len” retorna o comprimento no segundo parâmetro. O primeiro parâmetro é a cadeia real sendo analisada. Por favor, note – caracteres especiais devem ser escapados, que é o caso de qualquer seqüência no arquivo em lotes.

 @echo off setlocal call :len "Sample text" a echo The string has %a% characters. endlocal goto :eof :len   - 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 & 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) 

defina o var para o que você quer encontrar o comprimento dele ou altere-o para definir / p var = para que o usuário insira. Colocando isso aqui para referência futura.

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

Eu quero começar isso dizendo que não sei muito sobre escrever código / script / etc. mas pensei em compartilhar uma solução que pareço ter encontrado. A maioria das respostas aqui passou pela minha cabeça, então eu estava curioso para saber se o que eu escrevi é comparável.

 @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