http://qs1969.pair.com?node_id=522527

jesuashok has asked for the wisdom of the Perl Monks concerning the following question:

This node falls below the community's threshold of quality. You may see it by logging in.

Replies are listed 'Best First'.
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.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: how to add more intelligence to grep functionality
by GrandFather (Saint) 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

      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.

Re: how to add more intelligence to grep functionality
by holli (Abbot) on Jan 11, 2006 at 19:33 UTC
    hand rolled solution:
    #!/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


    holli, /regexed monk/
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

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.