【问题标题】:Parsing out text from string从字符串中解析出文本
【发布时间】:2013-11-04 07:29:14
【问题描述】:

我有一个制表符分隔的文件 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

foreach 文件2 中每一行的编号,我想在@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

【问题讨论】:

  • file2 是否可能包含 file1 第二列的数字?例如 50,440,110 等等?
  • File2 仅包含出现在 file1 的第 2 列和第 4 列中的数字。
  • @user2674514:您的示例显示 file2 包含 20, 410, 700,即 file1 的 column1 中的数字。 column 2 and 4 是您上一条评论中的错字吗?

标签: perl parsing string-parsing


【解决方案1】:

恕我直言,最好将 file1 中的数字存储在哈希中。参考您在上面提供的 file1 的示例克隆,您可以得到如下所示的内容

{
   '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时,只需将数字视为%inputarray的key即可。

【讨论】:

  • $i+=1 如果 file2 可以包含任何数字。您可能应该检查@numbers 是否有$ith 元素。
  • @DeVadder: 不应该是$i += 2,因为对于每次迭代,$i(key) 和 $i+1(value) 都用于%inpurarray。所以在下一次迭代中,它需要从$i+2 开始。我错过了您想指出的内容吗?
  • 谢谢 DeVadder 和 Samiron。我认为将第一个文件放入哈希中并在其键中搜索值是正确的想法。
  • @Samiron:是的,但我确实错过了他说他只需要每隔一个条目。我认为每个数字都必须是键和值,因为我假设每个数字都可以查找。
  • @user2674514 欢迎来到 SO!您可能想尽快访问about 页面。如果任何答案对您有用,请考虑通过单击答案左上方的空心绿色刻度线来接受它(在上下投票下方)
【解决方案2】:

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

#!/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";
}

如果您只想在 pairs 中考虑来自 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";
}

【讨论】:

  • 请注意,上面的两个脚本都会产生与您的测试数据相匹配的输出。您必须提出更全面的测试来确定哪个脚本满足您的需求。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 2023-01-31
    相关资源
    最近更新 更多