为什么我的 Text::CSV 代码在打印它们时会在空格处拆分值?

Why does my Text::CSV code split values on spaces when I print them?

我有以下使用 Text::CSV 的代码:

#!/usr/bin/perl

package main;
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV -> new ({ binary => 0, eol => $/ });
open my $io, "<", $file or die "$file: $!";

while (my $row = $csv -> getline ($io)) 
{
    my @fields = @$row;

    while(my $field = <@fields>) 
    {
        print $field."\n";
    }

}

(改编自 Text::CSV documentation

当我在为 @fields 数组分配来自 @$row 的值后尝试循环遍历它时,它会分解空格上的值。例如

"FOO","BAR","IM FOO BAR'D"

结果为

FOO
BAR
IM
FOO
BAR'D

为什么会发生这种情况,我该如何解决?

尝试

for my $field (@fields)

而不是

while(my $field = <@fields>)

while 语句与您认为的不一样。相当于

while (my $field = glob "@fields")

这与您的意思完全不同。 (glob 打破了它在空格上的论点并尝试扩展通配符,匹配磁盘上的文件。你的论点没有任何通配符,所以它最终的意思与 split ' ', "@fields" 大致相同)。

问题出在你的第二个循环中:

while(my $field = <@fields>) 
{
    print $field."\n";
}

您可以使用 B::Deparse:

查看实际情况
$ perl -MO=Deparse -e 'while (my $field = <@fields>) { print $field."\n" }'
use File::Glob ();
while (defined(my $field = glob(join($", @fields)))) {
    do {
        print $field . "\n"
    };
}
-e syntax OK

让我们稍微分解一下:

join($", @fields)

@fields 的元素连接成一个字符串,由 $" 分隔(默认为单个 space)。所以如果 @fields 包含 FOOBARIM FOO BAR'Djoin 的结果将是

FOO BAR IM FOO BAR'D

现在,glob 做什么?来自 perldoc -f glob:

In list context, returns a (possibly empty) list of filename expansions on the value of EXPR such as the standard Unix shell /bin/csh would do. In scalar context, glob iterates through such filename expansions, returning undef when the list is exhausted. This is the internal function implementing the <*.c> operator [...]

Note that glob splits its arguments on whitespace and treats each segment as separate pattern.

所以

glob("FOO BAR IM FOO BAR'D")

在标量上下文中将 return FOO,然后是 BAR,然后是 IM,依此类推。

作为 ,将循环更改为类似这样的内容以修复:

foreach my $field (@fields) 
{
    print "$field\n";
}

或者更好的是,不是将 @$row 的内容复制到 @fields 并循环遍历 @fields,而是直接循环遍历 @$row

foreach my $field (@$row) {
    print "$field\n";
}