使用perl在括号内使用正则表达式连字符时出错

时间:2013-09-20 22:16:11

标签: regex perl hyphen

我有这个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。希望澄清一下。

1 个答案:

答案 0 :(得分:2)

您的问题描述了集合交集,即covered in the Perl FAQ

  

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

     

使用哈希。这是两个以上的代码。它假定每个   element在给定数组中是唯一的:

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中,但两者都不是。把它想象成一个xor操作。

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

将公共代码分解出来以查找数据文件中的名称。该子假设

  • 每个[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的名称以及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{$_};
  }
}