代码之家  ›  专栏  ›  技术社区  ›  Casey

空文件上的perl拆分

  •  2
  • Casey  · 技术社区  · 14 年前

    我基本上使用了以下Perl:

    open I,$coupon_file or die "Error: File $coupon_file will not Open: $! \n";
    while (<I>) {
     $lctr++;
     chomp;
     my @line = split/,/;
     if (!@line) {
         print E "Error: $coupon_file is empty!\n\n";
         $processFile = 0; last;
     }
    }
    

    如果给split/,/函数一个空文件,我很难确定它返回什么。如果(!@不会被执行。如果我把它改成

    if (@line)
    

    然后执行代码块。我在 http://perldoc.perl.org/functions/split.html 以及讨论 here 关于测试一个空数组但不确定这里发生了什么。

    我是Perl新手,所以可能在这里遗漏了一些简单的东西。

    5 回复  |  直到 13 年前
        1
  •  1
  •   Greg Bacon    14 年前

    下面是一些使代码更习惯化的提示:

    • 这个 special variable $. 已经保存了当前行号,所以您可以删除 $lctr .
    • 空行真的是错误吗,还是可以忽略它们?
    • 把从 split 给这些碎片起个名字。
    • 让perl用 "diamond operator" :

    空文件句柄 <> 是特殊的:它可以用来模拟 sed awk . 输入来自 <> 来自标准输入或命令行中列出的每个文件。工作原理如下:第一次 <> 被评估, @ARGV 数组被选中,如果它是空的, $ARGV[0] 设置为 "-" ,打开时会提供标准输入。这个 @ ARGV 然后将数组作为文件名列表处理。循环

    while (<>) {
    ... # code for each line
    }
    

    相当于以下类似Perl的伪代码:

    unshift(@ARGV, '-') unless @ARGV;
    while ($ARGV = shift) {
      open(ARGV, $ARGV);
      while (<ARGV>) {
      ... # code for each line
      }
    }
    

    只是说起来没那么麻烦,而且会起作用的。

    假设您的输入位于名为 input 包含

    Campbell's soup,0.50
    Mac & Cheese,0.25

    然后用

    #! /usr/bin/perl
    
    use warnings;
    use strict;
    
    die "Usage: $0 coupon-file\n" unless @ARGV == 1;
    
    while (<>) {
      chomp;
    
      my($product,$discount) = split /,/;
      next unless defined $product && defined $discount;
    
      print "$product => $discount\n";
    }
    

    我们在Unix上运行如下:

    $ ./coupons input
    Campbell's soup => 0.50
    Mac & Cheese => 0.25
        2
  •  5
  •   Eugene Yarmash    14 年前
    1. 如果文件为空,while循环体将完全不运行。
    2. 在标量上下文中计算数组将返回数组中的元素数。

      split /,/ 如果 $_ 定义。

        3
  •  2
  •   ysth    14 年前

    您可以尝试一些调试:

    ...
    chomp;
    
    use Data::Dumper;
    $Data::Dumper::Useqq = 1;
    
    print Dumper( { "line is" => $_ } );
    my @line = split/,/;
    print Dumper( { "split into" => \@line } );
    
    if (!@line) {
    ...
    
        4
  •  0
  •   dlamotte    14 年前

    空文件还是空行?不管怎样,试试这个测试而不是 !@line .

    if (scalar(@line) == 0) {
        ...
    }
    

    这个 scalar 方法以Perl格式返回数组的长度。

    一些澄清:

    if (@line) {
    }
    

    同:

    if (scalar(@line)) {
    }
    

    在标量上下文中,数组( @line )返回数组的长度。所以 scalar(@line) 军队 @线 在标量上下文中求值并返回数组的长度。

        5
  •  0
  •   DVK    14 年前

    我不确定您是否在尝试检测行是否为空(您的代码正在尝试执行此操作),或者整个文件是否为空(这就是错误所说的)。

    如果行,请修正你的错误文本和逻辑应该像其他海报上说的那样(或者你可以把 if ($line =~ /^\s*$/) 如你所愿)。

    如果是文件,您只需要测试 if (!$lctr) {} 之后 循环结束-如另一个答案所述,如果文件中没有行,则不会输入循环。