Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在perl中跟踪上一行和下一行的最佳方法_Perl_Loops_Readfile - Fatal编程技术网

在perl中跟踪上一行和下一行的最佳方法

在perl中跟踪上一行和下一行的最佳方法,perl,loops,readfile,Perl,Loops,Readfile,在perl中,保持上一行和/或下一行信息的最佳/正确方法是什么。例如,使用此代码: while (<IN>) { print; } while(){ 打印 } 如果文件中的上一行或下一行与foo匹配,如何更改为不打印该行,而打印其他行 你能给出代码示例吗。谢谢。我会将文件读入一个数组,每行都是一个数组元素,然后您可以进行比较。唯一真正的设计考虑是要读入内存的文件的大小。更新:简化说明。 基本上,如果要根据另外两行中包含的信息打印当前行,则需要跟踪两行。下面是一个简单的脚本,

在perl中,保持上一行和/或下一行信息的最佳/正确方法是什么。例如,使用此代码:

while (<IN>) {
   print;
}
while(){
打印
}
如果文件中的上一行或下一行与foo匹配,如何更改为不打印该行,而打印其他行


你能给出代码示例吗。谢谢。

我会将文件读入一个数组,每行都是一个数组元素,然后您可以进行比较。唯一真正的设计考虑是要读入内存的文件的大小。

更新:简化说明。 基本上,如果要根据另外两行中包含的信息打印当前行,则需要跟踪两行。下面是一个简单的脚本,包含所有硬编码的内容:

#!/usr/bin/env perl

use strict;
use warnings;

my $prev = undef;
my $candidate = scalar <DATA>;

while (defined $candidate) {
    my $next = <DATA>;
    unless (
        (defined($prev) && ($prev =~ /foo/)) ||
        (defined($next) && ($next =~ /foo/))
    ) {
        print $candidate;
    }
    ($prev, $candidate) = ($candidate, $next);
}

