Правильное использование EnableDelayedExpansion в пакетном сценарии преобразования ASCII - PullRequest
0 голосов
/ 08 марта 2019

Основной вопрос:

Как изменить опубликованный пакетный скрипт combined.bat, чтобы у меня был правильный вывод для OUTPUT_A и OUTPUT_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-символов в десятичные 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
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_A и OUTPUT_B неверны. Это смещено на 26. Я сделал обоснованное предположение, что это вызвано строкой 2 из combined.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_A и OUTPUT_B в одно и то же время выполнения.

При предоставлении решения, пожалуйста, уточните в отношении изменений скрипта, внесенных в combined.bat.

1 Ответ

0 голосов
/ 08 марта 2019

Разобрался со всем этим и опубликовал скрипт решения, а также вывод скрипта.

Я изменил 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%.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...