我有以下使用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";
}
}
当我在为@fields
分配值后,尝试遍历@$row
数组时,会分解空格中的值。例如
"FOO","BAR","IM FOO BAR'D"
出现
FOO
BAR
IM
FOO
BAR'D
为什么会发生这种情况,我该如何解决?
答案 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
包含FOO
,BAR
和IM 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";
}