从预格式化的CSV中删除空行

时间:2016-04-07 12:12:06

标签: excel vba csv batch-file filter

我使用VBA从XLS文件生成CSV,之后我使用Batch过滤CSV。我的过滤器如下所示:

for %%a in (*.csv) do (

  for /f "usebackq tokens=1-10 delims=, eol=^" %%1 in ("%%a") do (
    if %%4 EQU Req_Category ECHO %%1,%%2,%%3,%%4,%%5,%%6,%%7,%%8,%%9 >> "%%a"_JIRA.csv
    if %%4 EQU Requirement ECHO %%1,%%2,%%3,%%4,%%5,%%6,%%7,%%8,%%9 >> "%%a"_JIRA.csv
  )

)

如果CSV文件没有空行,这可以正常工作。 在极少数情况下XLS - > CSV转换会在CSV中生成空行或CR。

SW_Fn-289,4.1.1.1,Controling Hardware PCB,Heading,,,,,IgnoreTesting,
SW_Fn-291,4.1.1.1.0-1," 
Date : 07.03.1777

The SystemDesignSpecification is stored in SVN path
http://sblablablabla.xlsm
",Requirement,Lab1 (B-Sample),,Released,Accepted,IgnoreTesting,
SW_Fn-4281,4.1.1.1.0-2," 
Date : 123.123.123

Path : https://apath.com
",Requirement,R1,,New,New,IgnoreTesting,
SW_Fn-166,4.2,Compliance Requirements,Heading,,,,,IgnoreTesting,
SW_Fn-286,4.2.1,Resource Usage,Heading,,,,,IgnoreTesting,

CSV中的每一行都应以ID开头:SW_Fn-Example。 是否每个人都知道如何使用批处理功能将信息带到一行?

我需要让文件看起来像这样(在过滤之前):

SW_Fn-289,4.1.1.1,Controling Hardware PCB,Heading,,,,,IgnoreTesting,
SW_Fn-291,4.1.1.1.0-1,"Date : 07.03.1777 TheSystemDesignSpecificationisstored in SVN path http://sblablablabla.xlsm",Requirement,Lab1 (B-Sample),,Released,Accepted,IgnoreTesting,
SW_Fn-4281,4.1.1.1.0-2," Date : 123.123.123 Path : https://apath.com",Requirement,R1,,New,New,IgnoreTesting,
SW_Fn-166,4.2,Compliance Requirements,Heading,,,,,IgnoreTesting,
SW_Fn-286,4.2.1,Resource Usage,Heading,,,,,IgnoreTesting,  

不应该有一条不以SW_Fn-blabla开头的行。如果一行以其他内容开头,那么它应该是前一行中具有Sw_Fn-blabla的一部分。

然后我的过滤器会产生这个:

SW_Fn-291,4.1.1.1.0-1,"Date : 07.03.1777 TheSystemDesignSpecificationisstored in SVN path http://sblablablabla.xlsm",Requirement,Lab1 (B-Sample),,Released,Accepted,IgnoreTesting,
SW_Fn-4281,4.1.1.1.0-2," Date : 123.123.123 Path : https://apath.com",Requirement,R1,,New,New,IgnoreTesting,

提前致谢

3 个答案:

答案 0 :(得分:0)

AAK!不要在metavariable%%1)使用数字 - 它非常不可靠。使用字母字符。

Batch将一个分隔符字符串视为单个分隔符,并且您已指定逗号和空格作为分隔符,因此

SW_Fn-166,4.2,Compliance Requirements,Heading,,,,,IgnoreTesting,

将显示为

SW_Fn-166,4.2,Compliance,Requirements,Heading,IgnoreTesting,,,,

您还没有表现出您对输出的期望。您是否只想要开始SW_Fn-的行,或者您是否希望所有不开始SW-Fn的行都附加到最后一行?

@ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q36475816.csv"
SET "outfile=%destdir%\outfile.txt"
SET "line="
(
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
 SET "newpart=%%a"
 IF DEFINED line CALL :test
 IF DEFINED line CALL SET "line=%%line%% %%a"
 IF NOT DEFINED line SET "line=%%a"
)
IF DEFINED line ECHO(%line%
)>"%outfile%"

