繁体   English   中英

如果仅非空字段用双引号引起来,我如何读取CSV文件?

[英]How can I read a CSV file if only non-empty fields are wrapped by double quotes?

我正在尝试在Bash脚本中读取CSV文件。 我成功地使用gawk并指定FPAT来实现该目标,例如:

gawk -v LOGFILE="${LOGFILE}" 'BEGIN {
    FPAT = "([^,]+)|(\"[^\"]+\")"
    }
NR == 1{
    # doing some logic with header
}
NR >= 2{
    # doing some logic with fields
}' <filename>

这里的问题是,该文件包含如下数据:

"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID"

现在,有了这些数据,我得到了错误的数据,因为它忽略了逗号,这使我提取的数据的位置编号错误。 例如,它告诉“ 7865431234”在第3位,而在第6位。

谁能建议更改以获取正确的字段位置?

FPAT要求每个字段至少包含一个字符,但是您希望识别零个字符的空字段。 FPAT添加一个允许零字符的替代方法:

gawk 'BEGIN { FPAT = "([^,]+)|(\"[^\"]+\")|" }
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("[%s]", $i); print "" }'

注意额外的| FPAT结束时。 该操作仅标识记录号,字段数,并用方括号将每个字段的值括起来。

将数据字符串提供给该脚本后,输出为:

1:8:["RAM"]["31st street, Bengaluru, India"][][][]["7865431234"][]["VALID"]

这清楚地显示了四个空字段。

现在您所要做的就是处理:

"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,"",,,"INVALID"

引号中包含双引号。 这不是很难管理的事情:

gawk 'BEGIN { FPAT = "([^,]+)|(\"([^\"]|\"\")*\")[^,]*|" }
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("%d[%s]", i, $i); print "" }' "$@"

FPAT说一个字段是:

  • 一系列非逗号,
  • 还是以双引号开头的字段,其中包含零个或多个以下任一实例:

    • 非引号,或
    • 两个双引号

    后跟双引号和可选的非逗号数据

  • 还是空的

请注意,“可选的非逗号数据”应该为空,并且仅出现在格式错误的CSV数据中。

给定输入数据:

"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID"
"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,,,,"INVALID"
"Some","","Empty","",Fields "" Wrapped,"",in quotes
"Malformed" CSV,Data,"Note it has data after" a close quote,"and before a comma,",,"INVALID"

这将产生:

1:8:1["RAM"]2["31st street, Bengaluru, India"]3[]4[]5[]6["7865431234"]7[]8["VALID"]
2:8:1["Mr ""Manipulator"", the Artisan"]2["29th Street, Delhi, India"]3[]4[]5[]6[]7[]8["INVALID"]
3:7:1["Some"]2[""]3["Empty"]4[""]5[Fields "" Wrapped]6[""]7[in quotes]
4:6:1["Malformed" CSV]2[Data]3["Note it has data after" a close quote]4["and before a comma,"]5[]6["INVALID"]

请注意,字段号作为括号数据的前缀包括在内(因此我略微调整了打印格式)。

关于唯一不能处理的格式,是可以在字段的数据中插入换行符的格式-根据基于行的输入的性质,它假定没有字段被拆分为多行。 (这也意味着它将无法正确识别以双引号开头并且在行尾没有匹配的双引号的字段。我想您可以添加一个替代方法来识别该字段。这样做会更好。使数据正确。)


请注意Sobrique 答案中的建议,以使用专门用于处理CSV的工具来处理CSV。 通常这是一个好主意,并且您必须处理的变体集越复杂,它就越好。 您应该考虑使用的正则表达式非常复杂。 还要注意,尽管RFC 4180正式且严格地定义了CSV版本,但仍有多个程序(包括MS Office)处理不同但相关的格式。

如果您有需要解析的csv,则尽管通常可以使用正则表达式对其进行破解,但使用解析器要容易得多。

像这样:

#!/usr/bin/env perl

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV -> new; 
open ( my $input, '<', 'flarg.csv' ) or die $!; 

while ( my $row = $csv -> getline ( $input ) ) {
   if ( $. == 1 ) {
        # do first row stuff; 
        print "Header: ", join ",", @$row,"\n";
   }
   else {
       print join "\n", @$row;
   }
}

或更简单-使用核心的Text::ParseWords

#!/usr/bin/env perl

use strict;
use warnings;
use Text::ParseWords;

while ( my $line = <DATA> ) {
    my @fields = parse_line(',', 1, $line);
    print join "\n", @fields;
} 
__DATA__
"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM