【问题标题】:regex perl capture between two same tags across multiple lines in perl正则表达式 perl 在 perl 中跨多行的两个相同标签之间捕获
【发布时间】:2017-01-16 18:45:06
【问题描述】:

我有很多制表符分隔的文本文件,我需要在其中捕获测试中相同单词之间的所有内容,输入看起来像这样

H string
H string
H string
SCAN 00001 00001
I string
I string
432.203 194090 0
SCAN 00002 00002

使用相同的模式(以 I 开头的几行,然后是我需要捕获的数字),扫描从最低到最高排序,并且它们是唯一的。在两次“SCAN”之间,只有数字分隔在 3 列空间中,我需要提取第一个和第二个数字,在两次扫描之间,大约有两三千行由 3 个数字组成。

我不是正则表达式之神,但我正在尝试这个

while (<$fh_2>)
{
chomp;
next if (/^H/);

my $sc;

if (/(^S.+[\d]+)/../^S.+[\d]+/ms) #while we are between two ^S
{
my @sc_line= split /\s/, $1; #capture the scan number
$sc= pop @sc_line;
if (/(^[\d]+\.?[\d]*)/) # if there are numbers (m) at the start 
   {
    my @lines = split /\s/, $_;
    push @ms, $1; #capture the first number
    push @int, $lines[1]; #capture the second number (i)
    $m{$sc} = [@ms]; #create hash of array
    $in{$sc}= [@int];
   }
}

主要问题是我希望在特定扫描之后以某种方式将所有内容与该扫描匹配,但由于模式相同,我发现编写它很棘手。

输出必须是数组的散列或多维散列,其中对于每次扫描,我可以关联每个第一个数字 (m) 和 (i) 数字,它可以是两个单独的散列,也可以不是,只要我可以从扫描号中检索数组。
编辑:我用另一种方式解决了它

while (<$fh_2>)
{
chomp;

next if (/^H/);

if (/^S/) 
{ 
my @sc_line= split /\s/, $_;
my $sc_= pop @sc_line;
push @sc, $sc_;
push @count, scalar @int;
}
    elsif (/(^[\d]+\.?[\d]*)/)
    {
    my @lines = split /\s/, $_;
    push @ms, $1;
    push @int, $lines[1];
    }

}
close $fh_2;

每次@sc 获得一个新元素时,我都使用索引来获取@int(或@ms)的元素数量,一开始不考虑它是愚蠢的。 仍然有兴趣看看是否有任何 TIMTOWTDI 魔法正在发生。

【问题讨论】:

  • 你的问题不是很清楚。你能试着澄清一下吗?例如,您想从您提供的示例数据中具体提取什么?您只对SCAN 行感兴趣吗?如果是这样,您是否只对编号不同的SCAN 行感兴趣?
  • 即使是半神也能提供现实世界的输入字符串
  • 更好地提供样本输出
  • @GillesQuenot 添加
  • @redneb 我编辑了问题告诉我现在是否更清楚了

标签: regex perl


【解决方案1】:

这是将其作为两个数组散列的脚本。它们保留每个扫描编号内的扫描线顺序。试一试,看看它是否满足您的需求。

#!/usr/bin/perl -w
use strict;

my %m=();
my %in=();
my $sn="";

while (my $line=<>) {
   chomp($line);

   if ($line=~m/^SCAN (\d+) (\g1)/) {
     $sn="$1";
   }
   elsif ($line=~m/^(\d+.\d+) (\d+)/) {
     push(@{$m{$sn}},$1); push(@{$in{$sn}},$2);
   }
}


## You could also print the hash of hashes like this
#
use Data::Dumper;
$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 2;
$Data::Dumper::Sortkeys = 1;

print "Here is the dump of results:\n";
print "m = ".(Dumper(\%m))."\nin = ".(Dumper(\%in));


## Printing manually
#
print "\nHere is how you can print them manually:\n";
for my $sn (sort keys %m) {
   for my $i (0..scalar(@{$m{$sn}})-1) {
      print "ScanNumber<$sn> First<$m{$sn}[$i]> Second<$in{$sn}[$i]>\n";
   }
}

这里是示例数据:

H string
H string
H string
SCAN 00001 00001
I string
I string
100.100 100000 0
200.200 200000 0
SCAN 00002 00002
H string
H string
H string
300.300 300000 0
400.400 400000 0
500.500 500000 0
600.600 600000 0
700.700 700000 0
800.800 800000 0
900.900 900000 0
SCAN 00001 00003

这里是命令运行的输出:./script.pl

Here is the dump of results:
m = {
  '00001' => [
               '100.100',
               '200.200'
             ],
  '00002' => [
               '300.300',
               '400.400',
               '500.500',
               '600.600',
               '700.700',
               '800.800',
               '900.900'
             ]
}

in = {
  '00001' => [
               '100000',
               '200000'
             ],
  '00002' => [
               '300000',
               '400000',
               '500000',
               '600000',
               '700000',
               '800000',
               '900000'
             ]
}

Here is how you can print them manually:
ScanNumber<00001> First<100.100> Second<100000>
ScanNumber<00001> First<200.200> Second<200000>
ScanNumber<00002> First<300.300> Second<300000>
ScanNumber<00002> First<400.400> Second<400000>
ScanNumber<00002> First<500.500> Second<500000>
ScanNumber<00002> First<600.600> Second<600000>
ScanNumber<00002> First<700.700> Second<700000>
ScanNumber<00002> First<800.800> Second<800000>
ScanNumber<00002> First<900.900> Second<900000>

【讨论】:

    【解决方案2】:

    试试下面的。我希望这提供了一个解决方案,至少可以满足您的需求。建议修改(或自己修改)以使其完全符合您的要求。

    这里是示例数据:

    H string
    H string
    H string
    SCAN 00001 00001
    I string
    I string
    432.203 194090 0
    221.332 983451 0
    SCAN 00002 00002
    H string
    H string
    H string
    SCAN 00001 00003
    I string
    I string
    521.193 182233 0
    522.103 171211 0
    SCAN 00004 00004
    

    这是脚本:

    #!/usr/bin/perl -w
    use strict;
    
    
    # Store information about scans in the form of hash of hashes
    my %scans=();
    
    # The current scan number
    my $scannumber="";
    
    while (my $line=<>) {
    
       chomp($line);
       #print "Current Line: $line\n";
    
       if ($line=~m/^SCAN (\d+) (\g1)/) {
          $scannumber="$1";
          #print "New Scan: $scannumber\n";
       }
       elsif ($line=~m/^(\d+.\d+) (\d+)/) {
          my ($key,$val)=("$1","$2");
          #print "$key : $val\n";
          $scans{$scannumber}{$key}=$val;
       }
    
    }
    
    
    ## You are ready to print the hash of hashes now
    #
    for my $scannumber (sort keys %scans) {
    
       for my $key (sort keys %{$scans{$scannumber}}) {
    
          my $val=$scans{$scannumber}{$key};
          print "$scannumber : $key : $val\n";
       }
    }
    
    
    ## You could also print the hash of hashes like this
    #
    use Data::Dumper;
    
    $Data::Dumper::Terse = 1;
    $Data::Dumper::Indent = 2;
    
    print "\n\n";
    print Dumper(\%scans);
    

    脚本运行示例:

    ~> cat data1 | ./script.pl
    00001 : 221.332 : 983451
    00001 : 432.203 : 194090
    00002 : 521.193 : 182233
    00002 : 522.103 : 171211
    
    
    {
      '00002' => {
                   '522.103' => '171211',
                   '521.193' => '182233'
                 },
      '00001' => {
                   '221.332' => '983451',
                   '432.203' => '194090'
                 }
    }
    

    【讨论】:

    • 输出需要是两个数组,因为我需要保存两个值的顺序,所以两个散列扫描作为键和数组作为值或多维,其中我将两个数组附加到同一个散列。文件也很长(或多或少 51000 次扫描),它们之间有几千行(不同的长度),所以我需要能够动态地捕捉所有数字但保持它们之间的顺序
    • @D.A.,我添加了另一个答案,该答案保留了每个扫描编号内的扫描线顺序。我保留了第一个答案,以便您能够选择最适合您需求的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多