Perl:逐行添加2个文件

时间:2016-06-22 16:23:26

标签: perl file

我是perl的初学者,所以请耐心等待。

我有2个文件:

1
2
3

2
4
5
6

我想创建一个新文件,它是上述两个文件的总和:

输出文件:

3
6
8
6

我现在正在做的是将文件作为数组读取并逐个元素地添加它们。

要添加数组,我使用以下内容:

$asum[@asum] = $array1[@asum] + $array2[@asum] while defined $array1[@asum] or defined $array2[@asum];

但这会产生以下错误:

Argument "M-oM-;M-?3" isn't numeric in addition (+) at perl_ii.pl line 30.
Argument "M-oM-;M-?1" isn't numeric in addition (+) at perl_ii.pl line 30.
Use of uninitialized value in addition (+) at perl_ii.pl line 30.

我使用以下代码将文件读取为数组:

use strict;
use warnings;

my @array1;
open(my $fh, "<", "file1.txt") or die "Failed to open file1\n";
while(<$fh>) { 
    chomp; 
    push @array1, $_;
} 
close $fh;

my @array2;
open(my $fh1, "<", "file2.txt") or die "Failed to open file2\n";
while(<$fh1>) {
    chomp;
    push @array2, $_;
}
close $fh1 ;

任何人都可以告诉我如何解决这个问题,或者完全采取更好的方法?

6 个答案:

答案 0 :(得分:3)

这是另一个使用菱形<>文件读取运算符的Perl解决方案。这将读入命令行中指定的文件(而不是在程序中显式打开它们)。抱歉,我无法找到解释此内容的文档部分。

此程序的命令行如下所示:

perl myprogram.pl file1 file2 > outputfile

其中file1和file2是2个输入文件,outputfile是要打印添加结果的文件。

#!/usr/bin/perl
use strict;
use warnings;

my @sums;
my $i = 0;
while (my $num = <>) {
    $sums[$i++] += $num;
    $i = 0 if eof;
}

print "$_\n" for @sums;

注意:$i在文件末尾重置为零(在这种情况下,在读取第一个文件之后)。实际上,在读取第二个文件后它也会重置为0。但是,这对程序没有影响,因为在示例中的第二个文件之后没有要读取的文件。

答案 1 :(得分:3)

以下解决方案使程序的内存占用量与文件大小无关。相反,现在内存占用量仅取决于文件的 number

FixedLengthTokenizer

答案 2 :(得分:2)

您的脚本现在有两个不同的问题:

  1. 第一个错误

      

    论证&#34; M-oM-; M-?3&#34;在perl_ii.pl行另外(+)不是数字   30

    发生

    是因为您的输入文件以Unicode格式保存,第一行使用&#34; \ xFF \ xFE&#34; BOM字节。 要简单地修复它,只需将文件重新保存为ANSI文本。如果需要Unicode,则从您从文件中读取的第一个字符串中删除这些字节。

  2. 第二个错误

      

    在perl_ii.pl第30行另外使用未初始化的值(+)。

    发生

    是因为您访问了第一个不存在的数组中的第4个元素。请记住,您选择最大输入数组长度作为索引限制。要修复它,只需为input元素添加以下条件:

    $asum[@asum] = (@asum < @array1 ? $array1[@asum] : 0)  + (@asum < @array2 ? $array2[@asum] : 0) while defined $array1[@asum] or defined $array2[@asum];
    

答案 3 :(得分:2)

读取两个文件的逻辑是一样的,我建议使用一个子程序并调用它两次:

#!/usr/bin/env perl

use strict;
use warnings;

my @array1 = read_into_array('file1.txt');
my @array2 = read_into_array('file2.txt');

sub read_into_array
{
    my $filename = shift;
    my @array;
    open(my $fh, "<", $filename) or die "Failed to open $filename: $!\n";
    while(<$fh>) { 
        chomp; 
        push @array, $_;
    } 
    close $fh;
    return @array;
}

但这只是我做出的一个观察,而不是你问题的解决方案。作为CodeFuller already said,您应该将文件重新保存为纯ASCII而不是UTF-8。

第二个问题,使用未初始化的值(+),也可以使用Perl 5.10中引入的Logical Defined Or运算符//来解决:

my @asum;
$asum[@asum] = ($array1[@asum] // 0) 
             + ($array2[@asum] // 0) 
             while defined $array1[@asum] or defined $array2[@asum];

不,这不是评论,而是与||非常相似的运营商。不同之处在于,当左侧(lhs)为undef时触发,而当{lhs 虚假时触发||(即0''undef)。因此

$array1[@asum] // 0
如果0为undef,则

给出$array1[@asum]。它与

相同
defined($array1[@asum]) ? $array1[@asum] : 0

答案 4 :(得分:1)

完全不同的方法:

$ paste -d '+' file1 file2 | sed 's/^+//;s/+$//' | bc
3
6
8
6

paste命令打印彼此相邻的文件,以+符号分隔:

$ paste -d '+' file1 file2
1+2
2+4
3+5
+6

sed命令会删除前导和尾随+符号,因为这些符号会bc

$ paste -d '+' file1 file2 | sed 's/^+//;s/+$//'
1+2
2+4
3+5
6

bc最终计算总和。

答案 5 :(得分:1)

以英语形式更新Sinan’s approach

#!/usr/bin/env perl
use 5.010; use strict; use warnings;

use autodie;
use List::Util 'sum';

my @fh = map { open my $fh, '<', $_; $fh } @ARGV;

while ( my @value = grep { defined } map { scalar readline $_ } @fh ) {
    say sum @value;
    @fh = grep { not eof $_ } @fh if @value < @fh;
}