Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl how to pass in a regular expression to my subroutine like grep

print grep /test/, "mytestphrase";

With the grep syntax you can pass in a regular expression without quotes. I want the same behavior for my subroutine as follows:

use strict; 
use warnings;

sub testsub {
    my $regex = shift;
    my $phrase = shift;

    print grep $regex, $phrase;
}

testsub /test/, "mytestphrase";

However it tries before the testsub call to evaluate $_ against my regex, issuing following error:

Use of uninitialized value $_ in pattern match (m//) at ./a.pl line 14.

Is it possible to call testsub like the grep command and how must the subroutine be modified to support that?

like image 931
user2050516 Avatar asked Oct 26 '25 10:10

user2050516


2 Answers

Pass the parameter like this:

testsub qr/test/, "mytestphrase";

Change also the utilisation of $regex to /$regex/:

#!/usr/bin/perl

use strict; 
use warnings;

sub testsub {
    my $regex = shift;
    my $phrase = shift;
    print grep /$regex/, $phrase;
}

testsub qr/test/, "mytestphrase";
like image 176
Toto Avatar answered Oct 29 '25 05:10

Toto


AFAIK there is no way to replicate grep's special "take a block OR take a bare expression" syntax. As pointed out in TLP's answer, you can use the &@ prototype to get the foo {...} LIST syntax, but you can't ask for a block OR a scalar.

There is also no prototype to get a bare regular expression. You must pass in a compiled regular expression, a qr/.../, as noted by M42.

Prototypes are incomplete. They cannot express the full range of Perl's built in functions. open, split, print and even apparently simple ones like chomp. You can check this by asking for print prototype 'CORE::some_function'. Some say this is a weakness in prototypes. Some say this is a madness in Perl's built in functions.

Prototypes should only be used when you are replacing built in functions. They are really best avoided. One of the few valid idioms is to use the &@ prototype to provide the foo {...} LIST idiom for list processing.

I would recommend you pass in qr// or sub { ... } to your function normally and pass it along to grep.

Did I say there's no way to do it? What was I thinking, this is Perl! If you REALLY REALLY REALLY want this feature, you can delve into Devel::Declare. This module lets you come up with your own function call syntax. To say it is not easy to use is an understatement. Things like Method::Signatures and TryCatch use it to work their magic. If you're at the level of just figuring out qr//, I would recommend against bringing Devel::Declare into production code. Mess around with it, though.

like image 40
Schwern Avatar answered Oct 29 '25 05:10

Schwern