Re^2: qr// and user provided regex patterns...
by misterMatt (Novice) on Jul 30, 2009 at 06:57 UTC
|
Okay, I decided to go the eval route. Because as you pointed out - I'm only using the match operator - which I thought was a regex pattern (I'm really still not clear on the difference.)
anyway, I'm also going that route because as another monk pointed out - the use of qr// messes with the user pattern that's already wrapped in //. (the interpolation issue)
right now I'm looking at this:
if($options{c}){
#variable grab
my $pattern = eval "qr$options{c}" or die $@;
print "Please enter the text you wish to run the pattern on: ";
my $text = <STDIN>;
chomp $text;
if($text =~ $pattern){
print $&; #prints entire match
print " " . $text;
}
else{
print "$pattern on $text Failed. ";
}
}
It works, as long as what the user provides doesn't have any spaces in it. (ex: /Bill Clinton/i causes the program to fail, but /BillClinton/i doesn't.) How do I fix that?
| [reply] [d/l] |
|
I'm really still not clear on the difference.
A multiplier tells the multiplication operator by how much it should multiply. The multiplier is data, the operator is Perl code.
A regex pattern tells the match operator what it should be match. The pattern is data to Perl, the operator is Perl code.
You don't expect $c = '4 * 5'; 3 + $c to execute the contents of $c, so why would you expect differently from $c = '/foo/'; $x =~ $c?
It works, as long as what the user provides doesn't have any spaces in it. (ex: /Bill Clinton/i causes the program to fail, but /BillClinton/i doesn't.) How do I fix that?
I'm guessing the problem is that the user did NOT provide an argument with spaces in it, but rather passed two arguments. Quote the argument appropriately for your shell.
| [reply] [d/l] [select] |
|
Wrapping the argument in quotes solved it - good catch.
Thanks.
| [reply] |
Re^2: qr// and user provided regex patterns...
by misterMatt (Novice) on Aug 02, 2009 at 07:33 UTC
|
Okay, I've managed to get this to work perfectly with a regular match (//) - but when I try to do a substitution(s///), the pattern fails to match anything - and no substitution is done.
I'm calling the program like this: -r "s/matt/matthew/" -i -g, with the text 'matt, Matt'.
Here is the code that processes the substitution bit:
if($options{r}){
#variable grab, add flags to pattern if they exist.
my $pattern = $options{r};
$pattern .= 'g' if $options{g};
$pattern .= 'i' if $options{i};
$pattern .= 's' if $options{s};
#compile that stuff with eval
my $compd_pattern = eval "qr($pattern)" or die $@;
print "Please enter the text you wish to run the pattern on: ";
my $text = <STDIN>;
chomp $text;
#do work and display
if($text =~ $compd_pattern){
print $text;
}
else{
print "$pattern on \n\t{$text} Failed. ";
}
} #end R FLAG
| [reply] [d/l] |
|
As toolic points out, qr// is meant to quote a pattern, not an entire substitution. If you want to pass in literal substitutions, rather than just patterns, then just eval at a different point:
eval "\$text =~ $pattern";
By the way, ikegami suggested using (?i:) in place of a string-based eval. Since such evals are always a cause for concern, and should be a cause for terror when run on user-provided input, are you sure that you considered the alternative properly before making your decision?
If you're not happy with the inability of a (?i:)-type solution to handle substitutions, then you can probably just offer --search and --replace --by flags so that the user can specify directly what he or she wants. | [reply] [d/l] [select] |
|
-
It makes no sense to let the user specify /g for a match. You can't even use it on qr// because it makes no sense. ixsm are the four modifiers that apply to the pattern as opposed to the operator.
-
The followign doesn't make much sense:
my $compd_pattern = eval "qr($pattern)" or die $@;
It removes the ability of qr// to quote, which is what you want. The code should be
my $compd_pattern = qr($pattern);
-
You say you have problems doing substitutions, but you didn't show us your attempt (despite your claim). You should have no problems using a qr// pattern in a substitution.
my $pat = ...;
my $repl = ...;
my $mods = '';
$mods .= 'i' if ...;
$mods .= 's' if ...;
$mods .= 'm' if ...;
$mods .= 'x' if ...;
my $re = qr/(?$mods:$pat)/;
if (...) {
s/$re/$repl/g;
} else {
s/$re/$repl/;
}
| [reply] [d/l] [select] |
|
You say you have problems doing substitutions, but you didn't show us your attempt (despite your claim). You should have no problems using a qr// pattern in a substitution.
I think that misterMatt's problem was that he was trying to stuff a substitution into a qr//, like:
my $substitution = 's/out/in/';
my $pattern = qr/$substitution/;
which, naturally, doesn't work (well, doesn't cause a substitution, anyway). | [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
so I pretty much will have to split it and evaluate it like this: eval("$text =~ s/$pa/$tx/$md");
It might be difficult splitting a regex that could contain multiple /'s. I'll have to adjust the program so the user enters the pattern, and replacement separately I guess.
| [reply] |
Re^2: qr// and user provided regex patterns...
by misterMatt (Novice) on Jul 31, 2009 at 19:58 UTC
|
Using the eval works great for matches : $pattern = eval "qr$pattern" or die $@;
But of course, when I do a 'substitution pattern' s///, it fails because it looks like eval "qrs/stuff/morestuff/.
So I tried adding a bang, to wrap around the interpolated variable in the original : $pattern = eval "qr!$pattern!" or die $@;
But now my patterns fail to match anything. Example: s/Bill Clinton/The ex-President/gi on Bill Clinton is the ex-President
+. bill clinton. results in Failure.
| [reply] [d/l] [select] |
|
Using the eval works great for matches : $pattern = eval "qr$pattern" or die $@;
No, it doesn't.
First of all, it doesn't work at all if $pattern actually contains a pattern.
And then there are issues with improper escaping. If you pass /a\+/, it won't match "a" followed by "+" as desired.
| [reply] [d/l] [select] |