简体   繁体   中英

How to use Regular expression in perl if both regular expression and strings are variables

I have two variables coming from some user inputs. One is a string that needs to be checked and other one is a regular expression as below.

Following code doesn't work.

my $pattern = "/^current.*$/";
my $name = "currentStateVector";

if($name =~ $pattern) {
    print "matches \n";
} else {
    print "doesn't match \n";
}

And following does.

if($name =~ /^current.*$/) {
    print "matches \n";
} else {
    print "doesn't match \n";
}

What's the reason for this. I've the regular expression stored in a variable. Is there another way to store this variable or modify it?

The double-quotes that you use interpolate -- they first evaluate what's inside them (variables, escapes, etc) and return a string built with evaluations' results and remaining literals. See Gory details of parsing quoting constructs for an illuminating discussion, with lots of detail.

And your example string happens to have a $/ there, which is one of Perl's global variables (see perlvar ) so $pattern is different than expected; print it to see. (In this case the / is erroneous as discussed below but the point stands.)

Instead, either use single quotes to avoid interpretation of characters like $ and \ (etc) so that they are used in regex as such

my $pattern = q(^current.*$);

or, better, use the regex-specific qr operator

my $pattern = qr/^current.*$/;

which builds from its string a proper regex pattern (a special type of Perl value), and allows use of modifiers. In this case you need to escape characters that have a special meaning in regex if you want them to be treated as literals.

Note that there's no need for // for the regex, and they wouldn't be a part of the pattern anyway -- having them around the actual pattern is wrong.

Also, carefully consider all circumstances under which user input may end up being used.


It is brought up in a comment that users may submit a "pattern" with extra / 's. That'd be wrong, as mentioned above; only the pattern itself should be given (surrounded on the command-line by ' , so that the shell doesn't interpret particular characters in it). More detail follows.

The / 's are clearly not meant as a part of the pattern, but are rather intended to come with the match operator, to delimit (quote) the regex pattern itself (in the larger expression) so that one can use string literals in the pattern. Or they are used for clarity, and/or to be able to specify global modifiers (even though those can be specified inside patterns as well).

But then if users still type them around the pattern the regex will use those characters as a part of the pattern and will try to match a leading / , etc; it will fail, quietly. Make sure that users know that they need to give a pattern alone, with no delimiters.

If this is likely to be a problem I'd check for delimiters and if found carry on with a "loud" (clear) warning. What makes this tricky is the fact that a pattern starting and ending with a slash is legitimate -- it is possible, if somewhat unlikely, that a user may want actual / 's in their pattern . So you can only ask, or raise a warning, not abort.

Note that with a pattern given in a variable, or with an expression yielding a pattern at runtime, the explicit match operator and delimiters aren't needed for matching; the variable or the expression's return is taken as a search pattern and used for matching. See The basics (perlre) and Binding Operators (perlop) .

So you can do simply $name =~ $pattern . Of course $name =~ /$pattern/ is fine as well, where you can then give global modifiers after the closing /

The slashes are part of the matching operator m// , not part of the regex.

When I populate the regex from user input

my $pattern = shift;

and run the script as

58663971.pl '^current.*$'

it matches.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM