Как разбить строки в двойных кавычках со встроенными пробелами, уменьшенными пробелами в командном файле? - PullRequest
2 голосов
/ 29 октября 2011

Я борюсь с улучшением сценария, который я предложил в качестве ответа на Как написать пакетный файл с указанием пути к исполняемому файлу и версии Python, обрабатывающей сценарии Python для 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
Я попытался использовать 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 ]

2 голосов
/ 20 ноября 2011

Альтернативным синтаксическим анализатором, который очень похож на синтаксический анализатор 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 и обнаружил, что некоторые записи не были заключены в кавычки, даже если они содержат пробелы впуть!Я не думаю, что какой-либо из ответов на этой странице справится с этим.На самом деле вся идея вопроса может быть ошибочной.

2 голосов
/ 29 октября 2011

Это прямая возможность 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"
%*
2 голосов
/ 15 ноября 2011

Как сказал Аасини, вашу проблему можно решить с помощью внутреннего разделения параметров с помощью оператора CALL.

Чтобы не потерять знаки % на call, вы можете удвоить их непосредственно перед расширением call.
Ключевой линией является 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
1 голос
/ 29 октября 2011

По сути, вам нужно преобразовать всю строку в ее элементы, так же, как это сделает парсер.В вашем случае лексический анализ, вероятно, сработает из-за правил Windows о том, где разрешены пробелы.

По сути, вам нужно создать конечный автомат в вашем файле .cmd с метками и условными переходами.FSA имеет состояния, которые обрабатывают различные части элемента, который вы хотите собрать.В начальном состоянии вы решаете, видите ли вы пробел (пропустите и вернитесь к началу), двойные кавычки (перейдите к части FSA, которая обрабатывает строки с двойными кавычками), или что-то непустое (перейдите к частиFSA, который собирает непустые символы).

Часть FSA, которая собирает строки в двойных кавычках, отбирает символы, пока не найдет другую двойную кавычку;это то, что позволяет вам захватывать пробелы внутри строк в двойных кавычках.Я думаю, что вы должны проверить на наличие "экранированных" двойных кавычек (две из них подряд) и, если они найдены, заменить их на одинарную двойную кавычку и продолжить сбор символов.Скрипт имеет действительно ужасные возможности обработки строк.Все, что вам нужно знать, можно найти, набрав HELP SET в командной строке DOS.В частности, подстрока имеет форму %VAR:~n,m%, которая отбирает m символов, начиная с индекса n в переменной окружения %VAR%.Я считаю полезным SET TEMP=%VAR%, а затем очищать символы от %TEMP% один за другим с помощью простых последовательностей, таких как

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

Наслаждайтесь.

...