2012-02-02 3 views
3

Пожалуйста, рассмотрите сценарий ниже, я хочу, чтобы соответствовать $ b до $ a, даже если $ b является частичным совпадением. Можно ли это сделать?Perl частичное совпадение

$a="MCF-7"; 
$b="MCF"; 
if($b=~m/$a/i) 
{ 
    print "FOUND"; 
} 
+4

Не можете ли вы просто изменить смысл? 'print" FOUND ", если $ a = ~/$ b/i;'? – unpythonic

ответ

8

Хотя регулярные выражения могут сделать это, это звучит как ваша проблема также может быть решена с помощью функции index:

say index($haystack, $needle) >= 0 ? 'match' : 'fail'; # any position 
say index($haystack, $needle) == 0 ? 'match' : 'fail'; # anchored at start 

index функция чувствительна к регистру. Если вы хотите нечувствительное соответствие, примените функцию uc или lc к обоим аргументам.

Хотя функция index будет намного быстрее, чем регулярное выражение, если вы хотите использовать регулярное выражение, вы можете создать генератор регулярных выражений, который производит череду чередования, которые будут выполнять частичное совпадение.

sub build_partial { 
    my ($str, $min) = (@_, 1); 
    my @re; 
    for (0 .. length($str) - $min) { 
     my $str = substr $str, $_; 
     for ($min .. length $str) { 
      push @re, quotemeta substr $str, 0, $_ 
     } 
    } 
    my $re = join '|' => sort {length $a <=> length $b} @re; 
    qr/^(?:$re)$/i 
} 

my $haystack = 'MCF-7'; 
my $needle = 'MCF'; 

my $regex = build_partial $haystack; 

say $needle =~ /$regex/ ? 'match' : 'fail'; # match 

Регулярное выражение Генерация MCF-7 выглядит следующим образом:

/^(?:M|C|F|7|MC|CF|\-|MCF|F\-|\-7|CF\-|F\-7|MCF\-|CF\-7|MCF\-7)$/i 

И это будет соответствовать, даже если игла один символ из стога. build_partial принимает необязательный номер, указывающий на минимальную длину, необходимую для матча:

my $regex_3 = build_partial $haystack, 3; 

который производит это регулярное выражение:

/^(?:MCF|CF\-|F\-7|MCF\-|CF\-7|MCF\-7)$/i 

Эти модели соответствовать подстроку, начиная с любой позиции. Если вы хотите, чтобы он был привязан к передней части струны, build_partial становится немного проще:

sub build_partial { 
    my ($str, $min) = (@_, 1); 

    my $re = join '|' => map { 
     quotemeta substr $str, 0, $_ 
    } $min .. length $str; 

    qr/^(?:$re)$/i 
} 
+0

Мне нравится подход, хотя мне интересно, почему вы используете 'join '|' => 'вместо' join '|' '. – flesk

+0

@flesk => только личное предпочтение кодирования. Я склонен использовать жирную стрелу в любое время, когда она привлекает полезную связь между аргументами. поэтому 'join '' => @ list', но не' push @array => @ list', так как это обратное –

7

Вы, кажется, $a и $b смешались:

use strict; 
use warnings; 
my $a="MCF-7"; 
my $b="MCF"; 
if($a=~/$b/i) #tests for case-insensitive matching of $b within $a. 
{ 
print "Found\n"; 
} 

код в вашем вопросе не произвел никакого вывода, так как нет матча "MCF-7" в "MCF".

Смежные вопросы