String 我需要用批处理文件从CSV中分割一行,但它有需要保留的空值
我正在编写一个批处理文件,它从CSV中获取行,并将它们重新排列为新的CSV,以便导入Excel 我的困难在于空元素被忽略,但重要的是要在生成CSV的表中保留空元素,以便我可以提取正确的值进行导入 下面是我的问题的一个简化示例:假设我有一个文件input.txt,其中包含以下内容:String 我需要用批处理文件从CSV中分割一行,但它有需要保留的空值,string,batch-file,dos,batch-processing,string-split,String,Batch File,Dos,Batch Processing,String Split,我正在编写一个批处理文件,它从CSV中获取行,并将它们重新排列为新的CSV,以便导入Excel 我的困难在于空元素被忽略,但重要的是要在生成CSV的表中保留空元素,以便我可以提取正确的值进行导入 下面是我的问题的一个简化示例:假设我有一个文件input.txt,其中包含以下内容: 1,2,,4 这是我的代码: @echo off set filename=input.txt for /F "tokens=1,2,3,4 delims=," %%a in (%filename%) do (
1,2,,4
这是我的代码:
@echo off
set filename=input.txt
for /F "tokens=1,2,3,4 delims=," %%a in (%filename%) do (
echo a : %%a
echo b : %%b
echo c : %%c
echo d : %%d
)
我的输出是:
a : 1
b : 2
c : 4
d :
我希望输出:
a : 1
b : 2
c :
d : 4
有什么建议吗?首先,假设您有一个简单的例子,其中没有任何值包含引号、逗号或
代码>。然后你可以使用:
@echo off
setlocal EnableDelayedExpansion
set filename=input.txt
for /F "delims=" %%x in (%filename%) do (
set line=%%x
for /F "tokens=1,2,3,4 delims=," %%a in ("!line:,,=,"",!") do (
echo a : %%~a
echo b : %%~b
echo c : %%~c
echo d : %%~d
)
)
@echo off
setlocal enableDelayedExpansion
set "filename=input.csv"
for /f usebackq^ delims^=^ eol^= %%a in ("%filename%") do (
set "ln=%%a"
for /f "tokens=1-4 delims=," %%a in (""!ln:^,^=","!"") do (
echo a : %%~a
echo b : %%~b
echo c : %%~c
echo d : %%~d
)
)
如果某些列值已被引用,则上述操作将无法正常工作。Aacini的代码在某些情况下可以工作,但是如果有连续的空列,或者有一个前导的空列,它就会失败。更多的代码解决了这些缺点:
@echo off
setlocal enableDelayedExpansion
set "filename=input.csv"
for /f usebackq^ delims^=^ eol^= %%a in ("%filename%") do (
set "ln=%%a"
if "!ln:~0,1!" equ "," set "ln=""!ln!"
if "!ln:~-1,1!" equ "," set "ln=!ln!""" %== I don't think this is needed, but it can't hurt ==%
set "ln=!ln:,,=,"",!"
set "ln=!ln:,,=,"",!"
for /f "tokens=1-4 delims=, eol=," %%a in ("!ln!") do (
echo a : %%~a
echo b : %%~b
echo c : %%~c
echo d : %%~d
)
)
但是CSV文件可能很棘手。任何列值都可以被引用,引用的值可以包含逗号、换行符或转义为“
”的引号。另外,扩展包含的FOR/F变量如果启用延迟扩展,则代码>(或可能的^
)将损坏该值。使用纯本机批处理命令解决所有这些问题非常困难。这是可以做到的,但这将是神秘而缓慢的
我已经写了一篇文章,使for/F能够安全地解析几乎任何CSV文件,从而变得简单高效。该代码是纯脚本,从XP开始将在任何现代Windows机器上运行。脚本中嵌入了完整的文档。此外,还有多个示例展示了如何使用这些实用程序
下面是可以用于本问题示例的代码。下面的代码允许使用逗号、引号、换行符、代码>,以及列值中的^
@echo off
:: Delayed expansion must be disabled during macro definition
setlocal disableDelayedExpansion
call define_csvGetCol
set "filename=input.csv"
:: Delayed expansion must be enabled when using %csvGetCol%
setlocal enableDelayedExpansion
for /f "tokens=1-4 delims=," %%A in ('parseCSV /e /d ^<"%filename%"') do (
%== Load and decode column values ==%
%csvGetCol% A "," %%A
%csvGetCol% B "," %%B
%csvGetCol% C "," %%C
%csvGetCol% D "," %%D
%== Print results ==%
echo a : !A!
echo b : !B!
echo c : !C!
echo d : !D!
)
@echo关闭
::在宏定义期间,必须禁用延迟扩展
setlocal disableDelayedExpansion
调用define_csvGetCol
设置“filename=input.csv”
::使用%csvGetCol%时必须启用延迟扩展
setlocal enableDelayedExpansion
对于/f“tokens=1-4 delims=,”%%A in('parseCSV/e/d^对于初学者,假设您有一个简单的情况,其中没有任何值包含引号、逗号或!
。然后您可以使用:
@echo off
setlocal enableDelayedExpansion
set "filename=input.csv"
for /f usebackq^ delims^=^ eol^= %%a in ("%filename%") do (
set "ln=%%a"
for /f "tokens=1-4 delims=," %%a in (""!ln:^,^=","!"") do (
echo a : %%~a
echo b : %%~b
echo c : %%~c
echo d : %%~d
)
)
如果某些列值已被引用,上述操作将无法正常工作。Aacini的代码在某些情况下可以正常工作,但如果存在连续的空列或前导的空列,则无法正常工作。再多些代码可以解决这些缺点:
@echo off
setlocal enableDelayedExpansion
set "filename=input.csv"
for /f usebackq^ delims^=^ eol^= %%a in ("%filename%") do (
set "ln=%%a"
if "!ln:~0,1!" equ "," set "ln=""!ln!"
if "!ln:~-1,1!" equ "," set "ln=!ln!""" %== I don't think this is needed, but it can't hurt ==%
set "ln=!ln:,,=,"",!"
set "ln=!ln:,,=,"",!"
for /f "tokens=1-4 delims=, eol=," %%a in ("!ln!") do (
echo a : %%~a
echo b : %%~b
echo c : %%~c
echo d : %%~d
)
)
但是CSV文件可能很棘手。任何列值都可能被引用,引用的值可能包含逗号、换行符或转义为“
”的引号。此外,扩展包含!
(或可能包含^
)的FOR/F变量如果启用延迟扩展,将损坏该值。使用纯本机批处理命令解决所有这些问题非常困难。这是可以做到的,但这将是一个神秘而缓慢的过程
我已经编写了一个脚本,使for/F安全地解析几乎所有CSV文件变得简单高效。该代码是纯脚本,从XP开始将在任何现代Windows计算机上运行。脚本中嵌入了完整的文档。此外,还发布了多个示例,展示了如何使用这些实用程序
以下是可用于此问题示例的代码。下面的代码允许在列值中使用逗号、引号、换行符、!
和^
@echo off
:: Delayed expansion must be disabled during macro definition
setlocal disableDelayedExpansion
call define_csvGetCol
set "filename=input.csv"
:: Delayed expansion must be enabled when using %csvGetCol%
setlocal enableDelayedExpansion
for /f "tokens=1-4 delims=," %%A in ('parseCSV /e /d ^<"%filename%"') do (
%== Load and decode column values ==%
%csvGetCol% A "," %%A
%csvGetCol% B "," %%B
%csvGetCol% C "," %%C
%csvGetCol% D "," %%D
%== Print results ==%
echo a : !A!
echo b : !B!
echo c : !C!
echo d : !D!
)
@echo关闭
::在宏定义期间,必须禁用延迟扩展
setlocal disableDelayedExpansion
调用define_csvGetCol
设置“filename=input.csv”
::使用%csvGetCol%时必须启用延迟扩展
setlocal enableDelayedExpansion
对于/f“tokens=1-4 delims=,”%%A in('parseCSV/e/d^您可以尝试用另一个字符串(如[filler\u string]
)替换空点,您可以稍后将其过滤掉PowerShell可能是获得所需内容的最简单方法(导入Csv
)。您可以尝试用另一个字符串替换空点(如[filler_string]
)您可以稍后将其过滤掉PowerShell可能是获取所需内容的最简单方法(导入Csv
)。OP应该意识到不会处理一行中的两个空字段。foxidrive是正确的-它不会处理连续的空字段。使用(“!line:^,^=”,“!”)中的可以轻松解决此问题执行…
此外,如果第一列为空,上述操作将失败。“解决方案”在我的第一个注释中,如果已经引用了任何值,则注释将失败。有关其他选项,请参阅。OP应该意识到,一行中的两个空字段将不会被处理。foxidrive是正确的-它不会处理连续的空字段。使用(“!line:^,^=”,“!”)中的“for…可以轻松解决此问题执行…
此外,如果第一列为空,则上述操作将失败。如果已引用任何值,则我的第一条注释中的“解决方案”将失败。有关其他选项,请参阅。