Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl partial match

Tags:

perl

Please consider the script below, I want to match $b to $a even if $b is a partial match. Can this done be done?

$a="MCF-7";
$b="MCF";
if($b=~m/$a/i)
{
    print "FOUND";
}
like image 613
Pink Avatar asked Dec 05 '22 18:12

Pink


1 Answers

While regular expressions can do this, it sounds like your problem could also be solved with the index function:

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

The index function is case sensitive. If you want an insensitive match, apply the uc or lc function to both arguments.

Although the index function will be much faster than a regex, if you do want a regex solution you can build a regex generator that produces a series of alternations that will perform partial matching.

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

The regex generated for MCF-7 looks like this:

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

And it will match even if the needle is a single character from the haystack. build_partial takes an optional number indicating the minimum length required for a match:

my $regex_3 = build_partial $haystack, 3;

which produces this regex:

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

These patterns match a substring starting from any position. If you want it anchored to the front of the string, build_partial gets a bit simpler:

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

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

    qr/^(?:$re)$/i
}
like image 67
Eric Strom Avatar answered Jan 02 '23 05:01

Eric Strom