在ASCII转换批处理脚本中正确使用EnableDelayedExpansion

时间:2019-03-07 21:43:53

标签: batch-file windows-10 ascii

主要问题:

应如何更改已发布的批处理脚本combined.bat,以使我可以同时在OUTPUT_AOUTPUT_B上获得正确的输出? (必须具备EnableDelayedExpansion用法/范围的知识才能提供正确的解决方案)

上下文:

我结合了以下两个链接中的批处理脚本:

https://stackoverflow.com/a/15535761/7889588

https://helloacm.com/the-chr-function-implementation-in-windows-pure-batch-script/

并创建了以下批处理脚本(让我将其称为combined.bat

combined.bat是一个ASCII Dec到ASCII Char转换器。

@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

运行combined.bat时,会产生以下内容:

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_AOUTPUT_B都不正确。它偏移了26。我有根据地猜测这是由2combined.bat的第@setlocal EnableDelayedExpansion行引起的。

因此,当我通过将行2更改为REM @setlocal EnableDelayedExpansion来注释掉行combined.bat时,将产生以下内容:

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!

如您所见,OUTPUT_A现在是正确的。但是,OUTPUT_B的批处理代码无法正常工作。我尝试修改一下脚本(即将EnableDelayedExpansion放在不同的位置,等等)。我仍然无法获得该脚本,无法在同一运行时为OUTPUT_AOUTPUT_B产生正确的输出。

在提供解决方案时,请详细说明对combined.bat所做的脚本更改。

1 个答案:

答案 0 :(得分:0)

全部弄清楚,并发布了解决方案脚本以及脚本输出。

我更改了alphabet,以使!现在为^^!,而^现在为^^^。这解决了大多数问题。但是,仍然存在一个错误,其中33 s无法正确转换为! s。为了解决此问题,我必须对:CHR:ASCII函数进行更改。这篇文章的底部列出了对该解决方案的重要脚本编辑。

解决方案-ASCII转换批处理脚本(已修复所有错误):

@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_32_33_34_126
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!
call :CHR 32        
set resultA=!resultA!!char!
call :CHR 33        
set resultA=!resultA!!char!
call :CHR 34        
set resultA=!resultA!!char!
call :CHR 126
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 |
set char=!chr!

:: end the script
goto :EOF

:: sub-routine
:ASCII
        :: 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)
    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

解决方案脚本的输出:

INPUT = 64_65_66_67_68_69_70_64_32_33_34_126

OUTPUT_A = @ABCDEF@ !"~

array[0] = 64 = @
array[1] = 65 = A
array[2] = 66 = B
array[3] = 67 = C
array[4] = 68 = D
array[5] = 69 = E
array[6] = 70 = F
array[7] = 64 = @
array[8] = 32 =
array[9] = 33 = !
array[10] = 34 = "
array[11] = 126 = ~
OUTPUT_B = @ABCDEF@ !"~

更改为alphabet变量:

以下内容解决了大部分问题。

已更改

set alphabet= !"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

set alphabet= ^^!"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^^_`abcdefghijklmnopqrstuvwxyz{|}~"

更改为:CHR:ASCII功能:

以下内容修复了33 s无法正确转换为! s的错误。

  • 摆脱了setlocal EnableDelayedExpansion函数特有的本地endlocal &:ASCII
  • 使用set %2=!character!代替set %2=^%character%
  • 使用set char=!chr!代替set char=^%chr%