it-swarm.com.de

Wie erhält man die Stringlänge in einer Batchdatei?

Es scheint nicht einfach zu sein, die Länge eines Strings in einer Batchdatei abzurufen. Z.B.,

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

Wie finde ich die Stringlänge von MY_STRING?

Bonuspunkte, wenn die Funktion Zeichenfolgenlänge alle möglichen Zeichen in Zeichenfolgen einschließlich Escape-Zeichen wie folgt behandelt: !%^^()^!.

59
indiv

Da es keine integrierte Funktion für die Stringlänge gibt, können Sie Ihre eigene Funktion wie folgt schreiben: 

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

Diese Funktion benötigt immer 13 Schleifen anstelle einer einfachen strlen-Funktion, die strlen-loops benötigt.
.__ behandelt alle Zeichen.

79
jeb

Sie können dies in zwei Zeilen tun, vollständig in einer Batchdatei, indem Sie die Zeichenfolge in eine Datei schreiben und dann die Länge der Datei abrufen. Sie müssen nur zwei Bytes abziehen, um die automatische CR + LF zu berücksichtigen, die am Ende hinzugefügt wird.

Nehmen wir an, Ihre Zeichenfolge befindet sich in einer Variablen namens strvar:

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

Die Länge der Zeichenfolge befindet sich jetzt in einer Variablen namens strlength.

Etwas ausführlicher:

  • FOR %%? IN (filename) DO ( ...: ruft Informationen zu einer Datei ab
  • SET /A [variable]=[expression]: wertet den Ausdruck numerisch aus
  • %%~z?: Spezieller Ausdruck, um die Länge der Datei zu ermitteln 

Um den gesamten Befehl in einer Zeile zusammenzufügen:

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

Ich bevorzuge die akzeptierte Antwort von jeb - es ist die schnellste bekannte Lösung, die ich in meinen eigenen Skripten verwende. (Tatsächlich gibt es ein paar zusätzliche Optimierungen, die sich auf DosTips beziehen, aber ich denke nicht, dass sie es wert sind.)

Es macht aber Spaß, neue effiziente Algorithmen zu entwickeln. Hier ist ein neuer Algorithmus, der die Option FINDSTR/O verwendet:

@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

Der Code subtrahiert 3, da der Parser den Befehl jongliert und ein Leerzeichen hinzufügt, bevor CMD/V/C ihn ausführt. Mit (echo(!%~1!^^^) kann dies verhindert werden.


Für diejenigen, die die absolut schnellste Leistung wünschen, kann jebs Antwort zur Verwendung als batch "Makro" mit Argumenten verwendet werden. Dies ist eine fortschrittliche Batch-Technik, die bei DosTips entwickelt wurde und die den in sich langsamen Prozess des Aufrufens einer: Subroutine eliminiert. Sie können mehr Hintergrundwissen über die Konzepte hinter Batch-Makros erhalten , aber dieser Link verwendet eine eher primitive, weniger wünschenswerte Syntax.

Nachfolgend finden Sie ein optimiertes @ strLen-Makro mit Beispielen, die die Unterschiede zwischen der Verwendung des Makros und der: Subroutine sowie die Leistungsunterschiede zeigen.

@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

- Beispielausgabe -

@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
19
dbenham

Die ersten Zeilen dienen lediglich der Veranschaulichung der: strLen-Funktion. 

@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

Bei der von Jeb bereitgestellten "13 Loop" -Version ist dies natürlich nicht ganz so effizient. Es ist jedoch einfacher zu verstehen und Ihr 3 GHz-Computer kann in wenigen Sekunden durch einige tausend Iterationen schlüpfen.

8
Cody Barnes

Ja, natürlich gibt es eine einfache Möglichkeit, vbscript (oder Powershell) zu verwenden. 

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

speichern Sie dies als strlen.vbs und in der Befehlszeile

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

Verwenden Sie eine for-Schleife, um das Ergebnis zu erfassen (oder verwenden Sie vbscript vollständig für Ihre Skriptaufgabe).

Sicherlich, wenn Sie mit Batch umständliche Workarounds erstellen müssen. Es gibt keinen Grund, es nicht zu verwenden, da vbscript in jeder Windows-Distribution (und später in PowerShell) verfügbar ist.

5
ghostdog74

Gerade gefunden ULTIMATE Lösung:

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%

Die Ausgabe ist:

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

Es behandelt Escape-Zeichen, eine Größenordnung, die einfacher als die oben genannten Lösungen ist, und enthält keine Schleifen, magischen Zahlen, DelayedExpansion, Temp-Dateien usw.

Bei Verwendung außerhalb des Batch-Skripts (dh manuelle Befehle für die Konsole) ersetzen Sie den %%RESULT%%-Schlüssel durch %RESULT%.

Bei Bedarf kann %ERRORLEVEL% variable mit einem beliebigen NOP-Befehl auf FALSE gesetzt werden, z. echo. >nul

3
Alexander

Wenn Sie Windows Vista + verwenden, probieren Sie diese Powershell-Methode aus:

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

oder alternativ:

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

Ich bin unter Windows 7 x64 und das funktioniert für mich.

3
Farrukh Waheed

Ich mag den Zwei-Linien-Ansatz von Jmh_gr.

Es funktioniert nicht mit einstelligen Zahlen, es sei denn, Sie setzen () um den Teil des Befehls vor der Umleitung. da 1> ein spezieller Befehl ist, wird "Echo is On" in die Datei umgeleitet.

In diesem Beispiel sollten einstellige Zahlen berücksichtigt werden, nicht jedoch die anderen Sonderzeichen wie <, die in der Zeichenfolge enthalten sein können.

(ECHO %strvar%)> tempfile.txt
2
OnlineOverHere
@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)

setzen Sie die Variable auf das, was Sie suchen, um die Länge zu ermitteln, oder ändern Sie sie in set/p var =, so dass der Benutzer sie eingibt.

1
unpredictubl

Ein weiteres Batch-Skript zum Berechnen der Länge eines Strings in wenigen Zeilen. Es ist vielleicht nicht das Schnellste, aber es ist ziemlich klein. Das Unterprogramm ": len" gibt die Länge im zweiten Parameter zurück. Der erste Parameter ist der tatsächlich analysierte String. __ Bitte beachten Sie, dass Sonderzeichen mit Escapezeichen versehen werden müssen, d. H. Bei einem beliebigen String in der Batchdatei.

@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
1
Silkworm

Es ist viel einfacher !

Reine Batchlösung. Keine temporären Dateien. Keine langen Skripte.

@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 ist die maximal geschätzte Stringlänge. Ändern Sie es entsprechend Ihren Bedürfnissen.

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

Ich möchte dies vorwegnehmen, indem ich sage, dass ich nicht viel über das Schreiben von Code/Skript/etc weiß. Aber ich dachte, ich würde eine Lösung teilen, die ich anscheinend gefunden habe. Die meisten Antworten gingen irgendwie über meinen Kopf, daher war ich neugierig, ob das, was ich geschrieben habe, vergleichbar ist.

@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
0
John