perl 文本::CSV解析CSV在字符串下引用字符串,如1,“foo“bar”baz”,42 [已关闭]

fcy6dtqo  于 2022-12-30  发布在  Perl
关注(0)|答案(3)|浏览(131)

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
2小时前关门了。
Improve this question
我正在查看文档(https://metacpan.org/pod/Text::CSV#allow_loose_quotes)并以相同的方式实现。但是,即使在打开allow_loose_quotes后,也无法解析CSV的字符串。
CSV文本:1,"foo"栏"baz",42
解析为:

use Text::CSV

my $csv = Text::CSV->new({
    escape_char => '\\',
    quote_char => "\"",
    allow_loose_quotes => 1,
    sep_char => ',',
    });
while (my $line = <FH>) 
{
  chomp $line;
    
  # Parsing the line
  if ($csv->parse($line)) 
  {
      # Extracting elements
      my @words = $csv->fields();
      $worksheet->write_row($x, $y, \@words);
  } 
  else
  {
      # Warning to be displayed
      warn "Line could not be parsed: $line\n";
  }
  $x++;
}

请建议我如何解析CSV具有这种价值观。
我尝试按照文档中提到的那样进行解析

wribegjk

wribegjk1#

Text::CSV(和Text::CSV_XS)文档指出,如果设置allow_loose_quotes并确保转义字符与引号字符不同,则可以解析带有"a "b" c"之类字段的行。默认情况下,这两个字符都是"。注意,“escape”是CSV特性,而不是Perl字符串特性。
您使用的是parse,如果字符串中有完整的记录,这很好。但是,当您从文件中读取时,带引号的字段可能会扩展到两行。考虑"a\nb\nc\n"这样的字段,请改用getline,因为它知道如何在需要另一行来完成记录时获取另一行。
下面是一些行之有效的方法:

use v5.10;

use Text::CSV_XS;
use Data::Dumper;

my $csv = Text::CSV_XS->new({
    allow_loose_quotes => 1,
    quote_char         => q("),
    escape_char        => undef,
    });

say "Quote char is ", $csv->quote_char;
say "Escape char is ", $csv->escape_char;

while( my $row = $csv->getline(*DATA) ) {
    say Dumper($row)
    }

__DATA__
1,2,3
1,"foo "bar" baz",42
"a","b","c,d"

这将给出每行的输出:

Quote char is "
Escape char is
$VAR1 = [
          '1',
          '2',
          '3'
        ];

$VAR1 = [
          '1',
          'foo "bar" baz',
          '42'
        ];

$VAR1 = [
          'a',
          'b',
          'c,d'
        ];

而且,不管怎样,查看模块的测试套件以了解它如何使用某个特性通常是有用的。

yvfmudvl

yvfmudvl2#

在看了达达的评论,同样的代码是为他工作。它点击我,我应该升级到最新的文本::CSV模块和升级后,宾果现在为我工作。

ws51t4hk

ws51t4hk3#

输入文件的格式不正确,无法正确分析。
请参见以下代码示例并检查生成的 CSV 文件的内容。

use strict;
use warnings;
use feature 'say';

use Text::CSV;
use Data::Dumper;

my(@rows,$restored_rows);
my $fname = 'new.csv';

my $csv = Text::CSV->new({
    escape_char => '\\',
    quote_char => "\"",
    allow_loose_quotes => 1,
    sep_char => ',',
    });

@rows = (
        [1,'some "text" line 1', 42],
        [2,'some "text" line 2', 43],
        [3,'some "text" line 3', 44],
        [4,'some "text" line 4', 45]
    );

csv_save($fname,\@rows);
$restored_rows = csv_read($fname);

say Dumper($restored_rows);

exit 0;

sub csv_save {
    my $fname = shift;
    my $data  = shift;
    
    open my $fh, '>:encoding(utf8)', $fname
        or die "$fname: $!";
        
    $csv->say ($fh, $_) for $data->@*;

    close $fh
        or die "$fname: $!";
}

sub csv_read {
    my $fname = shift;
    my $data;
    
    open my $fh, "<:encoding(utf8)", $fname
        or die "$fname: $!";
    
    while (my $row = $csv->getline ($fh)) {
        push $data->@*, $row;
    }

    close $fh;
    
    return $data;
}

产出

$VAR1 = [
          [
            '1',
            'some "text" line 1',
            '42'
          ],
          [
            '2',
            'some "text" line 2',
            '43'
          ],
          [
            '3',
            'some "text" line 3',
            '44'
          ],
          [
            '4',
            'some "text" line 4',
            '45'
          ]
        ];

文件新.csv内容

1,"some \"text\" line 1",42
2,"some \"text\" line 2",43
3,"some \"text\" line 3",44
4,"some \"text\" line 4",45

相关问题