从字符串中解析文本

时间:2013-11-04 07:29:14

标签: perl parsing string-parsing

我有一个制表符分隔的文件1:

  20    50  80  110
  520   590 700 770
  410   440 20  50
  300   340 410 440

读取并将它们放入数组中:

while(<INPUT>)
{
    chomp;
    push @inputarray, $_;
}

现在我正在循环浏览另一个文件2:

  20, 410, 700
  80, 520
  300

file2中每行的foreach编号,我想在@inputarray中搜索该编号。如果它存在,我想获取后面的相应数字。例如,对于数字20,我想要获取数字50.我假设它们仍然被字符串中的一个标签分隔,该标签在@inputarray中作为数组元素存在。

while(my $line = <INPUT2>) 
{
  chomp $line;
  my @linearray = split("\t", $line);
  foreach my $start (@linearray)
  {
    if (grep ($start, @inputarray))
    {
       #want to grab the corresponding number
    }
  }
}

一旦grep找到它,我不知道如何获取该数组元素以找到数字的位置以使用substr函数提取相应的数字。我如何获取grep找到的数组元素?

所需的输出是:

line1:
20 50
410 440
700 770

line2:
80 110
520 590

line3:
300 340

3 个答案:

答案 0 :(得分:2)

恕我直言,最好将文件1中的数字存储在哈希中。参考上面提供的file1的示例clontent,您可以使用下面的内容

{
   '20' => '50',
   '80' => '110',
   '520'=> '590',
   '700'=> '770',
   '410'=> '440',
   '20' => '50',
   '300'=> '340',
   '410' => '440'
}

示例代码就像

my %inputarray;
while(<INPUT>)
{
    my @numbers = split $_;
    my $length = scalar $numbers;
    # For $i = 0 to $i < $length;
    # $inputarray{$numbers[$i]} = $numbers[$i+1];
    # $i+=2;
}

上述循环的演示

index:    0     1   2    3
numbers: 20    50  80  110

first iteration: $i=0
     $inputarray{$numbers[0]} = $numbers[1];
     $i = 2; #$i += 2;
second iteration: $i=2
     $inputarray{$numbers[2]} = $numbers[3];

然后在解析file2时,您只需要将该数字视为key的{​​{1}}。

答案 1 :(得分:1)

我相信这会让你接近你想要的东西。

#!/usr/bin/perl -w

my %follows;

open my $file1, "<", $ARGV[0] or die "could not open $ARGV[0]: $!\n";

while (<$file1>)
{
    chomp;

    my $prev = undef;

    foreach my $curr ( split /\s+/ )
    {
        $follows{$prev} = $curr if ($prev);
        $prev = $curr;
    }
}

close $file1;

open my $file2, "<", $ARGV[1] or die "could not open $ARGV[1]: $!\n";
my $lineno = 1;

while (<$file2>)
{
    chomp;
    print "line $lineno\n";
    $lineno++;

    foreach my $val ( split /,\s+/, $_ )
    {
        print $val, " ", ($follows{$val} // "no match"), "\n";
    }
    print "\n";
}

如果你只想考虑file1的数字,而不是考虑哪些数字跟随其他数字而不考虑对边界,那么你需要改变逻辑在第一个while循环中。

#!/usr/bin/perl -w

my %follows;

open my $file1, "<", $ARGV[0] or die "could not open $ARGV[0]: $!\n";

while (<$file1>)
{
    chomp;

    my $line = $_;

    while ( $line =~ s/(\S+)\s+(\S+)\s*// )
    {
        $follows{$1} = $2;
    }
}

close $file1;

open my $file2, "<", $ARGV[1] or die "could not open $ARGV[1]: $!\n";
my $lineno = 1;

while (<$file2>)
{
    chomp;
    print "line $lineno\n";
    $lineno++;

    foreach my $val ( split /,\s+/, $_ )
    {
        print $val, " ", ($follows{$val} // "no match"), "\n";
    }
    print "\n";
}

答案 2 :(得分:0)

如果您想要读取输入一次但是要检查数字,那么最好将split输入行转换为单个数字。然后将每个数字作为键添加到哈希中,并使用以下数字作为值。这使得阅读速度变慢并且需要更多内存,但是由于exist和哈希的性质,第二部分,您要检查以下数字将是轻而易举的。

如果我理解你的问题是正确的,你可以只使用一个大哈希。当然,假设每个数字后面都跟着相同的数字。

相关问题