正则表达式,匹配运算符使用Perl中的字符串变量

时间:2014-06-16 22:22:21

标签: regex perl string-matching

我正在使用regex,但我得到一些奇怪的,意外的"匹配"。 "名称"被发送到子程序以与名为@ASlist的数组进行比较,该数组包含多行。每行的第一个元素也是一个名称,后跟0到几个同义词。目标是匹配传入的"名称"到@ASlist中具有匹配单元格的任何行。

示例输入,从中导出$names以与@ASlist进行比较:

13  1   13  chr7    7   70606019    74345818    Otud7a  Klf13   E030018B13Rik   Trpm1   Mir211  Mtmr10  Fan1    Mphosph10   Mcee    Apba2   Fam189a1    Ndnl2   Tjp1    Tarsl2  Tm2d3   1810008I18Rik   Pcsk6   Snrpa1  H47 Chsy1   Lrrk1   Aldh1a3 Asb7    Lins    Lass3   Adamts17

来自@ASlist的样本行:

HSPA5   BIP FLJ26106    GRP78   MIF2        
NDUFA5  B13 CI-13KD-B   DKFZp781K1356   FLJ12147    NUFM    UQOR13
ACAN    AGC1    AGCAN   CSPG1   CSPGCP  MSK16   SEDK

代码:

my ($name) = @_;  ## this comes in from another loop elsewhere in code I did not include
chomp $name;

my @collectmatches = (); ## container to collect matches

foreach my $ASline ( @ASlist ){

    my @synonyms = split("\t", $ASline );

    for ( my $i = 0; $i < scalar @synonyms; $i++ ){
         chomp $synonyms[ $i ];
         #print "COMPARE $name TO $synonyms[ $i ]\n";

         if ( $name =~m/$synonyms[$i]/ ){
              print "\tname $name from block matches\n\t$synonyms[0]\n\tvia $synonyms[$i] from AS list\n";
              push ( @collectmatches, $synonyms[0], $synonyms[$i] ); 
          }
         else {
              # print "$name does not match $synonyms[$i]\n"; 
         }
    }
}

该脚本正在运行,但也会报告奇怪的匹配。例如,当$name是&#34; E030018B13Rik&#34;它匹配&#34; NDUFA5&#34;当它发生在@ASlist时。这两个不应该匹配。

如果我将正则表达式从~m/$synonyms[$i]/更改为~m/^$synonyms[$i]$/,那么&#34;怪异的&#34;比赛消失,但剧本错过绝大多数比赛。

4 个答案:

答案 0 :(得分:1)

NDUFA5条记录包含B13作为模式,与E030018<B13>Rik匹配。

如果您想更加文字,请将边界条件添加到正则表达式/\b...\b/。也应该使用quotemeta来转义正则表达式特殊字符。

if ( $name =~ m/\b\Q$synonyms[$i]\E\b/ ) {

或者,如果您想测试直接相等,那么只需使用eq

if ( $name eq $synonyms[$i] ) {

答案 1 :(得分:1)

测试字符串相等性的另一种更多Perlish方法是使用散列。

您没有显示任何真实的测试数据,但是这个简短的Perl程序会根据匹配字符串行的数组@ASlist构建一个哈希值。之后,大部分工作都已完成。

后续的for循环仅测试E030018B13Rik以查看它是否是新%ASlist的键之一并打印相应的消息

use strict;
use warnings;

my @ASlist = (
    'HSPA5   BIP FLJ26106    GRP78   MIF2',
    'NDUFA5  B13 CI-13KD-B   DKFZp781K1356   FLJ12147    NUFM    UQOR13',
    'ACAN    AGC1    AGCAN   CSPG1   CSPGCP  MSK16   SEDK',
);

my %ASlist = map { $_ => 1 } map /\S+/g, @ASlist;

for (qw/ E030018B13Rik /) {
  printf "%s %s\n", $_, $ASlist{$_} ? 'matches' : 'doesn\'t match';
}

<强>输出

E030018B13Rik doesn't match

答案 2 :(得分:0)

您使用B13作为正则表达式。由于没有任何字符具有特殊含义,因此包含子字符串B13的任何字符串都与表达式匹配。

E030018B13Rik
       ^^^

如果希望表达式与整个字符串匹配,请使用锚点:

if ($name =~m/^$synonyms[$i]$/) {

或者,使用indexeq来检测子串(或分别为相同的字符串),因为您的输入似乎不使用正则表达式的任何功能。

答案 3 :(得分:0)

由于您只需要比较两个字符串,您只需使用eq:

即可
if ( $name eq $synonyms[$i] ){