保留输入中引用的CSV字段的引号

时间:2014-10-26 03:17:40

标签: perl csv

我有一个CSV文件,无论是否需要,都会引用一些字段。我想要做的是加载此文件,修改一些值,并生成修改后的CSV,引用的字段保持不变。

我目前正在使用Perl的Text::CSV软件包尝试解决此问题,但遇到了一些障碍。以下是一个用于演示该问题的小型测试脚本:

use Text::CSV;

my $csv = Text::CSV->new ({'binary' => 1, 'allow_loose_quotes' => 1, 'keep_meta_info' => 1});
my $line = q^hello,"world"^;

print qq^input:  $line\n^;

$csv->parse($line);
my @flds = $csv->fields();
$csv->combine(@flds);

print 'output:  ', $csv->string(), "\n";

产生

input:  hello,"world"
output:  hello,world

根据Text :: CSV的文档,存在一个is_quoted()函数来测试输入中是否引用了一个字段,但如果我使用它来向字段添加周围的引号,我会得到意想不到的结果:

my $csv = Text::CSV->new ({'binary' => 1, 'allow_loose_quotes' => 1, 'keep_meta_info' => 1});
my $line = q^hello,"world"^;

print qq^input:  $line\n^;

$csv->parse($line);
my @flds = $csv->fields();

for my $idx (0..$#flds) {
    if ($csv->is_quoted($idx)) {
            $flds[$idx] = qq^"$flds[$idx]"^;
    }
}

$csv->combine(@flds);

print 'output:  ', $csv->string(), "\n";

产:

input:  hello,"world"
output:  hello,"""world"""

我相信我在combine()之前添加的引号被视为该字段的一部分,因此当combine()正在处理时,正在使用第二个双引号进行转义。< / p>

确保引用字段从输入到输出保持不变的最佳方法是什么?我不确定该应用程序是否会接受always_quote&#39; ed字段...是否有一些Text :: CSV对象属性的组合可以保持引号不变?或许我离开时调整了记录帖子 - combine

1 个答案:

答案 0 :(得分:2)

这很遗憾,但似乎虽然keep_meta_info允许您访问元数据但却无法告诉Text::CSV在输出时重新应用is_quoted状态

根据您的记录的复杂程度,您可以自行重新组装。但是,您必须应对以前安全无引号的字符串字段的更改,但在您处理之后现在需要引号。这将取决于您引入的更改类型,即您是否曾期望之前的安全&#34;字符串值将变得不安全。如果答案是&#34;永远不会&#34; (即0.00000%几率),那么你应该自己重新组装并记录你已经完成的事情。

后处理需要您对字符串进行CSV解析以处理字符串中逗号和其他不安全字符的可能性,因此这可能不是一个选项。

或者,您可以深入了解Text::CSV的代码并实现所需的功能。即允许用户强制在输出中引用特定字段。我玩了它,它看起来像所需机制的一部分可能就位,但不幸的是我所有的访问权限是XS版本,它委托给本机代码,所以我此时无法深入研究。这是我得到的:

原始combine方法。请注意_FFLAGSundef的设置。

sub combine
{
    my $self = shift;
    my $str  = "";
    $self->{_FIELDS} = \@_;
    $self->{_FFLAGS} = undef;
    $self->{_STATUS} = (@_ > 0) && $self->Combine (\$str, \@_, 0);
    $self->{_STRING} = \$str;
    $self->{_STATUS};
    } # combine

我的尝试。我猜测Combine的第二个参数可能是标志,但由于(小写)combine API基于接收数组而不是数组引用,因此没有办法传递两个数组。我改变它以期望两个arrayrefs并尝试将第二个传递给Combine,但是&#34;无法调用方法&#34; print&#34;在未经证实的参考&#34;

sub combine2
{
    my $self = shift;
    my $str  = "";
    my $f    = shift;
    my $g    = shift;
    $self->{_FIELDS} = $f;
    $self->{_FFLAGS} = $g;
    $self->{_STATUS} = (@$f > 0) && $self->Combine (\$str, $f, $g);
    $self->{_STRING} = \$str;
    $self->{_STATUS};
    } # combine