正則表達式是奇妙的東西:)你可以使用一個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
+1,非常好,簡單。如果列1-3中的任何一行的值可能有換行符,但這不會正常工作,但根據樣本輸入,這看起來不成問題。這也有我的答案中的其他限制。如果'%% d'爲空,您可以安全地移除'set「aa =」',因爲'set「aa = %% d」'將清除該值。 – dbenham
答案甚至可以從命令行簡化爲幾乎合理的一行:output.txt(for/f「delims =,tokens = 1-3,*」%a in(input.csv)do @set d =%d&如果已定義d(echo%d)else(echo%a))' – dbenham