2011-10-28 33 views
1

我正在努力改进脚本,我建议作为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"%*

编辑
我在阅读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" 
+0

我看着我的计算机的FTYPE输出,发现文件不包含在引号内的一些条目,即使路径包含空格。我担心你使用FTYPE的策略可能不可靠。 – dbenham

+0

@dbenham我也注意到了这一点。然而,考虑到所有这些问题,我写了什么似乎是简单的批处理文件,我掩盖了这个问题。 –

回答

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 

如果我们可以依靠第一个标记总是用引号括起来的事实,那么解决方案就更简单了。我们可以使用EOL和DELIMS的FOR/F设置为"

@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输出,发现一些条目没有被引用,即使它们在路径中包含空格!我不认为这个页面上的任何答案都能解决这个问题。事实上,这个问题背后的全部前提可能是有缺陷的。

+0

您的评论*如果我们可以依靠第一个标记总是用引号括起来的事实,那么解决方案就更容易了。*似乎表明,即使第一个标记是**,第一个解决方案也可以工作**用引号括起来。 –

+0

@Piotr Dobrogost正确。只要路径中不包含任何空格或特殊字符,我的第一个解决方案就可以使用不加引号的路径。如果路径包含空格/特殊字符,则路径必须被引用。当然,第二种解决方案不会在没有引号的情况下工作。 – dbenham

+0

感谢您的信息。然而,我注意到我在'for/f'tokens = 2 delims =='%% i in('ftype Python.File')后丢失了'!'符号,在我改进的解决方案中设置了reg_entry = %% i' [如何编写一个批处理文件,显示在Windows上处理Python脚本的可执行文件和Python版本的路径?](http://stackoverflow.com/questions/7825780/) –

1

基本上你所要做的是将整个字符串转换成它的元素,就像一个解析器会做到这一点。在你的情况下,由于Windows规则中关于允许空格的位置,词法分析可能会诀窍。

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

收集双引号的字符串的FSA部分挑选过的字符,直到找到另一双引号;这是什么让你捕获双引号字符串内的空白。我认为你必须检查一个“逃脱”双引号(其中两个连续),如果找到了,请用一个双引号替换它们,并继续收集字符。

这是很丑陋,因为CMD脚本有真正可怕的字符串处理能力。您需要知道的每一件(丑陋的)事情都可以通过在DOS命令提示下输入HELP SET来找到。具体地讲,是substringing其拾取关闭m字符起始于在环境变量%VAR%索引n形式%VAR:~n,m%的。我发现它是有用的SET TEMP=%VAR%然后剥离字符断%TEMP%逐一通过简单的序列,如

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

享受。

+0

我冒昧地解决了代码片段中的一些小错误,比如在'SET%var%= ...'中不必要的'%'或错误的'1',它应该是'0'(意味着第一个字符)。请看一下,以防万一我的东西错了。 –

+0

@Andriy:谢谢! –

+0

好的解释和是的,它可以用一个有限状态机来解决,但这里没有必要,因为批处理有这个内部版本 – jeb

2

这就是批量的直接能力。在批处理批处理文件的参数由空格分开,并且一个参数可以用引号括起来,所以只是通过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" 
%* 
+0

一切都很好,但如何在现有的批处理文件的上下文中使用这种方法?解析'call'的参数与解析批处理文件的参数是一样的吗?如果是这样,我需要在批处理文件中额外转义这些参数,而不是将它们传递给命令行上的批处理文件? –

+0

几乎相同,如果内容位于引号内,则不需要转义。唯一让人烦恼的角色是脱字符,每个脱字号(里面的引号)都会被呼叫加倍 – jeb

1

正如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 
+0

这是疯了!谢谢。 –

+0

仍然存在一个错误 - 您忘记处理'!',这是可能导致问题的路径中的另一个有效字符。 – dbenham

+0

:-)你有我,我没有忘记它,但你也知道这是不能用这个'call'解决方案以简单的方式处理 – jeb

相关问题