2013-09-25 123 views
1

我在Windows批處理文件中使用字符串引號時遇到了一些問題。我嘗試解析一個csv文件(,分離)和多行條目。我不得不將只讀字符串作爲文本文件寫出。結果必須包括新行和引號。如何在Windows批處理文件中使用引號處理變量值

輸入:

"1","50","1","Warning! Q1: Value too high [W-0001]" 
"2","49","1","Warning! Q1: Value too low [W-0002]" 
"3","48","1","Warning! Q1: Value changing too fast. 
Check for endless loop[W-0003]" 

輸出:

"Warning! Q1: Value too high [W-0001]" 
"Warning! Q1: Value too low [W-0002]" 
"Warning! Q1: Value changing too fast. 
Check for endless loop[W-0003]" 

這項工作的罰款沒有新線串。

for /F "tokens=1-4 skip=4 delims=," %%a in (input.csv) do @echo %%d >> output.txt 

我試過,但我得到了,因爲在字符串

Syntaxfehler. 
C:\>if ["Warning Value changing too fast.]==[] goto :test 

如何用引號處理變量值的開頭引用的語法錯誤

for /F "delims=, tokens=1-4" %%a in (input.csv) do call :loopbody %%a %%b %%c %%d 
goto :eof 

if [%4]==[] goto :test 
echo %4 
goto :eof 

:test 
echo %1 

錯誤?

回答

3

這與您的數據:

@echo off 
for /F "delims=, tokens=1-3,*" %%a in (input.csv) do (
set "aa=" 
set "aa=%%d" 
    if not defined aa (
     >>file.out echo %%a 
    ) else (
     >>file.out echo %%d 
    ) 
) 
+0

+1,非常好,簡單。如果列1-3中的任何一行的值可能有換行符,但這不會正常工作,但根據樣本輸入,這看起來不成問題。這也有我的答案中的其他限制。如果'%% d'爲空,您可以安全地移除'set「aa =」',因爲'set「aa = %% d」'將清除該值。 – dbenham

+0

答案甚至可以從命令行簡化爲幾乎合理的一行:output.txt(for/f「delims =,tokens = 1-3,*」%a in(input.csv)do @set d =%d&如果已定義d(echo%d)else(echo%a))' – dbenham

1

正則表達式是奇妙的東西:)你可以使用一個hybrid JScript/batch utility called REPL.BAT執行正則表達式搜索和替換標準輸入,並將結果寫入stdout。

假設REPL.BAT是在當前目錄中,或者更好的是,地方whithin你的路徑,那麼下面的一個襯墊在命令行直接運行:

repl "^(?:[^,]*,){3}(\q[^\q]*\q).*$" "$1\n" mx <input.csv >output.txt 

請注意,上述方案假定每記錄至少包含4列(3個逗號)。它還假定前3列在值中不包含任何逗號,第4列必須被引用,並且不得包含轉義引用"",並且第4行之後的任何列在值中不包含新行。如果這些條件沒有得到滿足,所有地獄都可能破裂。

使用更復雜的正則表達式,我有一個解決方案應該提取任何有效的csv文件的第4列。它可以正確處理帶引號和不帶引號的值。引用的值可能包含逗號,轉義引號和/或新行。第四列輸出將始終引用,即使源不是。唯一的限制是每個記錄必須包含至少4列。

repl "^(?:(?:[^,\q\n]*|\q(?:[^\q]|\q\q)*\q),){3}(?:\q((?:[^\q]|\q\q)*)\q|([^,\q\n]*))(?:,(?:[^,\q\n]*|\q(?:[^\q]|\q\q)*\q))*$" "\q$1$2\q" mx <input.csv >output.txt 

這裏是一個討厭的測試用例CSV文件:

1,"50, 
""ignore"" 
x","1","Warning! Q1: Value too high [W-0001]",extra," hello,""world"" 
more!","part A 
1,2,3","I don't want this",<last column of record 1> 
"2","49","1","Warning! Q1: Value too low [W-0002]",<last column of record 2> 
"3","48","1","Warning! Q1: Value changing too fast. 
Check for endless loop[W-0003]","<last column of record 3>" 
1,2,3,"I want this part 1 
and ""this"" part 2",<last column of record 4> 
a,b,c,I want this unquoted value,<last column of record 5> 

這裏是輸出:

"Warning! Q1: Value too high [W-0001]" 
"Warning! Q1: Value too low [W-0002]" 
"Warning! Q1: Value changing too fast. 
Check for endless loop[W-0003]" 
"I want this part 1 
and ""this"" part 2" 
"I want this unquoted value" 

使用批處理變量有助於記錄正則表達式的邏輯,和可以輕鬆快速捕獲任意一組列。下面是使用變量相同的解決方案:

@echo off 
setlocal 

:: define a regex that matches a non-captured column value 
set "ignore=(?:[^,\q\n]*|\q(?:[^\q]|\q\q)*\q)" 

:: define a regex that matches a captured column value 
:: quoted value is in $1, unquoted value is in $2 
set "capture=(?:\q((?:[^\q]|\q\q)*)\q|([^,\q\n]*))" 

call repl "^(?:%ignore%,){3}%capture%(?:,%ignore%)*$" "\q$1$2\q" mx <input.csv >output.txt 
type output.txt 

這裏是一個最終CALL示範捕獲的第一和第四列

call repl "^%capture%,%ignore%,%ignore%,%capture%(?:,%ignore%)*$" "\q$1$2\q,\q$3$4\q" mx <input.csv >output.csv