perl拆分分隔符从文件逐行

时间:2016-06-02 09:45:16

标签: arrays perl

我有一个名为' dataexample'的文本文件。像这样的多行:

a|30|40
b|50|70

然后我用这段代码分割分隔符:

open(FILE, 'dataexample') or die "File not exist";
while(<FILE>){
    my @record = split(/\|/, $_);
    print "$record[0]";
}
close FILE;

当我print "$record[0]"时,这就是我得到的:

ab

我的期望:

a 30 40

所以当我print "$record[0][0]"时,我希望输出为:a

哪里弄错了?

5 个答案:

答案 0 :(得分:4)

您的循环while ( <FILE> ) { ... }一次从文件句柄读取一行并将其放入$_

my @record = split(/\|/, $_)在管道字符|上拆分该行,因此第一行是"a|30|40\n"@record现在将是'a', '30', "40\n"。从文件中读取的换行符仍然存在,如果您不想在那里删除,则应使用chomp将其删除

所以现在$record[0]a,您打印,然后继续阅读文件中的下一行,这次将@record设置为'b', '50', "70\n"。现在$record[0]b,您也会打印,在控制台上显示ab

您现在已到达文件末尾,因此while循环终止

这听起来像是你期待一个二维数组。你可以通过在每次读取记录时将每个数组推到主数组上来实现,比如

use strict;
use warnings 'all';

open my $fh, '<', 'dataexample' or die qq{Unable to open "dataexample" for input: $!};

my @data;

while ( <$fh> ) {
    chomp;
    my @record = split /\|/;
    push @data, \@record;
}

print "@{$data[0]}\n";

print "$data[0][0]\n";

输出

a 30 40
a

或者,更简洁,像这样,产生完全相同的结果,但可能会有点先进

use strict;
use warnings 'all';

open my $fh, '<', 'dataexample' or die qq{Unable to open "dataexample" for input: $!};

my @data = map { chomp; [ split /\|/ ] } <$fh>;

print "@{$data[0]}\n";

print "$data[0][0]\n";

了解自己代码的一些要点

  • 必须始终 use strictuse warnings 'all'位于您编写的每个Perl程序的顶部。这是一个可以发现许多你可能没有注意到的简单错误的措施

  • 您应该将词汇文件句柄与三参数表单或open一起使用。由于文件不存在的其他许多原因,open可能会失败,因此您应该在$!字符串中加入内置的die变量,以说为什么失败了

  • 请勿忘记chomp从文件中读取的每条记录,除非您想保留后续的新行或对您不重要

  • 如果您习惯使用默认变量 $_,您将能够编写更简洁的代码。例如,split的第二个参数默认为$_,因此split(/\|/, $_)可能只写为split /\|/

您可以使用Data::Dumper显示变量的内容,这将有助于您调试代码。 Data::Dump是优越的,但它不是核心模块,因此您可能必须先安装它才能在代码中使用它

答案 1 :(得分:3)

你必须使用

print "$record[1]";
print "$record[2]";

因为它们存储在连续的索引值中。

如果你想打印整件事,你可以做

print "@record\n";

答案 2 :(得分:2)

每次循环时都会在数组的第一个索引处打印值,而不使用新行。因此,您从每一行获得第一个值,在同一行上彼此相邻,因此ab

使用新行在引号下打印整个数组。你的程序改变了一点

use strict;
use warnings;

my $file = 'dataexample';
open my $fh, '<', $file or die "Error opening $file: $!";
while (<$fh>) {
    chomp;
    my @record = split(/\|/, $_);
    print "@record\n";
}
close $fh;

使用引号打印元素时,在它们之间添加空格,以便

a 30 40
b 50 70

如果您在没有引号的情况下进行打印,则会打印元素而不会留出额外的空格 此

print @record, "\n";

整个循环打印

a3040
b5070

如果你没有新的行"\n",那么它全部打印在一行上,所以这个

print @record;

完全打印

a3040b5070

对于$record[0][0],这对您拥有的数组无效。这将从二维数组打印。举个例子,

my @data = ( [1.1, 2.2], [10, 20] );

此数组@data在其第一个索引处具有对数组的引用 - 更确切地说,是匿名数组 [1.1, 2.2]。它的第二个元素是匿名数组[10, 20]。所以$data[0][0]是:@data的第一个元素(所以内部的两个匿名数组中的第一个),然后是该数组的第一个元素,即1.1。同样地,$data[1][1]20。 感谢Sobrique发表评论。

但是你的程序中没有这个。将数据拆分为数组时

while(<FILE>){
   my @record = split(/\|/, $_);
   # ...
}

每次循环都会创建一个名为@record的新数组。所以@record是一个普通数组,而不是二维数组。为此,语法$record[0][0]并没有多大意义。

答案 3 :(得分:1)

我认为您正在尝试创建一个二维数组,其中每个元素都包含输入每行的所有管道分隔项:

my @record;
while(<DATA>){
    chomp;
    my @split = split(/\|/);
    push @record, [@split];
}

print "@{$record[0]}\n";
a 30 40

答案 4 :(得分:0)

record[0]包含第1列的内容 - &#39; a&#39;在循环的第一次迭代中,&#39; b&#39;在第二个。 record[1]有第2列,依此类推。您将打印语句print "record[0]" 放入循环中,以便获得&#39; a&#39;在第一次迭代中打印并且&#39; b&#39;在第二个。

要获得您想要的内容,您需要用;

替换print语句
print join " ", @record, "\n";