使用Perl时,括号内的正则表达式连字符用法出错

42fyovps  于 2022-11-15  发布在  Perl
关注(0)|答案(1)|浏览(123)

我有一个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中的两个不同的列表。然后比较list中一个元素的[]和另一个元素的[]之间的名称。所有这些结果都被推送到@shared中。希望这能澄清一些问题。

yfwxisqw

yfwxisqw1#

您的问题描述了一个 * 集合交集 *,Perl常见问题解答中介绍了该问题。

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

使用散列。下面的代码可以同时执行这两个操作,还可以执行更多操作。它假定给定数组中的每个元素都是唯一的:

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中来自cyt.dat的名称,以及nuc.dat%nuc的名称,这里的代码迭代两个哈希值的键,并递增%shared中对应的键。

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

此时,%shared表示cyt.datnuc.dat中的名称的 * 集合并集 。也就是说,%shared包含来自%cyt%nuc的所有键。为了计算集合差,我们观察到%shared中存在于两个输入中的键的值必须大于1。
下面的最后一遍按排序顺序迭代键(因为散列键在内部是按未定义的顺序存储的)。对于真正共享的键(
即 *,那些值大于1的键),代码打印它们并删除其余的键。

for (sort keys %shared) {
  if ($shared{$_} > 1) {
    print $_, "\n";
  }
  else {
    delete $shared{$_};
  }
}

相关问题