如何拆分带有嵌入空格的双引号字符串,这些空格在批处理文件中用空格分隔?

时间:2011-10-28 21:55:29

标签: windows parsing batch-file

我正在努力改进脚本,我建议将其作为How to write a batch file showing path to executable and version of Python handling Python scripts on Windows?问题的答案。要阻止打开对话框,我想读取ftype命令的输出,提取路径 从中执行并检查它是否存在。

在此之后

@echo off
setlocal EnableDelayedExpansion 
rem c:\ftype Python.File ->
rem Python.File="c:\path with spaces, (parentheses) and % signs\python.exe" "%1" %*
for /f "tokens=2 delims==" %%i in ('ftype Python.File') do (
    set "reg_entry=%%i"
)

reg_entry's内容

"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*

如何拆分才能获得 "c:\path with spaces, (parentheses) and % signs\python.exe""%1"%*

EDIT
我在阅读Aacini的答案后尝试使用call,它几​​乎可以使用。但是,它不会处理%符号。

@echo off
setlocal EnableDelayedExpansion 
set input="c:\path with spaces and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
call :first_token output !input!
echo !output!
goto :eof

:first_token
set "%~1=%2"
goto :eof

输出

"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*
"c:\path with spaces and (parentheses) and 1"

4 个答案:

答案 0 :(得分:2)

这是Batch的直接功能。在批处理中,批处理文件的参数用空格分隔,参数可以用引号括起来,所以只需将reg_entry的值作为批处理文件的参数传递,其中包含每个参数:

C:\>type test.bat
@echo off
:loop
echo %1
shift
if not "%1" == "" goto loop

C:\>echo %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe" "%1" %*

C:\>test %reg_entry%
"c:\path with spaces and (parentheses) and % signs\python.exe"
"%1"
%*

答案 1 :(得分:2)

正如Aacini所说,使用CALL语句可以通过内部参数拆分解决您的问题。

为了避免在%之前丢失call个符号,您可以在call展开之前将其加倍。
keyline为set "input=!input:%%=%%%%!",其中一个解析器阶段的百分号为半,因此%替换单%%

但即使这样,这个解决方案并不完美!

此解决方案在使用&<>|这样的特殊字符时遇到问题,在您的情况下只有&,因为这是文件名/路径中唯一的合法字符。
通过将行set "%~1=%2"更改为set ^"%~1=%2"可以避免这种情况,这可以确保%2使用周围的引号。

但现在你又遇到了另一个问题,所有的插入都加倍了 所以我必须用set "output=!output:^^=^!"替换输出。

新代码看起来像这样

@echo off
setlocal EnableDelayedExpansion 
set input="c:\path with spaces, exlcamation mark^!, ampersand &, carets ^ and (parentheses) and %% signs\python.exe" "%%1" %%*
echo !input!
set "input=!input:%%=%%%%!"
call :first_token output !input!
set "output=!output:^^=^!"
echo !output!
goto :eof

:first_token
set ^"%~1=%2"
goto :eof

编辑:用于处理感叹号!
您需要将:first_token功能更改为

:first_token
setlocal DisableDelayedExpansion
set ^"temp=%2"
set ^"temp=%temp:!=^!%"
(
endlocal
set ^"%~1=%temp%"
)
goto :eof

答案 2 :(得分:2)

与CALL解析器非常相似的替代解析器是简单的FOR。有两个复杂因素:

1-如果在包含!的情况下启用延迟扩展,则不得展开FOR。这很容易处理。

2-内容不得包含通配符*??可以暂时替换,然后返回。但是没有简单的方法来搜索和替换*

由于此问题试图解析路径,并且路径不能包含通配符,因此无需使用CALL即可轻松解决此问题。为了完整性,我在测试用例中添加了!

@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for %%A in (!input!) do if not defined output endlocal & set output=%%A
set output

如果我们可以依赖第一个令牌将始终用引号括起来的事实,那么解决方案就更容易了。我们可以使用FOR / F,EOL和DELIMS都设置为"

@echo off
setlocal disableDelayedExpansion
set input="c:\path with spaces, ampersand &, carets ^ and (parentheses)! and %% signs\python.exe" "%%1" %%*
set input
set "output="
setlocal enableDelayedExpansion
for /f eol^=^"^ delims^=^" %%A in ("!input!") do endlocal & set output="%%A"
set output

但是,我只看了我的FTYPE输出,发现一些条目没有被引用,即使它们在路径中包含空格!我不认为此页面上的任何答案都可以解决这个问题。事实上,问题背后的整个前提可能存在缺陷。

答案 3 :(得分:1)

基本上你要做的就是将整个字符串转换为它的元素,就像解析器一样。在你的情况下,由于Windows规则允许空格被允许,词汇分析可能会成功。

从根本上说,您需要在.cmd文件中使用标签和条件格式构建有限状态机。 FSA拥有处理您希望收集的元素的各个部分的州。在开始状态中,您决定是否看到空白(跳过并返回开始),双引号(转到处理双引号字符串的FSA部分),或者是非空白的部分(转到部分)收集非空白字符的FSA。)

收集双引号字符串的FSA部分选择字符,直到找到另一个双引号;这就是让你在双引号字符串中捕获空格的原因。我想你必须检查一个“转义”双引号(连续两个),如果找到,用一个双引号替换它们并继续收集字符。

这非常难看,因为CMD脚本具有非常糟糕的字符串处理功能。通过在DOS命令提示符下键入HELP SET,可以找到您需要知道的每个(丑陋)事物。特别是,子字符串格式为%VAR:~n,m%,从环境变量m中的索引n开始挑选%VAR%个字符。我发现它对SET TEMP=%VAR%很有用,然后通过简单的序列逐一从%TEMP%剥离字符,例如

SET CHAR=%TEMP:~0,1%
SET TEMP=%TEMP:~1%

享受。