String 我需要用批处理文件从CSV中分割一行,但它有需要保留的空值

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 (

我正在编写一个批处理文件,它从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 (
  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…可以轻松解决此问题执行…
此外,如果第一列为空,则上述操作将失败。如果已引用任何值,则我的第一条注释中的“解决方案”将失败。有关其他选项,请参阅。