2

我正在解析格式如下的文本文件

> alpha
apple
airplane
art
> beta
bear
blue
beat
> charlie
cow
cent
coat

我正在尝试查找alpha beta charlie具有主题(例如“ta”)的条目()。如果找到了主题,那么我将尝试打印出每个条目下方的单词 ( bear blue beat)。所以在这个例子中,我想要以下输出

> beta
bear
blue
beat

我已经想出了如何打印入口行,但不知道如何打印出下面的行。任何想法将不胜感激。

my $motif = "ta";
my $file = "file.pl";
open(INPUT, $file) or die "Can't open file.\n";
parse($motif);

sub parse{
    my ($x) = (@_);
    while(<INPUT>){
        if($_ =~ />*($x)/){
            print $_."\n";
#       if($_ !~ />/){
#           print $_."\n";
        }else{
            next;
        }
    }
}
4

5 回答 5

4

这是另一种选择:

use strict;
use warnings;

my $motif = pop;
local $/ = '>';    # record separator

while (<>) {
    chomp;
    print $/ . $_ if /(?<=\x20).*?$motif/;
}

用法:perl script.pl data.txt 'ta'

在 data.txt 中输出您的数据:

> beta
bear
blue
beat

该符号local $/ = '>'将记录分隔符设置为>而不是通常的\n,因此每个>标记都标记了已读取记录的开始。您搜索的行在 之后有一个空格>,这就是积极的后视(?<=\x20)尝试匹配的内容。

您可以通过执行以下操作将输出重定向到文件:perl script.pl data.txt 'ta' >output.txt.

于 2013-02-13T04:45:36.860 回答
3

那么,你需要保持循环状态。匹配触发“打印”状态,不匹配则解除触发。所以你有这样的东西吗?

sub parse {
  my ($x) = (@_);
  my $printable = 0

  while (<INPUT>) {
    if ($_ =~ /^>.*($x)/) {
      print $_;
      $printable = 1;
    } elsif ($_ =~ /^>/) {
      $printable = 0;
    } elsif ($printable) {
      print $_;
    }
  }
}
于 2013-02-13T03:57:42.393 回答
1

基本上,您可以使用变量 ( $print_flag) 来查看是否应该打印该行。如果您获得所需的匹配项,则将其设置为 1(评估为 true),如果您匹配以开头">"但不包含$motif.

试试这个(警告:未经测试):

use strict;    #Always!
use warnings;  #Always!
my $motif = "ta";
my $file = "file.pl";
open(my $input,"<", $file) or die $!; #two argument open: bad!
parse($motif);

sub parse{
    my ($x) = (@_);
    my $print_flag = 0;
    while(<$input>){

        chomp; #removes trailing EOL character
        if(/^>.*($x)/)   #Don't need $_
        {    
            $print_flag = 1;
        }
        elsif(/^>/)
        {
            $print_flag = 0;
        }

        if($print_flag)
        {
            print "$_\n";
        }
    }
}
于 2013-02-13T03:55:53.767 回答
1

这种类型的问题对于 Perl 范围运算符(在这种情况下更普遍地称为“触发器”运算符)来说似乎很自然。但是,您的要求细节最终使它比我预期的要复杂一些:

#!/usr/bin/env perl    

use strict;
use warnings;

parse('ta');

sub parse {
  my $pattern = shift;

  my $seq;
  while (<DATA>) {
    if ($seq = /^>.*$pattern/ ... (/^>/ && !/^>.*$pattern/)) {
      print unless $seq =~ /E0$/;
    }
  }
}


__DATA__
> alpha
apple
airplane
art
> beta
bear
blue
beat
> charlie
cow
cent
coat

输出:

> beta
bear
blue
beat
于 2013-02-13T10:51:43.567 回答
0

如果匹配后的行数总是相同(三),那么这个骇人听闻的“匹配倒计时”成语就可以了:

 perl -ne '$m=4 if (/^>s/ ); print if ($m-->0);'

我们使用"4"来匹配行加上它后面的行数 ( 3),然后我们$m--在继续进行时使用 倒计时print。我$m用来模仿 shell 中的类似选项grep。但是,我实际上不确定这是否是一个成语,或者如果是这样的话,它的公认名称是什么。flip-flop范围方法可能...在脚本中更可取或更广泛使用 - 但这里有一个独立的脚本来尝试使用更hackish的方法。

传入要搜索的行数和模式作为参数:

#!perl
use v5.16; # strict & warnings

my $linesafter ; 
my $num = shift ;                                                              
my $pat = shift ;                                                              

while (<DATA>) {                                                               
  $linesafter = $num if ( /^> $pat/ );                                         
  print if ($linesafter-->0); 
}                                                                              

__DATA__                                                                       
> alpha                                                                        
apple                                                                         
airplane                                                                     
art                                                                           
> beta                                                                         
bear                                                                           
blue                                                                          
beat                                                                          
> charlie                                                                     
cow                                                                           
cent                                                                        
coat    
于 2014-12-01T22:49:48.810 回答