如何解析PERL中包含字段中的引号的CSV?

Int*_*ted 0 csv perl

我的数据中有引号,引用地址中属性的名称.例如

"21JAN1984:00:00:00","M",""Millfield""," "
Run Code Online (Sandbox Code Playgroud)

此时PERL Text :: CSV因错误而死亡

CSV_PP ERROR: 2025 - EIQ - Loose unescaped escape
Run Code Online (Sandbox Code Playgroud)

这看起来像有效的CSV,就像一个字段,"詹姆斯说"很好"."

使用的代码的缩写版本是:

my $csv = Text::CSV->new({
  binary => 1,
  auto_diag => 1,
  eol => "\n",
  always_quote => 1
}) or die "Cannot use CSV: " . Text::CSV->error_diag();

open my $fh, '<',  $ARGV[0] or die $!;
while (my $person = $csv->getline_hr($fh)) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 5

解决修订后的问题

"21JAN1984:00:00:00","M",""Millfield""," "
Run Code Online (Sandbox Code Playgroud)

如果您想要之前的双引号Millfield和之后的另一个引号,则正确的CSV格式为:

"21JAN1984:00:00:00","M","""Millfield"""," "
Run Code Online (Sandbox Code Playgroud)

如上所述,CSV数据被破坏.或者,无论如何,它不是"标准"格式.您可以找到CSV的标准规范作为RFC4180.这与微软的规范不同; RFC本身确定Excel不使用这种格式.

由于您使用的是Perl的Text :: CSV模块,因此您应该阅读其规范.请注意,该allow_loose_quotes属性描述的输入与您尝试处理的内容完全相同.它是可用于配置Text::CSVnew方法行为的众多属性之一.

解决原始问题

该问题的原始版本中显示的是可怕的格式错误的CSV.

21JAN1984:00:00:00","M",""Millfield""," "
Run Code Online (Sandbox Code Playgroud)

之后的双引号在00格式中没有位置.充其量,您必须将其视为由后面的逗号分隔的字段末尾的常规字符.这"M"是没有争议的.这""Millfield""是畸形的; 如果一个字符串以双引号开头,它将在下一个双引号结束,除非它本身后跟另一个双引号,所以第二个双引号是错误的.如果字段以双引号开头,则应用双引号括起来.您可以做的最好的事情是假设字段是Millfield""逗号停止,但是任何正常规则都是错误的.根据这些错误恢复规则," "最终没有争议.

要合理地构建并包含"Millfield"作为值,您需要以下其中一种:

"21JAN1984:00:00:00","M","""Millfield"""," "
21JAN1984:00:00:00,"M","""Millfield"""," "
21JAN1984:00:00:00,M,"""Millfield"""," "
21JAN1984:00:00:00,M,"""Millfield""", 
Run Code Online (Sandbox Code Playgroud)

这些行中的最后一行有一个尾随空白.

或者,如果Millfield在提取时不应该用双引号括起来,那么所有双引号都是多余的,尽管任何字段都可以被一对双引号括起来.

  • 我们只能回答你问的问题; 我们无法回答你想问的问题.正如我所解释的那样,米尔菲尔德周围的报价是虚假的.您需要在开头使用3个双引号才能在提取的值中单次出现双引号.还有别的错. (2认同)