我在提高更复杂脚本子函数的通用性以供以后使用时遇到了一些困难(从内联脚本提升到标记函数)。目的是安全地解析 readline 输入和输出并尽可能多地保留它,同时使字符串易于管理以进行额外的解析。
这是该脚本的准备好的摘录。有趣的是,在重建这个批次时,我遇到了一些我在最初构建原始脚本时发现的奇怪问题,我想我已经能够解决很多问题。然而在这种情况下,虽然我可以(大部分)获得
:prog2
的预期结果,但实现似乎是编码错误的 hacky 解决方法。毫无疑问,这可能会导致问题。
这是我正在使用的 readline 输入,但请随意发挥创意(对于那些热衷于了解它的发展方向的人;是的,使用完整的过滤器效果很好)
_strFilter /VERBOSE /STRING "C:/Documents & Settings" /TESTstr"C:\Users\User" "Hello/Universe & Goodbye;World\" /_DEBUG "test\stray" "test|stray2" /TESTstr "^^%^^%^^!|#|^^!@|"
.
:: ========================================
:: _strfilter.cmd
:: ----------------------------------------
:: @ZedCee on stackoverflow.com/users/21430468
:: ========================================
@ECHO OFF
setLocal
:: Spaces are required for later parsing, mostly fighting set quotes, though they seem to trail even using the "correct" way to set
:: The quotes are there to prevent leaks and breakages
set "_userInput=" %* ""
:: ========================================
::
:: With _strFilter as a seperate (more versatile) function
::
:prog2
call :_strFilter _userInput_filter "%%_userInput%%"
echo;&echo;Escaped String ----- "%_userInput_filter%"
call :_strRestore _userInput_filter
echo;&echo;Restored String ----- "%_userInput_filter%"
exit /B
:_strFilter varName strVal
setlocal disableDelayedExpansion
:: Similarly here, without additional quoting, the variables leak and throw a wrench in the mix
set "_strArray="%*""
set "_strArray=%_strArray:&=(AMP)%"
set "_strArray=%_strArray:|=(BAR)%"
set _strArray=%_strArray:^=(CARET)%
set _strArray=%_strArray:!=(EXCLAIM)%
for /F "tokens=1,*" %%A in ("%_strArray%") do (
endLocal
set %%~A=%%~B
)
exit /B
::
:: ----------------------------------------
::
:_strRestore varName
setlocal enableDelayedExpansion
for /F "tokens=*" %%X in ("!%*!") do (
endLocal
set "_strArray=%%X"
)
setlocal disableDelayedExpansion
set "_strArray=%_strArray:(EXCLAIM)=!%"
set "_strArray=%_strArray:(CARET)=^%"
set "_strArray=%_strArray:(BAR)=|%"
set "_strArray=%_strArray:(AMP)=&%"
:: _strRestore fails if additional quote not accounted for
for /F "tokens=*" %%A in ("%_strArray:~0,-1%") do (
endLocal
set "%*=%%A"
)
exit /B
::
:: ========================================
::
REM :: prog1 works as expected, _strRestore returns exactly what's expected
REM ::
REM :prog1
REM ::_strFilter_Inline
REM setlocal disableDelayedExpansion
REM set "_userInput=%_userInput:&=(AMP)%"
REM set "_userInput=%_userInput:^=(CARET)%"
REM set "_userInput=%_userInput:!=(EXCLAIM)%"
REM set "_userInput=%_userInput:|=(BAR)%"
REM echo;&echo;Escaped String ----- "%_userInput%"
REM
REM call :_strRestore _userInput
REM echo;&echo;Restored String ----- "%_userInput%"
REM exit /B
::
:: ----------------------------------------
::
REM :_strRestore varName
REM setlocal enableDelayedExpansion
REM for /F "tokens=*" %%X in ("!%*!") do (
REM endLocal
REM set "_strArray=%%X"
REM )
REM setlocal disableDelayedExpansion
REM set "_strArray=%_strArray:(EXCLAIM)=!%"
REM set "_strArray=%_strArray:(CARET)=^%"
REM set "_strArray=%_strArray:(BAR)=|%"
REM set "_strArray=%_strArray:(AMP)=&%"
REM :: Works with prog1
REM if %chsYrAdvtr% == 1 goto :_restore1
REM if %chsYrAdvtr% == 2 goto :_restore2
REM for /F "tokens=*" %%A in ("%_strArray%") do (
REM endLocal
REM set "%*=%%A"
REM )
REM exit /B
::
:: ========================================
:prog1
和 :prog2
的结果非常相似,主要区别在于 :prog2
'Escaped string`
Escaped String ----- "" /VERBOSE /STRING "C:/Documents (AMP) Settings" /TESTstr"C:\Users\User" "Hello/Universe (AMP) Goodbye;World\" /_DEBUG "test\stray" "test(BAR)stray2" /TESTstr "(CARET)(CARET)%(CARET)(CARET)%(CARET)(CARET)(EXCLAIM)(BAR)#(BAR)(CARET)(CARET)(EXCLAIM)@(BAR)" """ %= trailing quote here =%
Restored String ----- "" /VERBOSE /STRING "C:/Documents & Settings" /TESTstr"C:\Users\User" "Hello/Universe & Goodbye;World\" /_DEBUG "test\stray" "test|stray2" /TESTstr "^^%^^%^^!|#|^^!@|" ""
这在最后的
for /F
中得到修复,同时将变量带出函数(向@jeb 和@dbenham 求助,以帮助从嵌套函数中提取变量),但诚然,修剪字符似乎不是正确的修复方法:
for /F "tokens=*" %%A in ("%_strArray:~0,-1%") do (
... )
我知道可能的问题可能与前导空格有关,或者可能与所需的额外引用有关,尽管
set
是以“正确”的方式完成的,但它带来了散兵游勇。如果没有所需的变量引用和修剪,&
、@
或类似类型的中断就会发生。有没有更简洁的方法来纠正这个问题,让 :prog1 和 :prog2 在输出中相同(最好是两行)?
通过逃生和特价添加额外的挑战。例如,插入符有点让人头疼…… 原始脚本如上所述解析插入符,但是当我最初复制必要的部分时,CMD 奇怪地在 _userInput 上吃掉了我的插入符。它变得更奇怪了,当我复制、重写、恢复时,输入的处理方式没有真正的根本改变,插入符开始通过 _userInput,完全用于
:prog1
,部分用于:prog2
。愿意发布一个 stackoverflow 问题,我创建了一个 if
开关来轻松尝试这两种方法,但令人费解的是,两者都有正确的插入符号。更奇怪的是,这些都不重要,我最终把它全部刮掉了,但我的插入符号仍然存在……非常混乱!
这引发了一些问题,是否进行了必要的最小逃生/特殊替换,或者是否忽略了其他符号。也许操作顺序不合适,或者需要返工?我怀疑这可能与一些困难有关(需要额外的引号和草率的修剪)。有什么方法可以使这样的功能更强大?