__DATA__
1
2
foo
3
4
5
foo
6
foo
7
8
9
foo
#/usr/bin/env perl
严格使用;
使用警告;
my$prev=未定义;
我的$candidate=标量;
while(定义为$candidate){
我的$next=;
除非(
(已定义($prev)和($prev=~/foo/)||
(已定义($next)&($next=~/foo/)
) {
打印$candidate;
}
($prev,$candidate)=($candidate,$next);
}
__资料__
1.
2.
福
3.
4.
5.
福
6.
福
7.
8.
9
福
我们可以将其推广到接受文件句柄和测试(作为子例程引用)的函数:

#/usr/bin/env perl
严格使用;使用警告;
打印中间if(\*数据,子{返回(
(已定义($\[0])&&($\[0]=~/foo/)||
(已定义($\[1])&($\[1]=~/foo/)
)} );
子打印\u中间\u如果{
我的$fh=班次;
我的$test=shift;
my$prev=未定义;
我的$candidate=标量;
while(定义为$candidate){
我的$next=;
如果$test->($prev,$next),则打印$candidate;
($prev,$candidate)=($candidate,$next);
}
}
__资料__
1.
2.
福
3.
4.
5.
福
6.
福
7.
8.
9
福

你可以把你的行读入一个数组,然后如果你得到某种信号,就弹出数组的最后几个元素。阅读完中的所有内容后,可以打印:

use strict;
use warnings;
use feature qw(say);
use autodie;  #Won't catch attempt to read from an empty file

use constant    FILE_NAME => "some_name.txt"
   or die qq(Cannot open ) . FILE_NAME . qq(for reading: $!\n);
open my $fh, "<", FILE_NAME;

my @output;
LINE:
while ( my $line = <DATA> ) {
    chomp $line;
    if ( $line eq "foo" ) {
        pop @output;  #The line before foo
        <DATA>;        #The line after foo
        next LINE;    #Skip line foo. Don't push it into the array
    }
    push @output, $line;
}
唯一的问题是这需要内存。如果文件非常大,可能会耗尽内存

解决这个问题的一种方法是使用缓冲区。将值存储在数组中,并在数组中推送另一个值时移出最后一个值。如果读取的值为
foo
,则可以重置数组。在这种情况下,缓冲区最多包含一行:

#! /usr/bin/env perl

use strict;
use warnings;
use autodie;
use feature qw(say);

my @buffer;
LINE:
while ( my $line = <DATA> ) {
    chomp $line;
    if ( $line eq "foo" ) {
        @buffer = ();    #Empty buffer of previous line
        <DATA>;           #Get rid of the next line
        next LINE;       #Foo doesn't get pushed into the buffer
    }
    push @buffer, $line;
    if ( @buffer > 1 ) {    #Buffer is "full"
        say shift @buffer; #Print out previous line
    }
}
#
# Empty out buffer
#
for my $line ( @buffer ) {
    say $line;
}
__DATA__
2
3
4
5
6
7
8
9
10
11
12
13
1
2
foo
3
4
5
foo
6
7
8
9
foo
#/usr/bin/env perl
严格使用;
使用警告;
使用自动模具;
使用特征qw(例如);
我的@buffer;
行:
while(我的$line=){
chomp$行;
如果($line eq“foo”){
@缓冲区=();#前一行的空缓冲区
去掉下一行
下一行;#Foo不会被推入缓冲区
}
按@buffer$line;
如果(@buffer>1){#buffer为“满”
说shift@buffer;#打印前一行
}
}
#
#清空缓冲区
#
对于我的$line(@buffer){
比如说$line;
}
__资料__
2.
3.
4.
5.
6.
7.
8.
9
10
11
12
13
1.
2.
福
3.
4.
5.
福
6.
7.
8.
9
福

请注意,当我跳过下一行时,很可能尝试从空文件中读取。这没关系。
将返回空字符串或undef,但我可以忽略它。当我返回循环的顶部时,我将捕获错误

我没有看到您对“最佳”有任何具体的标准,因此我将为您提供一个可能是“最佳”的解决方案,这个解决方案可能与目前提出的解决方案不同。您可以使用整个文件并将其视为一个数组,然后使用索引迭代该数组。上一行和下一行分别是
$index-1
$index+1
。您只需稍微担心索引超出数组的边界。下面是一个例子:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;          # just for "say"
use Tie::File;

tie my @array, 'Tie::File', "filename" or die;

for my $i (0..$#array) {
    if ($i > 0 && $i < $#array) {   # ensure $i-1 and $i+1 make sense
        next if $array[$i-1] =~ /BEFORE/ &&
                $array[$i+1] =~ /AFTER/;
    }
    say $array[$i];
}
#/usr/bin/env perl
严格使用;
使用警告;
使用5.010;#只是为了“说”
使用Tie::文件;
绑定my@array、'tie::File'、'filename'或die;
对于我的$i(0..$#数组){
如果($i>0&&$i<$#数组){#确保$i-1和$i+1有意义
如果$array[$i-1]=~/BEFORE/&&
$array[$i+1]=~/AFTER/;
}
比如说$array[$i];
}
如果更方便的话,您可以指定一个文件句柄而不是文件名,并且还可以使用一些参数来控制内存使用,或者如果需要的话,可以更改“行”的含义。查看文档了解更多信息


无论如何,这是另一种方法,如果您熟悉数组并且喜欢从数组的角度思考,那么在概念上可能会更简单

这是家庭作业吗?您尝试过什么?没有,这只是问题的简化,这里发布的答案可能会引起使用perl但知识有限的人的普遍兴趣,就像我一样。。。我有两个表格文件(比如4列),我想相交并删除文件B中存在的文件A中的行(我已经使用%seen在您的帮助下为此编写了代码),但前提是文件A的前一行和下一行在第3列中没有例如foo。谢谢你的帮助。虽然我不理解所有的语句和变量,但我会努力解决这个问题。如果可以的话,我会投票给你。很抱歉,我不知道,但是如果子例程有数组引用,我会尝试将文件中的数据读取到print_mid_中,但是我无法设置测试,因为$[0]未定义…接受背景和解释的答案。我遇到的唯一问题是在不经过第一个run()子例程的情况下通过输入流和打印_mid_if子例程的测试。但我会尽力做到的。仅供参考。它可能会提供信息或让人困惑。我不确定您在调用子例程时遇到了什么样的问题。正如我之前所问的,请将这些信息合并到您的帖子中,以便我们提供帮助。如果我理解正确,问题是过滤掉前面或后面包含
foo
的行。我不认为你们两个
#! /usr/bin/env perl

use strict;
use warnings;
use autodie;
use feature qw(say);

my @buffer;
LINE:
while ( my $line = <DATA> ) {
    chomp $line;
    if ( $line eq "foo" ) {
        @buffer = ();    #Empty buffer of previous line
        <DATA>;           #Get rid of the next line
        next LINE;       #Foo doesn't get pushed into the buffer
    }
    push @buffer, $line;
    if ( @buffer > 1 ) {    #Buffer is "full"
        say shift @buffer; #Print out previous line
    }
}
#
# Empty out buffer
#
for my $line ( @buffer ) {
    say $line;
}
__DATA__
2
3
4
5
6
7
8
9
10
11
12
13
1
2
foo
3
4
5
foo
6
7
8
9
foo
#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;          # just for "say"
use Tie::File;

tie my @array, 'Tie::File', "filename" or die;

for my $i (0..$#array) {
    if ($i > 0 && $i < $#array) {   # ensure $i-1 and $i+1 make sense
        next if $array[$i-1] =~ /BEFORE/ &&
                $array[$i+1] =~ /AFTER/;
    }
    say $array[$i];
}