GOTO :EOF

:: Test new data " Accumulate data into line or output & start a new line
:test
SET "newpart=%newpart:"=x%"
IF NOT "%newpart:~0,6%"=="SW_Fn-" goto :eof
echo(%line%
SET "line="
GOTO :eof

您需要更改sourcedirdestdir的设置以适合您的具体情况。

我使用了一个名为q36475816.csv的文件,其中包含我的测试数据。

生成定义为%outfile%

的文件

请注意,您发布的数据包含Fn-4281项中的不平衡报价。使用实际数据总是比使用实际数据更好,而不是'#34;某处接近"

阅读每一行。如果我们已经累积了一行的一部分,请检查前几个字符是否是目标。如果是,则输出构造的行并清除line

如果此操作后line清零,请将其设置为读取的行(必须从目标开始,否则累积该行。

:test过程中,在测试之前删除引号,以便它不会破坏语法。显然,如果前几个字符包含引号,则它不适合目标,因此测试将正确检测"no fit"

答案 1 :(得分:0)

试试这个:

@echo off
for %%a in (*.csv) do (
  for /f "delims=" %%b in (%%a) do (
    for /f "tokens=4 delims=," %%c in ("%%b") do (
      if "%%c"=="Requirement" echo %%b >>%%~na_JIRA%%~xa
      if "%%c"=="Req_Category" echo %%b >>%%~na_JIRA%%~xa
    )
  )
)

读取并处理每一行完成以克服Magoo提到的连续分隔符问题(使用另一个for来检查Token4,但不要费心拆解和重新组装整行)

答案 2 :(得分:0)

您的文件实际上是有效的CSV格式。带引号的CSV字段可能包含以下任何内容:

  • 逗号
  • 引用文字,转义为""
  • 换行符(LF或CRLF)

您的字段中没有逗号或引号,但您确实有新行代码会给您的代码带来严重问题。

但这只是一个潜在的问题。另一个问题是FOR / F将连续分隔符视为单个分隔符,因此如果您所需的任何守护线都有任何空字段,那么您的输出将完全错误。

对于任何类型的文本处理来说,批处理本质上远非理想,但对于CSV,除了最简单的问题之外,其他所有问题都特别糟糕。如果您确实想要使用批处理,可以使用ParseCSV.bat正确解析CSV并以可靠的方式使用FOR / F读取它。但是有更好的选择。

PowerShell有一个Import-Csv cmdlet。我不确定它的功能,但是如果它支持字段中的换行,那么你可以开发一个非常灵活的解决方案。

另一个选项是JREPL.BAT regular expression text processor。以下代码看起来很讨厌,但它会在一步中非常高效地生成所需的输出:

jrepl "((?:[\s\S]*?,){3}(?:(Req_Category,|Requirement,)|.*?,)(?:.*?,){4}.*?),[^,\n]*\n?" "$2?$1.replace(/\r\n/g,' ')+'\r\n':''" /m /j /f input.csv /o output.csv

如果将命令放在另一个批处理脚本中,则需要使用CALL JREPL。

我的JREPL解决方案依赖于以下事实:您的输入字段都不包含带引号的逗号。如果它确实包含带引号的逗号,那么JREPL解决方案将更加复杂。

此解决方案使用/ M多行选项,以便我可以跨换行符匹配。

搜索匹配每个10个字段集合(您的第10个字段似乎始终为空),无论换行符如何。 $ 1包含前9个字段(不带尾随逗号)。当且仅当它与“Req_Category”或“Requirement”匹配时,$ 2包含第4个字段。替换的javascript表达式测试是否定义了$ 2,如果是,则在用空格替换所有换行符之后将整个搜索表达式替换为$ 1,然后追加换行符。如果未定义$ 2,则整个搜索表达式将替换为空字符串。简单的概念,但有点讨厌开发; - )

略微简化允许您保留包含换行符的原始字段,并且仍然可以进行所需的过滤。:

jrepl "((?:[\s\S]*?,){3}(?:(Req_Category,|Requirement,)|.*?,)(?:.*?,){4}.*?),[^,\n]*\n?" "$2?$1+'\r\n':''" /m /j /f input.csv /o output.csv