为什么我不能在Perl脚本中逐行读取文件?

时间:2015-03-10 14:42:52

标签: perl

我有一个Perl脚本,它必须逐行读取文件。

文件中的行:

0060|9592014|A001-9592014-0060|82769|NOVARTIS PHARMA SERVICES AG        BASEL|51671|NOVARTIS AG|A+|SWITZERLAND|Guarantees Issued|12/31/2016|12/31/2016|0|0|0|0|0|0|0|0|0|29014.0967835279993469339764885601502052|0||||0|1|550.3648|32541||.32|SUIG|OLEG|AAA||||||END|

我只需要32个字段,前32个字段。

open (PRISM, "$infile") or die "Can't open $infile\n";
while (my $file_line = <PRISM>)
{
  last if ($file_line=~/^PRISMEXP/);
  next if ($file_line=~/^(\s)*$/);  # Skip blank lines
  print "LINE: $file_line\n";    # This line doesn't print anything
  my @field = (split /\|/, $file_line[0-32]);
  print "$field[0]\n";  #This line doesn't print anything
}

正如您所看到的,这部分代码不会读取文件,也不会打印任何内容。为什么?我的错误在哪里?

3 个答案:

答案 0 :(得分:3)

WHILE的位置应该while

此外,您的空行检查应该是=~,而不是=

您的split使用$file_line[0-32]$file_line[-32]相同,这是@file_line末尾的第32个元素,但您还没有设置在任何地方;我猜这应该是substr($file_line,0,32)。 或者,如果您只想要前32个字段,则应该是:

my @field;
@field[0..31] = split /\|/, $file_line;

始终使用use strict; use warnings;。它会捕获最后一个错误,也可能是第二个错误。

答案 1 :(得分:3)

以下是有关您的计划的一些注意事项,可帮助您提高成功率

  • 总是 use strictuse warnings位于每个 Perl程序的顶部,如果您还没有这样做

  • 使用词法文件句柄,例如my $prism_fh,而不是像PRISM

  • 这样的全局裸字文件句柄
  • 不要将标量变量放在双引号内。充其量它没有任何区别,最坏的情况下你会得到一个完全不同的字符串

  • 在检查$!来电状态时,始终die变量放在open字符串中。它会告诉你为什么打开失败。此外,perl会将源文件名和行号添加到die 的输出中,除非您在字符串末尾添加换行符,所以如果您想要,请不要这样做知道代码中发生错误的位置

  • 从文件中读取时,通常最好使用默认变量$_。许多运营商使用它作为默认参数,使代码更简洁整​​洁

  • 不要忘记unless。您可以使用next unless $file_line =~ /\S/

  • 更清晰地检查一行是否包含非空格
  • 如果您没有chomp输入行,则打印输出时无需在结尾处添加换行符

  • 您需要split行才能从输入中选择字段$file_line[0-32]无效Perl

这是您重构的Perl代码,以便它打印前32个管道分隔字段。我希望很明显它需要一个use strictuse warnings的序言,并定义$infile

open my $prism_fh, '<', $infile or die qq{Can't open "$infile": $!\n};

while (<$prism_fh>) {     
  next unless /\S/;
  last if /^PRISMEXP/;
  chomp;
  my @fields = (split /\|/);
  print join('|', @fields[0 .. 31]), "\n";
}    

<强>输出

0060|9592014|A001-9592014-0060|82769|NOVARTIS PHARMA SERVICES AG        BASEL|51671|NOVARTIS AG|A+|SWITZERLAND|Guarantees Issued|12/31/2016|12/31/2016|0|0|0|0|0|0|0|0|0|29014.0967835279993469339764885601502052|0||||0|1|550.3648|32541||.32

<强>更新

您可以使用正则表达式来抓取前32个以管道分隔的字段,而不是拆分和重新组合,就像这样

while (<$prism_fh) {     
  next unless /\S/;
  last if /^PRISMEXP/;
  chomp;
  print $1, "\n" if /^((?:[^|]*\|){31}[^|]*)/;
}

输出与上述程序的输出相同。

答案 2 :(得分:2)

由于这一行:

last if ($file_line=~/^PRISMEXP/);   

如果$infile的第一行以PRISMEXP开头,您将永远不会打印任何内容。

您还必须更改该行:

my @field = (split /\|/, $file_line[0-32]); 

为:

my @field = (split /\|/, $file_line)[0..32];