jesuashok has asked for the
wisdom of the Perl Monks concerning the following question:
Hi Gr8 People
#!/usr/local/bin/perl
use strict;
+
my @array = ( 'account_trend','trend_report','revenuebytrafficker','ti
+cketstatus','lostinventory','campaigndetail','campaignsummary','packa
+gesummary','placementsummary','bookedbyaccount','bookedbysalesperson'
+,'accounttrends','salespersontrends','salessitetrend','placementperfo
+rmance','packageperformance','forcastsummary');
+
my $value = 'reve*ker';
+
foreach (@array) {
if ( grep (/$value/,$_) ) {
print "Matched :$_:\n";
}
}
+
In the above the how to acheive the following to be matched using grep
If $value = "accoun*end" then output should be
Matched :account_trend
Matched :accounttrends
"Keep pouring your ideas"
Re: how to add more intelligence to grep functionality by mrborisguy (Hermit) on Jan 11, 2006 at 19:06 UTC |
@new = grep /accoun.*end/, @array;
print "Matched :$_:\n" for @new;
Notice the .*. The period means any character, the asterisk means any amount of these. Compare that to accoun*end which mean "find 'accou', then any amount of n's, then 'end'."
-Bryan | [reply] [d/l] [select] |
Re: how to add more intelligence to grep functionality by japhy (Canon) on Jan 11, 2006 at 19:07 UTC |
What you mean to ask is, "How do I convert a glob-style regex to a Perl regex?" The Text::Glob module helps here.
| [reply] |
Re: how to add more intelligence to grep functionality by holli (Monsignor) on Jan 11, 2006 at 19:33 UTC |
#!/usr/local/bin/perl
use strict;
my @array = (
'account_trend',
'trend_report',
'revenuebytrafficker',
'ticketstatus',
'lostinventory',
'campaigndetail',
'campaignsummary',
'packagesummary',
'placementsummary',
'bookedbyaccount',
'bookedbysalesperson',
'accounttrends',
'salespersontrends',
'salessitetrend',
'placementperformance',
'packageperformance',
'forcastsummary'
);
my @values =
(
'??m*',
'reve*ker',
'accoun*end',
);
for ( @values )
{
print "mask: $_\n";
my $regex = mask2re ($_);
print "re $regex\n";
print join ("\n", grep { /$regex/ } @array), "\n\n";
}
#turns a simple mask into a regex where * means
#none ore more chars amd ? means exactly one char
sub mask2re
{
#replacements (after quotemeta)
my %map =
(
"\\*" => ".*?",
"\\?" => ".",
);
#quotema everything
my $re = quotemeta ($_[0]);
#replace * and ? by regex active statements
$re =~ s/(\\[\*|\?])/$map{$1}/g;
#return compiled regex
return qr/^$re/;
}
Output:
mask: ??m*
re (?-xism:^..m.*?)
campaigndetail
campaignsummary
mask: reve*ker
re (?-xism:^reve.*?ker)
revenuebytrafficker
mask: accoun*end
re (?-xism:^accoun.*?end)
account_trend
accounttrends
| [reply] [d/l] [select] |
Re: how to add more intelligence to grep functionality by GrandFather (Cardinal) on Jan 11, 2006 at 19:42 UTC |
You have your answer, but for future reference your node would have been better if you trimmed the number of items in the array to show just enough cases to make your problem clear, and if your question matched the actual example in the code.
As it stands most browsers will either break your nasty long line in a random place, or not break it at all meaning that a huge amount of scrolling is required to read your node and its replies. Even replying in such a case is a real pain in the butt because the edit box is extreamly wide.
Cleaned up (and fixed) code could look like this:
use strict;
use warnings;
my @array = ('account_trend', 'trend_report', 'revenuebytrafficker');
my $value = qr'reve.*ker';
foreach (@array) {
print "Matched :$_:\n" if /$value/;
}
Prints:
Matched :revenuebytrafficker:
It's not clear to me why you had a grep in there. A version using grep is:
use strict;
use warnings;
my @array = qw(trend_report revenuebytrafficker revengebysmoker);
my $value = qr'reve.*ker';
my @matches = grep {/$value/} @array;
print ("Matched :" . (join ": :", @matches) . ":\n") if @matches;
Prints:
Matched :revenuebytrafficker: :revengebysmoker:
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
GrandFather gave you an example of how to make your code work, but I think a reference is in order (no, not that kind).
Instead of my $value = 'reve*ker';, as in your original code, GrandFather changed it to my $value = qr'reve.*ker';. See that little qr in there? That's the quote regex operator. It takes a string, compiles it into a regex, and returns it for later use. To quote perlop,
This operator quotes (and possibly compiles) its STRING as a regular expression. STRING is interpolated the same way as PATTERN in m/PATTERN/. If "'" is used as the delimiter, no interpolation is done. Returns a Perl value which may be used instead of the corresponding /STRING/imosx expression.
perlop. Lots of good stuff in there.
HTH
BTW, I'd like to second GrandFather's comment about long lines. Horizontal scrolling is awkward.
| [reply] [d/l] [select] |
Re: how to add more intelligence to grep functionality by blazar (Canon) on Jan 12, 2006 at 11:28 UTC |
You already received a lot of replies. The common consensus seems to be that you just mistook shell patterns for regular expressions. It seems to me that no one has stressed enough that you seem to have a poor understanding of grep: it is made for grepping across lists, and indeed you can pass it a list of exactly one element - only, you generally just don't want to! So you either want:
my @matching elements=grep /$wahtever/, @array;
print $_, "\n" for @matching elements;
# But then just:
# print $_, "\n" for grep /$wahtever/, @array;
# if you don't need @matching elements elsewhere
or
foreach (@array) {
print "Matched :$_:\n" if /$value/;
}
or even
/$value/ and print "Matched :$_:\n" for @array;
But then I have the feeling that you really wanted to ask about something different, since in all earnestness I couldn't make 100% sense of your wording.
Incidentally, to define that long list of "words", you may use use qw// to great advantage, improving readability, typing speed and possibly reducing the risk of typos. | [reply] [d/l] [select] |
|
|