Perl 在输入中引用的CSV字段上保留引号
我有一个CSV文件,这样一些字段被引用,而不管它们是否需要被引用。我想做的是加载这个文件,修改一些值,并生成修改后的CSV,其中带引号的字段保持不变 我目前正在使用Perl的包试图解决这个问题,但遇到了一些障碍。以下是一个小测试脚本,用于演示该问题:Perl 在输入中引用的CSV字段上保留引号,perl,csv,Perl,Csv,我有一个CSV文件,这样一些字段被引用,而不管它们是否需要被引用。我想做的是加载这个文件,修改一些值,并生成修改后的CSV,其中带引号的字段保持不变 我目前正在使用Perl的包试图解决这个问题,但遇到了一些障碍。以下是一个小测试脚本,用于演示该问题: use Text::CSV; my $csv = Text::CSV->new ({'binary' => 1, 'allow_loose_quotes' => 1, 'keep_meta_info' => 1}); my
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的文档,存在一个函数来测试输入中是否引用了字段,但是如果我使用它向字段添加周围的引号,我会得到意外的结果:
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()
正在处理时用第二个双引号转义
确保引用字段在输入到输出之间保持完整的最佳方法是什么?我不确定应用程序是否会接受
始终\u quote
'ed字段。。。是否存在允许保留引号完整的Text::CSV对象属性组合?或者也许我只剩下调整记录后的组合了?这是一个遗憾,但似乎当保留元数据信息
让您可以访问元数据时,没有选项告诉文本::CSV
在输出时重新应用被引用
状态
根据您的记录有多复杂,您可以自己重新组装它。但是,您必须处理对字符串字段的更改,这些更改以前是安全地不带引号的,但在处理之后现在需要带引号。这将取决于您引入的更改类型,即您是否期望以前的“安全”字符串值会变得不安全。如果答案是“从不”(即0.00000%的几率),那么您应该自己重新组装并记录您所做的工作
后期处理需要CSV解析字符串以处理字符串中可能存在的逗号和其他不安全字符,因此这可能不是一个选项
或者,您可以深入了解Text::CSV
的代码,并实现所需的功能。即,允许用户在输出时强制引用特定字段。我对它进行了研究,看起来所需机制的一部分可能已经到位,但不幸的是,我只能访问XS版本,它将委托给本机代码,因此我现在无法深入研究。就我所知:
原始的合并方法。注意将\u FFLAGS
设置为undef
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基于接收数组而不是arrayref,因此无法传入两个数组。我将其更改为预期两个ArrayRef,并尝试将第二个ArrayRef传递给Combine
,但由于“无法调用方法”print“on unblessed reference”而失败
+1个好问题,感谢您提供可运行的代码。
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