m//

G

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. 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.
 
G

Guy

Ben Morrow said:
Quoth "Guy said:
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
 
U

Uri Guttman

BM> Yup.

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
 
S

sln

[reordered slightly for clarity]

Quoth "Guy said:
Ben Morrow said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top