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

时间:2015-01-27 22:37:00

标签: perl csv

我有以下使用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

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

2 个答案:

答案 0 :(得分:5)

尝试

for my $field (@fields)

而不是

while(my $field = <@fields>)

while语句没有按照您的想法执行。它相当于

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

远远不是你的意思。 (glob打破它在空格上的参数,并尝试扩展通配符,匹配磁盘上的文件。你的参数没有任何通配符,所以它的意思与split ' ', "@fields"相同。< / p>

答案 1 :(得分:3)

问题在于你的第二个循环:

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的元素连接成一个字符串,以$"分隔(默认为单个空格)。因此,如果@fields包含FOOBARIM FOO BAR'D,则join的结果将为

FOO BAR IM FOO BAR'D

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

  

在列表上下文中,返回一个(可能为空)文件名扩展列表,其中包含EXPR的值,例如标准Unix shell /bin/csh。在标量上下文中,glob遍历此类文件名扩展,在列表耗尽时返回undef。这是实现<*.c>运算符[...]

的内部函数      

请注意,glob将其参数拆分为空格,并将每个段视为单独的模式。

所以

glob("FOO BAR IM FOO BAR'D")
标量上下文中的

将返回FOO,然后是BAR,然后是IM,依此类推。

作为cjm suggests,将您的循环更改为此类修复:

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

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

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