Code: Select all
[see third post for updated code]
Moderator: DosItHelp
Code: Select all
[see third post for updated code]
Sponge Belly wrote:Could someone please explain why I had to suppress the first 5 chars of rev? The cmd inside the in (…) clause behaves as if it’s receiving input from the command line. The rev var is initialised to nothing, or so I thought. On inspection, it had the value “!rev!”
Code: Select all
set "rev=!rev!!chr!"
Code: Select all
Z:\>set "rev="
Z:\>cmd /V:ON
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
Z:\>set "char=a"
Z:\>set "rev=!rev!!char!"
Z:\>set rev
rev=!rev!a
Code: Select all
echo("!rev!"
Code: Select all
@echo off & setLocal enableExtensions disableDelayedExpansion
(call;) %= sets errorLevel to 0 =%
(set lf=^
%= BLANK LINE REQUIRED =%
)
set "cr=" & if not defined cr for /f "skip=1" %%C in (
'echo(^|replace ? . /w /u'
) do set "cr=%%C"
set ^"orig=^<!-- !^^!^^^^! %%etad%% ^| ^"^^^&^^ --^>^"
call :reverseStr res1 orig || goto end
setLocal enableDelayedExpansion
call :reverseStr res2 orig || (endLocal & goto end)
echo(orig: [!orig!]
echo(res1: [!res1!]
echo(res2: [!res2!]
endLocal
:end - exit program with appropriate errorLevel
endLocal & goto :EOF
:reverseStr result= original=
:: reverses a string
setLocal
set "ddx=!" %= is delayed expansion enabled or disabled? =%
setLocal disableDelayedExpansion
setLocal enableDelayedExpansion
set "die=" & if not defined %2 (
>&2 echo( ERROR: var "%2" not defined & set "die=1"
) else set "str=!%2!" %= if =%
if not defined die for %%L in ("!lf!") ^
do if "!str!" neq "!str:%%~L=!" (
>&2 echo( ERROR: var "%2" contains linefeeds & set "die=1"
) %= if =%
if not defined die for %%C in ("!cr!") ^
do if "!str!" neq "!str:%%~C=!" (
>&2 echo( ERROR: var "%2" contains carriage returns
set "die=1"
) %= if =%
if defined die (
endLocal & endLocal & endLocal & set "%1=" & exit /b 1
) %= if =%
endLocal
:: reverse string
for /f delims^=^ eol^= %%R in ('
cmd /von /q /c set "rev=!%2:~-1!" ^^^& ^
set "str=!%2:~0,-1!" ^^^& for /l %%I in (^) do ^
if defined str (set "rev=!rev!!str:~-1!" ^^^& ^
set "str=!str:~0,-1!"^) else (echo(^!rev^!^^^& exit 0^)
') do set "str=%%R"
setLocal enableDelayedExpansion
:: double carets if returning to enabled delayed expansion
if not defined ddx set "str=!str:^=^^^^!"
:: double quotes
set "str=!str:"=""!"
:: escape exclaims if returning to enabled delayed expansion
if not defined ddx set "str=%str:!=^^^!%" !
:: restore quotes
set "str=!str:""="!"
:: use for /f to pass string back over endLocal boundary
for /f delims^=^ eol^= %%A in ("!str!") do (
endLocal & endLocal & endLocal & set "%1=%%A" !
) %= for /f =%
exit /b 0 %= reverseStr =%
Code: Select all
:reverse [%1 - string to reverse ; %2 - if defined will store the result in variable with same name]
@echo off
setlocal disableDelayedExpansion
set "str=%~1"
set LF=^
rem ** Two empty lines are required
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set $strLen=for /L %%n in (1 1 2) do if %%n==2 (%\n%
for /F "tokens=1,2 delims=, " %%1 in ("!argv!") do (%\n%
set "str=A!%%~2!"%\n%
set "len=0"%\n%
for /l %%A in (12,-1,0) do (%\n%
set /a "len|=1<<%%A"%\n%
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"%\n%
)%\n%
for %%v in (!len!) do endlocal^&if "%%~b" neq "" (set "%%~1=%%v") else echo %%v%\n%
) %\n%
) ELSE setlocal enableDelayedExpansion ^& set argv=,
%$strLen% len,str
setlocal enableDelayedExpansion
set /a half=len/2
set "res=!str:~%half%,-%half%!"
for /L %%C in (%half%,-1,0) do (
set /a len=%len%-1-%%C
if %%C neq %half% (
for %%c in (!len!) do (
set "res=!str:~%%c,1!!res!!str:~%%C,1!"
)
)
)
endlocal & endlocal & if "%~2" NEQ "" (set %~2=%res%) else echo %res%
Code: Select all
@echo off
setlocal disableDelayedExpansion
if NOT defined stringVar set "stringVar=%~1"
if NOT defined stringVar echo no stringVar defined! & exit /b
call :setAllMacros
setlocal enabledelayedexpansion
%strLen(var):var=!stringVar!%
set /a loop=3
if %len% gtr 150 set /a loop=len/10
if %len% gtr 600 set /a loop=len/25
if %len% gtr 1500 set /a loop=len/90
endlocal & set /a loop=%loop%, len=%len%
rem Reverse var
set "rev=!R:X,1!"
set "revers="
set "reverStr="
setlocal enabledelayedexpansion
for /l %%L in (1 1 %loop%) do set "revers=!Rev:X=~%%L!!revers!"
for /l %%L in (0 %loop% %len%) do (
set "R= !stringVar:~%%L!"
set "ReverStr=%revers%!ReverStr!"
)
if "%~2" equ "" echo !ReverStr!
for /f delims^=^ eol^= %%i in ("!ReverStr!") do (
endlocal
endlocal
if "%~2" neq "" set "%~2=%%i"
)
exit /b
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:setAllMacros
:: define LF as a Line Feed (newline) character
set ^"LF=^
^" Above empty line is required - do not remove
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:strLen.var
:: create a macro with reduced For loops
:: Parenthesis are included
:: usage: %strLen(var):var=!stringVar!%
::
@for %%T in ("%temp%\%~n0.tmp.cmd") do @(
@ >%%T (
echo( @set strLen(var^)=(%%\n%%
echo( set "str=Avar"%%\n%%
echo( set "len=0"%%\n%%
for /l %%i in (12 -1 0) do @(
echo( set /a "len|=1<<%%i"%%\n%%
echo( for %%%%# in (!len!^) do if .!str:~%%%%#^^^^^^,1!==. set /a "len&=~1<<%%i"%%\n%%
)
echo(^)
)
call %%T
del %%T
)
set "LF="
set "\n="
exit /B
Code: Select all
@echo off
setlocal disableDelayedExpansion
if NOT defined stringVar set "stringVar=%~1"
if NOT defined stringVar echo no stringVar defined! & exit /b
set "rev=!R:~X,1!"
set "revMax="
set "revers="
set "reverStr="
set ^"LF=^
^" Above empty line is required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set forI= set /a "len|=1<<FORi"%\n%
for %%# in (!len!^) do if .!str:~%%#^^^,1!==. ( set /a "len&=~1<<FORi"%\n%
^) else if not defined revMax set /a "revMax=(FORi-3)*(FORi-3)+10"
@set strLen(var^)=(%\n%
set "str=Avar"%\n%
set "len=0"
setlocal enabledelayedexpansion
for /l %%i in (12 -1 0) do @ set "strLen(var)=!strLen(var)!!lf!!forI:FORi=%%i!"
set strLen(var)=!strLen(var)!!lf!)
%strLen(var):var=!stringVar!%
set /a L=loop=1
for /l %%L in (1 1 %revMax%) do if !L! lss %len% ( set /a L=%%L*%%L, loop=%%L
set "revers=!Rev:X=%%L!!revers!"
)
if not defined revers ( set "ReverStr=!stringVar!"
) else for /l %%L in (0 %loop% %len%) do ( set "R= !stringVar:~%%L!"
set "ReverStr=%revers%!ReverStr!"
)
if "%~2" equ "" echo !ReverStr!
for /f delims^=^ eol^= %%i in ("!ReverStr!") do (
endlocal
endlocal
if "%~2" neq "" set "%~2=%%i"
)
exit /b
Code: Select all
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ORIGINAL=<some^sample!string%%incorporating&special|characters=and%%even(unbalanced)quotation"marks^>^"
call :REVERSE_STRING REVERSED ORIGINAL
set "REVERSED"
endlocal
exit /B
:REVERSE_STRING
setlocal DisableDelayedExpansion
set "#RTN=%~1"
set "#STR=%~2"
setlocal EnableDelayedExpansion
set "%#RTN%="
if defined %#STR% (
set /A "LIM=(1<<13)-1"
for /L %%I in (12,-1,0) do (
set "%#RTN%=" & set /A "CNT=1<<%%I, DBL=CNT<<1"
for %%J in (!CNT!) do (
for /L %%K in (0,!DBL!,!LIM!) do (
for %%L in (!DBL!) do (
set "PRT=!%#STR%:~%%K,%%L!"
if "!PRT:~,-%%J!"=="" set /A "LIM=%%K+%%J-2"
set "%#RTN%=!%#RTN%!!PRT:~-%%J!!PRT:~,-%%J!"
)
)
)
set "%#STR%=!%#RTN%!"
)
)
for /F "delims=" %%J in (^""!%#RTN%!"^") do (
endlocal & endlocal & set "%#RTN%=%%~J"
)
exit /B
Code: Select all
@echo off
setlocal EnableDelayedExpansion
:nextString
echo/
set /P "string=String: "
if errorlevel 1 goto :EOF
echo "!string!"
set "result="
for /L %%b in (12,-1,1) do if defined string (
set /A "len=1<<%%b, pos=len-1"
for /F "tokens=1,2" %%i in ("!len! !pos!") do (
if "!string:~%%j!" neq "" (
call :RevPow2Substr "!string:~-%%i!" %%i
set "string=!string:~0,-%%i!"
)
)
)
echo "!result!!string!"
goto nextString
:RevPow2Substr str len
set "str=%~1"
if %2 equ 2 set "result=%result%%str:~1%%str:~0,1%" & exit /B
set /A "len=%2/2"
set "left=!str:~0,%len%!" & set "right=!str:~%len%!"
(
call :RevPow2Substr "%right%" %len%
call :RevPow2Substr "%left%" %len%
)
exit /B
Same -
Code: Select all
@echo off
Set "$Example=/?! ^&f><oo%%.^|bar ^ ""` &^^ & | *((:~=!)^^ ^^^ " -"
REM requires calling environment to NOT have EnableDelayedExpanion active.
If "!!" == "" Exit /B 1
(Set \n=^^^
%= Newline var \n for multi-line macro definition - Do not modify. =%)
Set Reverse=For %%n in (1 2)Do if %%n==2 (%\n%
For /F "tokens=1,2 Delims=, " %%E in ("!Reverse_Args!")Do (%\n: Prep string for Parsing =%
Set "TempString=!%%~E!"%\n%
If Defined TempString (%\n%
Set ^^^"TempString=!TempString:"=``'``!"%\n%
Set "TempString=!TempString:^=^^!"%\n%
Set "TempString=!TempString:&=^&!"%\n%
Set "TempString=!TempString:|=^|!"%\n%
Set "TempString=!TempString:<=^<!"%\n%
Set "TempString=!TempString:>=^>!"%\n%
Set "TempString=!TempString:^=^^^!"%\n%
Set "NewString="%\n%
Set "Pos[#]=0"%\n: Split string by character and rebuild; handle detection and escaping of poison characters '!' '^' and '"' =%
For /f "usebackq Delims=" %%G in (`%Systemroot%\System32\cmd.exe /u /c ^"Echo(!TempString!^"^^^|%Systemroot%\System32\find.exe /v "[false_match_%~n0]"^^^|%Systemroot%\System32\findstr.exe "^^"`)Do (%\n%
Set /A "Pos[#]+=1"%\n%
Set "Char="%\n%
If "^%%~G" == "^^" (%\n: Character is a Caret =%
Set "Char=^"%\n%
)Else (%\n%
Set "Char="%\n%
If "^^^%%~G" == "^^^!" (%\n: Character is an Exclamation mark =%
Set "Char=^^^%%~G"%\n%
) Else (%\n%
Set Char=^^%%~G%\n%
)%\n%
)%\n%
Set "NewString=!Char!!NewString!"%\n%
)%\n%
)%\n: end string rebuild; Enact Escaping restorations =%
Set "NewString=!NewString:^^^=^^!"%\n%
Set "NewString=!NewString:^^={TwoCarets}!"%\n%
Set "NewString=!NewString:&^^=&^!"%\n%
Set "NewString=!NewString:|^^=|^!"%\n%
Set "NewString=!NewString:<^^=<^!"%\n%
Set "%%~F=!NewString:>^^=>^!"%\n%
Set "NewString=!NewString:^=!"%\n%
Set "NewString=!NewString:{TwoCarets}=^!"%\n%
Set ^^^"NewString=!NewString:``'``="!"%\n%
Set "Return=$Return"%\n%
If Defined TempString (%\n%
Set "Return=%%F"%\n%
)Else Set "NewString="%\n%
)%\n: Rebuild complete; return across endlocal =%
For /f "tokens=1* Delims=`" %%R in ("!Return!`!NewString!")Do (%\n%
Endlocal ^& Set "%%R=%%S"%\n%
)%\n%
)Else Setlocal EnableDelayedExpansion ^& Set Reverse_Args=
CLS
Rem Examples
%Reverse% $Example $Result1
%Reverse% $Result1 $Result2
Set $
Goto:Eof
Code: Select all
@if (@X==@Y) @then
:: Batch
@echo off & setLocal enableExtensions disableDelayedExpansion
set ^"strFwd=short ^" ^< %% ^| ^^ ! string^"
set "strRev=" & for /f "delims="eol^= %%R in ('
cscript //nologo //e:jscript "%~dpf0" strFwd
') do set "strRev=%%R"
set str
endLocal & goto :EOF
@end // JScript
WScript.StdOut.WriteLine(
WSH.CreateObject('WScript.Shell').
ExpandEnvironmentStrings('%'+WScript.Arguments(0)+'%').
split('').reverse().join('')
);
Nice work. triggered me to review mine - now updated with a macro to reverse any literal string comprised of ascii printable characters.Sponge Belly wrote: ↑30 Oct 2022 06:31Hi Again!
Belated thanks to Aacini and T3RRY for their excellent contributions.
Below is my final word on the topic—a Batch/JScript hybrid:
There might be some code page issues with this approach, but that's a whole other box of crayons!Code: Select all
@if (@X==@Y) @then :: Batch @echo off & setLocal enableExtensions disableDelayedExpansion set ^"strFwd=short ^" ^< %% ^| ^^ ! string^" set "strRev=" & for /f "delims="eol^= %%R in (' cscript //nologo //e:jscript "%~dpf0" strFwd ') do set "strRev=%%R" set str endLocal & goto :EOF @end // JScript WScript.StdOut.WriteLine( WSH.CreateObject('WScript.Shell'). ExpandEnvironmentStrings('%'+WScript.Arguments(0)+'%'). split('').reverse().join('') );
Happy Halloween!
- SB