Primary Question:
How should the posted batch script, combined.bat
, be changed so that I can have correct output for both OUTPUT_A
and OUTPUT_B
at the same runtime? (Knowledge of EnableDelayedExpansion usage/scope is required to provide a correct solution)
Context:
I combined batch scripts from the two following links:
https://stackoverflow.com/a/15535761/7889588
https://helloacm.com/the-chr-function-implementation-in-windows-pure-batch-script/
and created the following batch script (let me refer to this as combined.bat
):
combined.bat
is meant to be an ASCII Dec to ASCII Char converter.
@echo off
@setlocal EnableDelayedExpansion
:: define characters from 32 to 126
set alphabet= !"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
set testVar=64_65_66_67_68_69_70_64
echo INPUT = %testVar%
echo.
set resultA=
call :CHR 64
set resultA=%resultA%%char%
call :CHR 65
set resultA=%resultA%%char%
call :CHR 66
set resultA=%resultA%%char%
call :CHR 67
set resultA=%resultA%%char%
call :CHR 68
set resultA=%resultA%%char%
call :CHR 69
set resultA=%resultA%%char%
call :CHR 70
set resultA=%resultA%%char%
call :CHR 64
set resultA=%resultA%%char%
echo OUTPUT_A = %resultA%
echo.
set char=randomValueJustToInitFill
call :split "%testVar%" "_" array
set resultB=
:: Loop through the resulting array
for /L %%I in (0, 1, %array.ubound%) do (
call :CHR !array[%%I]!
echo array[%%I] = !array[%%I]! = !char!
set resultB=!resultB!!char!
)
echo OUTPUT_B = !resultB!
echo.
goto :EOF
:CHR
:: valid range should be from 32 to 126 inclusive
if "%1"=="" goto :EOF
if %1 LSS 32 goto :EOF
if %1 GTR 126 goto :EOF
:: call function
call :ASCII %1 chr
:: print result, using ^ to escape special characters
:: such as <, > and |
REM echo.^%chr%
set char=^%chr%
:: end the script
goto :EOF
:: sub-routine
:ASCII
setlocal EnableDelayedExpansion
:: get the index
set /a var=%1-32
:: retrieve letter
set character=!alphabet:~%var%,1!
:: end the routine and return result as second parameter (out)
endlocal & set %2=^%character%
@EXIT /B 0
:: split subroutine
:split <string_to_split> <split_delimiter> <array_to_populate>
:: populates <array_to_populate>
:: creates arrayname.length (number of elements in array)
:: creates arrayname.ubound (upper index of array)
set "_data=%~1"
:: replace delimiter with " " and enclose in quotes
set _data="!_data:%~2=" "!"
:: remove empty "" (comment this out if you need to keep empty elements)
set "_data=%_data:""=%"
:: initialize array.length=0, array.ubound=-1
set /a "%~3.length=0, %~3.ubound=-1"
for %%I in (%_data%) do (
set "%~3[!%~3.length!]=%%~I"
set /a "%~3.length+=1, %~3.ubound+=1"
)
@EXIT /B 0
@endlocal
when running combined.bat
, it yields the following:
INPUT = 64_65_66_67_68_69_70_64
OUTPUT_A = Z[\]_`aZ
array[0] = 64 = Z
array[1] = 65 = [
array[2] = 66 = \
array[3] = 67 = ]
array[4] = 68 = _
array[5] = 69 = `
array[6] = 70 = a
array[7] = 64 = Z
OUTPUT_B = Z[\]_`aZ
OUTPUT_A
and OUTPUT_B
are both not correct. It is offset by 26
. I made an educated guess that this is caused by line 2
of combined.bat
, @setlocal EnableDelayedExpansion
.
So when I comment out line 2
by changing it to REM @setlocal EnableDelayedExpansion
, edited combined.bat
yields the following:
INPUT = 64_65_66_67_68_69_70_64
OUTPUT_A = @ABCDEF@
array[0] = !array[0]! = !char!
array[1] = !array[1]! = !char!
OUTPUT_B = !resultB!
As you can see, OUTPUT_A
is now correct. However, the batch code for OUTPUT_B
does not work properly anymore. I tried tinkering around with the script for a bit (i.e. placing EnableDelayedExpansion
in different locations, etc.). I am still unable to get the script to yield correct output for both OUTPUT_A
and OUTPUT_B
at the same runtime.
When providing a solution, please elaborate in respect to the script changes made to combined.bat
.