m//

Discussion in 'Perl Misc' started by Guy, May 29, 2009.

  1. Guy

    Guy Guest

    A user submits a few keywords to search, for example "red barn". I push
    these words in the array @words.

    I then want to search through each record of my text database to see if any
    of those keywords (up to four keywords) appear in the description of the
    photos.

    I would suspect there is a better way. Would there be a simple way to check
    all submitted keywords, assuming the user could only submit a 50 character
    string?

    I suppose too that PDS may not be very descriptive for a hash. Do I need
    quotes around PDS?

    Note too that this is an array of hashes since $j is sequential between 0
    and n-1.


    if ( $info[$j]{'PDS'} =~ /$words[0]|$words[1]|$words[2]|$words[3]/ )


    Thanks for any and all info,
    Guy D.
    Guy, May 29, 2009
    #1
    1. Advertising

  2. Guy

    Guy Guest

    "Ben Morrow" <> a écrit dans le message de news:
    ...
    >
    > Quoth "Guy" <>:
    >> A user submits a few keywords to search, for example "red barn". I push
    >> these words in the array @words.
    >>
    >> I then want to search through each record of my text database to see if
    >> any
    >> of those keywords (up to four keywords) appear in the description of the
    >> photos.
    >>
    >> I would suspect there is a better way. Would there be a simple way to
    >> check
    >> all submitted keywords, assuming the user could only submit a 50
    >> character
    >> string?
    >>
    >> I suppose too that PDS may not be very descriptive for a hash.

    >
    > The question you should ask is: in the context of this program, is it
    > clear what the key is being used for? Without seeing the rest of the
    > program or knowing what 'PDS' stands for I can't give an opinion on that
    > :).
    >
    >> Do I need quotes around PDS?

    >
    > No. You can omit the quotes (inside the {} of a hash element, or to the
    > left of the => operator) on any word consisting only of the characters
    >
    > a-z A-Z 0-9 _
    >
    > i.e. any word that matches /^\w+$/.
    >
    >> Note too that this is an array of hashes since $j is sequential between 0
    >> and n-1.
    >>
    >> if ( $info[$j]{'PDS'} =~ /$words[0]|$words[1]|$words[2]|$words[3]/ )

    >
    > You are matching literal strings, so you need to use \Q in case they
    > contain regex metacharacters.
    >
    > I would write this
    >
    > # before the loop
    > my $rx = map qr/$_/, join "|", map "\\Q$_\\E", @words;
    >
    > # inside the loop
    > if ($info[$j]{PDS} =~ $rx) {
    > ...
    > }
    >
    > but you need to make sure you understand how that works before blindly
    > copying it.
    >
    > In general, looping over array indices is bad style in Perl. If you have
    > a loop that looks like this
    >
    > for (my $j = 0; $j < @info; $j++) {
    > if ($info[$j]{PDS} =~ $rx) {
    > ...
    > }
    > }
    >
    > it would be better written as
    >
    > for (@info) {
    > if ($_->{PDS} =~ /$rx/) {
    > ...
    > }
    > }
    >
    > Ben


    Thanks Ben.
    In your code, the for (used as a foreach) definitely looks (and reads) much
    better than the for-loop that I had in my code. It may be a dead giveaway
    that I used to write in Basic.

    I've tried to figure out your line of code:
    my $rx = map qr/$_/, join "|", map "\\Q$_\\E", @words;

    I'm guessing that it first uses map to disable pattern metacharacters in
    every $_ of @words. This is done by:
    map "\\Q$_\\E", @words

    I'm trying to unserstand why you have \\Q and \\E, I thought it would be
    something like:
    map "/\Q$_\E/", @words

    It then uses this result in the next map, which for each $_, disables
    pattern metacharacters with qr// and join them all with a "|".
    map qr/$_/, join "|"

    Finally, it store the reference of the resulting pattern into a scalar for
    later use.

    In the end, if looks like you transformed a string of keywords like this:
    "one two three four"
    into this:
    "one|two|three|four"
    And disabling pattern metacharacters in the process.

    Am I way out in left field?
    Guy
    Guy, Jun 2, 2009
    #2
    1. Advertising

  3. Guy

    Uri Guttman Guest

    >>>>> "BM" == Ben Morrow <> writes:

    >> > I would write this


    >> > # before the loop
    >> > my $rx = map qr/$_/, join "|", map "\\Q$_\\E", @words;
    >> >

    >>
    >> I'm guessing that it first uses map to disable pattern metacharacters in
    >> every $_ of @words. This is done by:
    >> map "\\Q$_\\E", @words


    BM> Yup.

    >> I'm trying to unserstand why you have \\Q and \\E, I thought it would be
    >> something like:
    >> map "/\Q$_\E/", @words


    BM> The double-backslashes are because the double-quotes will remove one
    BM> level of escaping:

    BM> ~% perl -le'print "\\Qfoo\\E"'
    BM> \Qfoo\E

    maybe using quotemeta would make that cleaner and remove the need for
    the extra escaping.

    map quotemeta, @words

    that should work just as your code but much cleaner.

    BM> What's a little confusing here is that the 'map qr//' only maps over one
    BM> element: by that point the list has been joined together into a single
    BM> string. The only reason for using map is because I like it: it could
    BM> just as well have been written

    BM> my $rx = join "|", map "\\Q$_\\E", @words;
    BM> $rx = qr/$rx/;

    that is a useful use of a single argument list to map.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Jun 2, 2009
    #3
  4. Guy

    Guest

    On Tue, 2 Jun 2009 03:50:11 +0100, Ben Morrow <> wrote:

    >[reordered slightly for clarity]
    >
    >Quoth "Guy" <>:
    >> "Ben Morrow" <> a écrit dans le message de news:
    >> ...
    >> >
    >> > In general, looping over array indices is bad style in Perl. If you have
    >> > a loop that looks like this
    >> >
    >> > for (my $j = 0; $j < @info; $j++) {
    >> > if ($info[$j]{PDS} =~ $rx) {
    >> > ...
    >> > }
    >> > }
    >> >
    >> > it would be better written as
    >> >
    >> > for (@info) {
    >> > if ($_->{PDS} =~ /$rx/) {
    >> > ...
    >> > }
    >> > }

    >>
    >> In your code, the for (used as a foreach) definitely looks (and reads) much
    >> better than the for-loop that I had in my code. It may be a dead giveaway
    >> that I used to write in Basic.

    >
    >Me too :). Learning good style in a ny language is an incremental
    >process. It's made somewhat harder for Perl by the enormous amount of
    >*really* ugly code out there.


    Explain "really ugly code". Is that the 10 thousand line C++ patch of
    the 300,000 line base in a two week contract?

    -sln
    , Jun 2, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page