0

我有这个 perl 脚本,它比较两个数组,将它们中的结果返回给我。问题出现了,我相信正则表达式,它在括号 [] 内遇到连字符 (-)。

我收到以下错误:

Invalid [] range "5-3" in regex; marked by <-- HERE in m/>gi|403163623|ref|XP_003323683.2| leucyl-tRNA synthetase [Puccinia graminis f. sp. tritici CRL 75-3 <-- HERE 6-700-3]
MAQSTPSSIQELMDKKQKEATLDMGGNFTKRDDLIRYEKEAQEKWANSNIFQTDSPYIENPELKDLSGEE
LREKYPKFFGTFPYPYMNGSLHLGHAFTISKIEFAVGFERMRGRRALFPVGWHATGMPIKSASDKIIREL
EQFGQDLSKFDSQSNPMIETNEDKSATEPTTASESQDKSKAKKGKIQAKSTGLQYQFQIMESIGVSRTDI
PKFADPQYWLQYFPPIAKNDLNAFGARVDWRRSFITTDINPYYDAFVRWQMNRLKEKGYVKFGERYTIYS
PKDGQPCMDHDRSSGERLGSQEYTCLKMKVLEWGPQAGDLAAKLGGKDVFFV at comparer line 21, <NUC> chunk 168.

我认为只需添加\Q..\E正则表达式以绕过 [] 即可解决该错误,但这并没有奏效。这是我的代码,提前感谢您提供的任何和所有帮助。

@cyt = <CYT>;
@nuc = <NUC>;

$cyt = join ('',@cyt);
$cyt =~ /\[([^\]]+)\]/g;

@shared = '';

foreach $nuc (@nuc) {
    if ($cyt =~ $nuc) {
        push @shared, $nuc;     
    }
}

print @shared;

我试图用这段代码实现的是比较加载到数组@cyt 和@nuc 中的两个不同列表。然后,我将列表中一个元素的 [] 之间的名称与另一个元素的 [] 中的名称进行比较。然后将所有这些发现推送到@shared。希望能澄清一点。

4

1 回答 1

2

您的问题描述了一个集合交集,这在 Perl FAQ 中有介绍

如何计算两个数组的差异?如何计算两个数组的交集?

使用哈希。这是可以同时执行更多操作的代码。它假设每个元素在给定数组中都是唯一的:

my (@union, @intersection, @difference);
my %count = ();
foreach my $element (@array1, @array2) { $count{$element}++ }
foreach my $element (keys %count) {
  push @union, $element;
  push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
}

请注意,这是对称差异,即 A 或 B 中的所有元素,而不是两者中的所有元素。把它想象成一个异或操作。

将其应用于您的问题会给出以下代码。

分解出通用代码以查找数据文件中的名称。这个子假设

  • 每个 [name] 都将完全包含在给定的行内,而不是跨越换行符边界
  • 每行输入最多包含一个 [name]

如果这些假设无效,请提供更具代表性的输入样本。

请注意使用/x正则表达式开关,它告诉正则表达式解析器忽略模式中的大多数空白。在下面的代码中,这允许在作为分隔符的括号和捕获名称的字符类周围的括号之间进行视觉分离。

sub extract_names {
  my($fh) = @_;

  my %name;
  while (<$fh>) {
    ++$name{$1} if /\[   ([^\]]+)   \]/x;
  }

  %name;
}

您的问题使用老式的 typeglob 文件句柄。请注意,参数extract_names期望是一个文件句柄。方便的参数传递是间接文件句柄的众多好处之一,例如下面创建的那些。

open my $cyt, "<", "cyt.dat" or die "$0: open: $!";
open my $nuc, "<", "nuc.dat" or die "$0: open: $!";

my %cyt = extract_names $cyt;
my %nuc = extract_names $nuc;

使用cyt.dat散列中的名称%cyt以及 fornuc.dat中的名称%nuc,此处的代码迭代两个散列的键并递增 中的相应键%shared

my %shared;
for (keys %cyt, keys %nuc) {
  ++$shared{$_};
}

此时,%shared表示和 中名称的集合并cyt.datnuc.dat。也就是说,%shared包含来自%cyt或的所有键%nuc。为了计算集合差异,我们观察到%shared两个输入中存在的键的值必须大于 1。

下面的最后一遍以排序顺序遍历键(因为哈希键在内部以未定义的顺序存储)。对于真正共享的密钥(值大于一的密钥),代码会打印它们并删除其余的。

for (sort keys %shared) {
  if ($shared{$_} > 1) {
    print $_, "\n";
  }
  else {
    delete $shared{$_};
  }
}
于 2013-09-20T23:55:52.610 回答