Package - Decreasing a variable in a substring does not work

I'm trying to cancel "hello" to "olleh". But the output displays "ooooo".
I think the problem is !string:~%back%,1! , because when I use echo to check whether the back value is decreasing or not, it works, but it does not work in the substring, so it always gets the last character string (-1,1).

 @echo off set string=hello set temp_string=%string% set /a string_length=0 :find_length if defined temp_string ( set temp_string=%temp_string:~1% set /a string_length+=1 goto :find_length ) :loop setlocal enabledelayedexpansion set /a back=-1 for /l %%a in (1,1,!string_length!) do ( set reverse_string=!string:~%back%,1!!reverse_string! set /a back-=1 ) echo !reverse_string! pause >nul 
+4
source share
4 answers

As TripeHound commented, %back% needs to be deferred. What you need to do is use the value of the for /L %%a loop instead of %back% . (There is no point reducing the variable manually when you are already decreasing for you as part of the for /L loop, right?)

 for /l %%a in (%string_length%,-1,0) do ( call set "reverse_string=!reverse_string!!string:~%%a,1!" ) 
Cycles

goto not very effective. If you have a long string that you are going to cancel, there will be a noticeable pause while you count its length, if you goto :label for each character. The fastest way I found the length of the string is based on jeb answer here :

 :length <return_var> <string> setlocal enabledelayedexpansion if "%~2"=="" (set ret=0) else set ret=1 set "tmpstr=%~2" for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if not "!tmpstr:~%%I,1!"=="" ( set /a ret += %%I set "tmpstr=!tmpstr:~%%I!" ) ) endlocal & set "%~1=%ret%" goto :EOF 

Put it all together as follows:

 @echo off setlocal set "string=%*" call :length string_length "%string%" setlocal enabledelayedexpansion for /l %%a in (%string_length%,-1,0) do ( set "reverse_string=!reverse_string!!string:~%%a,1!" ) echo(!reverse_string! pause >nul exit /b 0 :length <return_var> <string> setlocal enabledelayedexpansion if "%~2"=="" (set ret=0) else set ret=1 set "tmpstr=%~2" for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if not "!tmpstr:~%%I,1!"=="" ( set /a ret += %%I set "tmpstr=!tmpstr:~%%I!" ) ) endlocal & set "%~1=%ret%" goto :EOF 

Output Example:

: test.bat Fast brown fox
result: xof nworb kciuq ehT

+3
source

The problem is that %back% used without extension delay, so it will always be -1 . Replacing the end of your code:

 set /a back=-1 set /a count=1 :repeat if %count% gtr %string_length% goto :report set reverse_string=!string:~%back%,1!!reverse_string! set /a back-=1 set /a count+=1 goto :repeat :report echo !reverse_string! 

Will do the trick.

You can't just use !back! because you need contrast !...! and %...% to have the variable index, so you need to go back to the old-fashioned construction :loop , so %back% updated every time.

+2
source

As described in this post :

"To get the value of a substring when changing the index inside FOR / IF encloses a substring of two percent and precedes the command with the call. For example:

 for /l %%a in (1,1,!string_length!) do ( call set reverse_string=%%string:~!back!,1%%!reverse_string! set /a back-=1 ) 

Another way to achieve the previous process is to use the extra FOR command to change the slow index extension to an equivalent plug-in parameter, and then use the delayed extension for the substring. This method is faster than the previous CALL:

 for /l %%a in (1,1,!string_length!) do ( for %%b in (!back!) do ( set reverse_string=!string:~%%b,1!!reverse_string! ) set /a back-=1 ) 

"

However, it is inefficient to scroll the line first to count the characters, and then loop again to undo them. I think the method below should be the fastest:

 @echo off setlocal EnableDelayedExpansion set maxLength=80 set string=hello set "reverse=" for /L %%i in (1,1,%maxLength%) do ( set "reverse=!string:~0,1!!reverse!" set "string=!string:~1!" if not defined string goto break ) :break echo %reverse% 
+2
source

Here's another algorithm:

 @echo off call :reverse "The quick brown fox" echo %output% pause & exit :reverse setlocal enableDelayedExpansion set string=%~1 set index=0 :loopchar set char=!string:~%index%,1! if "!char!"=="" endlocal & set output=%output% & exit /b set output=!char!!output! set /a index+=1 goto loopchar 

"cunning":

  • using %index% inside ! to expand its current value instead of call with %% (@Aacini)
  • export !output! from the local area, reassigning it on the same line as endlocal .
+1
source

All Articles