Jak uzyskać długość łańcucha w pliku wsadowym?
Nie wydaje się być łatwym sposobem na uzyskanie długości łańcucha w pliku wsadowym. Np.,
SET MY_STRING=abcdefg
SET /A MY_STRING_LEN=???
Jak znaleźć Długość Łańcucha MY_STRING
?
Punkty bonusowe, jeśli funkcja długości łańcucha obsługuje wszystkie możliwe znaki w łańcuchach, w tym znaki escape, jak to: !%^^()^!
.
12 answers
Ponieważ nie ma wbudowanej funkcji dla długości łańcucha, możesz napisać własną funkcję w następujący sposób:
@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
)
Ta funkcja potrzebuje zawsze 13 pętli, zamiast prostej funkcji strlen, która potrzebuje pętli strlen.
Obsługuje wszystkie znaki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-03 02:16:04
Można to zrobić w dwóch wierszach, w pełni w pliku wsadowym, zapisując łańcuch znaków do pliku, a następnie pobierając jego długość. Wystarczy odjąć dwa bajty, aby uwzględnić automatyczne CR + LF dodane na końcu.
Załóżmy, że Twój łańcuch jest w zmiennej o nazwie strvar
:
ECHO %strvar%> tempfile.txt
FOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 )
Długość łańcucha jest teraz w zmiennej o nazwie strlength
.
Nieco bardziej szczegółowo:
-
FOR %%? IN (filename) DO ( ...
: pobiera informacje o pliku -
SET /A [variable]=[expression]
: Oceń wyrażenie numerycznie -
%%~z?
: wyrażenie specjalne do uzyskania długości pliku
Aby zmiksować całe polecenie w jednej linii:
ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 18:54:29
Preferuję akceptowaną odpowiedź Jeba - jest to najszybsze znane rozwiązanie i to, którego używam we własnych skryptach. (W rzeczywistości jest kilka dodatkowych optymalizacji na temat Dostipów, ale myślę, że nie są tego warte) {]} Ale fajnie jest wymyślać nowe wydajne algorytmy. Oto nowy algorytm, który używa opcji 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
Kod odejmuje 3, ponieważ parser żongluje komendą i dodaje spację, zanim CMD /V / C ją wykona. Może być zapobiegać za pomocą (echo(!%~1!^^^)
.
Dla tych, którzy chcą absolutnie najszybszej możliwej wydajności, odpowiedź Jeba może być przyjęta do użycia jako wsadowe "makro" z argumentami . Jest to zaawansowana technika wsadowa rozwijana przez at DosTips, która eliminuje z natury powolny proces wywoływania podprogramu:. Możesz uzyskać więcej tła na temat pojęć stojących za makrami wsadowymi tutaj , ale ten link używa bardziej prymitywnej, mniej pożądanej składni.
Poniżej znajduje się zoptymalizowane makro @ strLen, z przykładami pokazującymi różnice między użyciem makra i podprogramu:, a także różnice w wydajności.
@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
-- Przykładowe Wyjście --
@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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:28
Kilka pierwszych linii służy po prostu do zademonstrowania funkcji: 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
Oczywiście nie jest to tak efektywne w wersji" 13 loop " dostarczonej przez jeb. Ale jest to łatwiejsze do zrozumienia, a Twój komputer 3GHz może prześlizgnąć się przez kilka tysięcy iteracji w niewielkim ułamku sekundy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-27 20:59:01
Tak, oczywiście jest prosty sposób, używając vbscript (lub powershell).
WScript.Echo Len( WScript.Arguments(0) )
Zapisz to jako strlen.vbs
i w wierszu poleceń
c:\test> cscript //nologo strlen.vbs "abcd"
Użyj pętli for, aby uchwycić wynik (lub użyj VBScript całkowicie do zadania skryptowego)
Z pewnością przebije konieczność tworzenia uciążliwych obejść przy użyciu wsadowego i nie ma wymówki, aby go nie używać, ponieważ vbscript jest dostępny z każdą dystrybucją Windows (i powershell w późniejszym czasie).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-30 12:09:28
Jeśli korzystasz z systemu Windows Vista +, spróbuj użyć metody Powershell:
For /F %%L in ('Powershell $Env:MY_STRING.Length') do (
Set MY_STRING_LEN=%%L
)
Lub alternatywnie:
Powershell $Env:MY_STRING.Length > %Temp%\TmpFile.txt
Set /p MY_STRING_LEN = < %Temp%\TmpFile.txt
Del %Temp%\TmpFile.txt
Jestem na Windows 7 x64 i to mi działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-05 09:15:36
Lubię podejście dwuliniowe jmh_gr.
Nie będzie działać z numerami jednocyfrowymi, chyba że umieścisz ()
wokół części polecenia przed przekierowaniem. ponieważ {[2] } jest specjalne polecenie "Echo jest włączone" zostanie przekierowane do pliku.
Ten przykład powinien uwzględniać liczby jednocyfrowe, ale nie inne znaki specjalne, takie jak <
, które mogą znajdować się w łańcuchu.
(ECHO %strvar%)> tempfile.txt
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:08
Właśnie znalazłem ostateczne rozwiązanie:
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%
Wyjście to:
string "abcdef!%^^()^!" length = 14
Obsługuje znaki ucieczki, o rząd wielkości prostsze niż większość powyższych rozwiązań, i nie zawiera pętli, magicznych liczb, DelayedExpansion, plików tymczasowych itp.
W przypadku użycia poza skryptem wsadowym (czyli ręcznego umieszczania poleceń na konsoli), zastąp klawisz %%RESULT%%
na %RESULT%
.
W razie potrzeby zmienną %ERRORLEVEL%
można ustawić na FALSE
za pomocą dowolnego polecenia NOP, np. echo. >nul
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-12 16:27:55
Kolejny skrypt wsadowy do obliczania długości ciągu, w kilku wierszach. Może nie jest najszybszy, ale jest dość mały. Podprogram": len " zwraca długość w drugim parametrze. Pierwszym parametrem jest analizowany ciąg znaków. Uwaga-znaki specjalne muszą być unikalne, tak jest w przypadku dowolnego ciągu w pliku wsadowym.
@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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-09 19:11:47
@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)
Ustaw zmienną na dowolną jej długość lub zmień ją na set / P var= tak, aby użytkownik ją wprowadził. Umieszczam to tutaj dla przyszłych odniesień.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-11 18:03:20
@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 ########################
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-14 10:17:37
Chcę to poprzedzić mówiąc, że nie wiem zbyt wiele o pisaniu kodu/skryptu / itp. ale pomyślałem, że podzielę się rozwiązaniem, które wymyśliłem. Większość odpowiedzi tutaj trochę przeszło mi przez głowę, więc byłem ciekaw, czy to, co napisałem, jest porównywalne.
@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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-10 11:26:37