Perl:匹配数组元素,然后将上一个(后面 5 个索引)数组元素复制到新数组

问题描述 投票:0回答:4

本质上,我想做的是搜索一个大文本文件,以识别每个显示“未找到命中”的元素,并将匹配标识符的复制到新列表中。我对第一部分很满意,但我似乎不明白如何将数组的元素复制回恰好 5 个索引(这是一个标识符)并将其复制到另一个数组。

我尝试过这样的事情,

$fastafile = 'HpHcTEST.txt';
open(FASTAFILE, $fastafile);
@seq = <FASTAFILE>;
my $fastaid;
foreach (@seq) {
    if ($_ =~ /\*\*\*\*\* No hits found \*\*\*\*\*/){
        $fastaid .= $_[-5];
    }
}

print "here are the IDs\n";
print $fastaid;

有大量的 [-5] 变体,但它们都不起作用。我似乎找不到任何有关如何在满足匹配时反向引用并获取前一个元素的文档。 有人知道如何为此编码吗?

非常感谢您的宝贵时间。

安德鲁

regex perl bioinformatics fasta regular-language
4个回答
3
投票

快速修复

一种方法是带着索引走过

@seq

my @fastaid;

for (my $i = 0; $i < @seq; ++$i) {
    if ($seq[$i] =~ /\*\*\*\*\* No hits found \*\*\*\*\*/){
        push @fastaid, $seq[$i - 5] if $i >= 5;
    }
}

请注意从标量到名为

@fastaid
的数组的更改,您可以使用

进行打印
print "Here are the IDs:\n";
print "  - $_\n" for @fastaid;

甚至

print "Here are the IDs:\n",
      map "  - $_\n", @fastaid;

添加抛光剂

正如

brian d foy
在下面的评论中指出的那样,代码可以更优雅,更直接地表达意图。

my $id_offset = 5;
my @fastaid;

for ($id_offset .. $#seq) {
    if ($seq[$_] =~ /\*\*\*\*\* No hits found \*\*\*\*\*/){
        push @fastaid, $seq[$_ - $id_offset];
    }
}

如 perldata 的“标量值”部分中记录的

$#seq
@seq
中最后一个元素的索引。
..
范围运算符
正确处理
@seq
长度小于
$id_offset
个元素的情况。

显式的正则表达式绑定运算符仍然有点不太好。你可以一起去

my $id_offset = 5;
my @fastaid;

for my $i ($id_offset .. $#seq) {
  for ($seq[$i]) {
    push @fastaid, $seq[$i - $id_offset]
      if /\*\*\*\*\* No hits found \*\*\*\*\*/;
  }
}

或者您的版本至少为 5.10

use feature 'switch';

# ...

my $id_offset = 5;
my @fastaid;

for my $i ($id_offset .. $#seq) {
  given ($seq[$i]) {
    when (/\*\*\*\*\* No hits found \*\*\*\*\*/) {
      push @fastaid, $seq[$i - $id_offset];
    }
  }
}

历史记录

当时,有人讨论重新利用

$#
来跟踪数组遍历的索引,这样你就可以写

for (@fastaid) {
    if (/\*\*\*\*\* No hits found \*\*\*\*\*/) {
        push @fastaid, $seq[$# - 5] if $# >= 5;
    }
}

但这从未实现。


3
投票

您可以迭代索引和下标来获取数组元素:

for (5..$#seq) {
    $fastaid .= $seq[$_-5] if $seq[$_] =~ /your_regex/;
}

在 Perl 5.12 或更高版本中,您还可以使用

each
:

while (my ($index, $value) = each @seq) {
    next if $index < 5;
    $fastaid .= $seq[$index-5] if $value =~ /your_regex/;
}

2
投票
my @fasta_id = map { $seq[$_] =~ /your_regex/ ? $seq[$_-5] : () } 5 .. $#seq;

-2
投票

使用“for”循环代替“foreach”,

for ($index=0; $index < $#seq + 1; $index++) {
    if ($seq[$index] =~ /\*\*\*\*\* No hits found \*\*\*\*\*/){
        $fastaid .= $seq[$index-5];
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.