I'm guessing your set
commands all live within a parenthetical code block (such as a for
loop), and you aren't employing delayed expansion when you should be. If that's the case, you can probably fix your existing code this way:
setlocal enabledelayedexpansion
set "rest2=!t1!"
set "t1=!t3!"
set "t3=!rest2!"
Just so I feel like I've done something, here's a utility function that'll reverse a string that might solve your issue. This one has a limit of 100 characters for the sake of small execution time. I'm guessing this will be fine for most situations.
@echo off
setlocal
set /P "input=Input? "
call :reverse flipped "%input%"
echo %input% reversed is %flipped%
rem // end main runtime
goto :EOF
rem // functions
:reverse <return_var> <string>
setlocal enabledelayedexpansion
set "ret=" & set "str=%~2"
for /L %%I in (0,1,100) do (
if "!str!"=="" for %%a in ("!ret!") do (
endlocal & set "%~1=%%~a" & exit /b
)
set "ret=!str:~0,1!!ret!"
set "str=!str:~1!"
)
If you'd rather have the function work up to the limit of characters a variable can carry, you can increase the 100 to 8192, but that'll cause the for /L
loop to loop 8192 times regardless of whether broken by exit /b
1. There's not really a graceful way to break out of for /L
(although it is much faster than a goto
loop).
Adding a function to get the length of the string before firing the for /L
loop can make your code more efficient for long strings while not significantly impacting short ones. Although this is a lot more code, it is faster than the script above.
@echo off
setlocal
set /P "input=Input? "
call :reverse flipped "%input%"
echo %input% reversed is %flipped%
goto :EOF
:reverse <return_var> <string>
setlocal enabledelayedexpansion
set "ret=" & set "str=%~2" & call :length len "%~2"
for /L %%I in (0,1,%len%) do (
if "!str!"=="" for %%a in ("!ret!") do (
endlocal & set "%~1=%%~a" & exit /b
)
set "ret=!str:~0,1!!ret!"
set "str=!str:~1!"
)
: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%"
exit /b 0
1 When goto :EOF
or exit /b
is encountered within a for /L
loop, the counting continues, although the stuff after do
is ignored.