【问题标题】:Perl: Erase empty lines and save in a new filePerl:擦除空行并保存在新文件中
【发布时间】:2013-01-16 18:39:26
【问题描述】:

我正在尝试编写一个脚本来计算和删除文件中的空行并将更改保存在新文件中:

if (@ARGV != 2) {
  print "Usage: $0 infile outfile\n";
  exit;
}
$infile = @ARGV[0];
$outfile = @ARGV[1];
open($old, "<$infile");
open($new, ">$outfile");
@mass = <$old>;
foreach $newc(@mass) {
    $counter++;
    if ($_ =~ /^$/) {
        print "blank line found in $old at line number $counter\n";
        print $new;
    }
}
close($new);
close($old);

但它不起作用。我哪里错了?

【问题讨论】:

  • 问题是什么?出了什么问题?
  • @ARGV[0] 效果很好,我之前在其他脚本中测试过。我的问题是我无法删除输入文件的这些空行和空格
  • @array[$index] 有效,但风格不正确。 @array[...] 旨在返回多个索引,例如 my @slice = @array[1,2,3,4,5]。请注意符号匹配,@slice@array 以相同的字符开头。这就是为什么最好写my $item = $array[0] 而不是my $item = @array[0];

标签: perl counter erase string


【解决方案1】:

这是另一个选择:

use strict;
use warnings;

@ARGV == 2 or die "Usage: $0 infile outfile\n";

open my $fhIN,  '<', $ARGV[0] or die $!;
open my $fhOUT, '>', $ARGV[1] or die $!;

while (<$fhIN>) {
    if (/\S/) {
        print $fhOUT $_;
    }
    else {
        print "Blank at line $.\n";
    }
}

正如amon 所示,您可以迭代文件的行,而无需先将它们读入数组。该脚本还利用了$.,其中包含文件的当前行号。正则表达式 /\S/ 检查行中的任何非空白字符,因为这表示非空白行。如果/\S/ 为真,则将行写入outfile,否则打印空行通知。

文件句柄的词法范围是the three-argument form of open(首选方法),因此文件将在脚本结束时自动close


您甚至可以更进一步,利用 STDIN、STDOUT 和 STDERR 获得最大的灵活性和实用性。

use strict;
use warnings;

while (<>) {
    if (/\S/) {
        print;
    }
    else {
        print STDERRR "Blank at line $.\n";
    }
}

那就用

script.pl file.in >file.out

而不是

script.pl file.in file.out

但它也允许你做类似的事情

prog1 | script.pl | prog2

【讨论】:

  • 不得不承认这比其他代码工作得更好,我在此处发布的其他代码有一些错误!谢谢
  • 我希望您不介意我在您的答案中添加了一个部分,展示了如何简化程序并使其更强大并同时表现得更像其他程序。
  • @ikegami - 介意吗?一点都不。我总是很感激你的补充和修改。我知道这对 OP 有好处,我也从中受益。谢谢。
【解决方案2】:

您没有在循环中使用$newc,并且只打印空行

foreach $newc (@mass) {
    $counter++;
    if ($newc =~ /^$/) {
        print "blank line found in $old at line number $counter\n";
    } else {
        print $new $newc;
    }
}

如 cmets 中所述,请使用 $ARGV[0]$ARGV[1]$ARGV[0]@ARGV 的第一个值,而@ARGV[0] 是一个切片。详情请见Slices

【讨论】:

    【解决方案3】:

    @mass 中的行仍然包含一个尾随换行符。在您的正则表达式中考虑这一点,或者选择值。

    我会像这样编写循环代码

    while (<$old>) {
      chomp;
      say {$new} $_ if length;
    }
    

    另外,测试open的返回值:

    open my $old, "<", $infile or die qq(Can't open "$infile": $!);
    

    将整个代码作为一条线:

    perl -nE'chomp; say if length' infile.txt >outfile.txt
    

    perl -nE'chomp; if(length){say}else{say STDERR "blank on line $."}' infile.txt >outfile.txt
    

    $.是当前输入的行号。)

    【讨论】:

    • 他确实记账。 /^$/(不同于/^\z/)将匹配"\n"
    • 顺便说一句,chomp 可以替换为-l,因为-nl chomps。 (-pl 也是如此。)
    【解决方案4】:

    你的脚本应该是这样的:

    if (@ARGV != 2) {
      print "Usage: $0 infile outfile\n";
      exit;
    }
    $infile = $ARGV[0];
    $outfile = $ARGV[1];
    open $old, "<", $infile;
    open $new, ">", $outfile;
    @mass = <$old>;
    $counter = 0;
    foreach $newc (@mass) {
        $counter++;
        if ($newc =~ /^$/) {
            print "blank line found in $infile at line number $counter\n";
        } else { # print in the new file when not an empty line!
            print $new $newc;
        }
    }
    close($new);
    close($old);
    

    【讨论】:

    • 为什么投反对票?代码有效!有人想宣传他们的答案??
    • 投反对票的原因:(1)答案几乎没有解释。 (2) 它使用了有点过时的编码风格;与当前的最佳实践略有不同:(2.1) 全局变量 (2.2) 忘记了 open 的返回值。 (3) 方案还是使用O(n)内存,这里O(1)就够了。
    • 不使用所有最佳实践的重点当然是尽可能少地修改他的代码,以便他可以看到修改在哪里
    • @amon 这与您的答案之间的区别在于,OP 可以看到他做错了什么。而在你的回答中,他只是知道会怎么做。
    【解决方案5】:
    if (@ARGV != 2) {
      print "Usage: $0 infile outfile\n";
      exit;
    }
    
    $infile = $ARGV[0];
    $outfile = $ARGV[1];
    open(OLD, "<$infile");
    open(NEW, ">$outfile");
    while ($line = <OLD>) {
        print NEW $line unless ($line =~ /^$/);
    }
    close(NEW);
    close(OLD);
    

    【讨论】:

    • 投反对票的原因:(1)答案包含no解释。 (2)它使用了可怕和过时的编码风格;与当前最佳实践相去甚远:(2.1) 全局变量 (2.2) 裸字文件句柄 (2.3) open 的双参数形式 (2.4) 忘记了 open 的返回值。
    • 这个原始问题是针对一个快速而肮脏的 perl 脚本。这不是生产应用程序,它是完成任务的快速工具。遵循 10 行脚本的编码实践只是愚蠢的 IMO。各有各的。
    • @amon 当我将这些规则应用于您的答案时,我也必须对您的答案投反对票。
    • @OlafDietsche 那么请务必这样做。
    • 总是use strict; use warnings;,不管它是否是“......一个快速而肮脏的perl脚本”。
    猜你喜欢
    • 2011-07-07
    • 1970-01-01
    • 2019-12-10
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多