Re: Trying to make a search Part 2
by swiftone (Curate) on Jun 05, 2000 at 19:47 UTC
|
For future reference, please be more specific on what isn't working.
Your first line:
#/usr/bin/perl
Should be:
#!/usr/bin/perl
This is an operating system thing, not a perl thing, and won't affect you if you are using a Windows system or calling the script from the command line (e.g. "perl myscript.pl")
open(DATA, "data.txt") or die "error opening file $!";
@data = <DATA>;
Update: As many (sean, infoninja, and mdillon have pointed out, @data=<DATA> is correct.
<strikeout>I believe your problem might be here. <DATA> returns a string. @data is an array. Also, you are only getting the first line from DATA, not all the lines.</strikeout>
if ($data =~ /$word/) {
Note that this is case-sensitive. You might want to use /$word/i to make it insenstive.
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: Trying to make a search Part 2
by lhoward (Vicar) on Jun 05, 2000 at 19:55 UTC
|
One thing you might find handy is
use warnings;
It points out potential problems with your code.
(This code doesn't have any, but it is a good technique to use anyway).
In this case I think your problem is that you're double-chomping $word.
When reading input you only need to chomp once to remove the line terminator
(CR/LF).
print "Search for what: ";
chomp(my $search = <STDIN>);
@words = split(/ /, $search);
open(DATA, "data.txt") or die "error opening file $!";
@data = <DATA>;
foreach $data(@data) {
foreach $word(@words) {
if ($data =~ /$word/) {
print $data;
}
}
}
| [reply] [d/l] [select] |
|
|
Double chomping doesn't hurt anything. Yeah, its a waste of cycles, but chomp only removes white space characters. Double choping on the other hand would be bad (unless that was what you wanted to do)
| [reply] |
Re: Trying to make a search Part 2
by mdillon (Priest) on Jun 05, 2000 at 20:08 UTC
|
everybody is wrong!
@data = <DATA>; does not read only one line. it
reads all available lines from the DATA filehandle. has
everybody gone mad?
in scalar context, the <FH> operator returns a
single line, but in list context, it returns them all.
'@data =' is clearly a list context. | [reply] |
Re: Trying to make a search Part 2
by infoninja (Friar) on Jun 05, 2000 at 20:06 UTC
|
Actually, the use of @data will read each remaining line of the filehandle into an array element of @data. The code below illustrates this (assuming that the file test.pl exists in the directory where the code is run):
#!/usr/bin/perl -w
use strict;
open(TEST,'test.pl');
my @test = <TEST>;
my $line_number = 0;
foreach (@test) {
++$line_number;
print "$line_number: $_";
}
| [reply] [d/l] |
(zdog) Re: Trying to make a search Part 2
by zdog (Priest) on Jun 05, 2000 at 20:23 UTC
|
Cool. Thanx everyone. I finally got it like this:
#!/usr/bin/perl
print "Search for what: ";
chomp(my $search = <STDIN>);
@words = split(/ /, $search);
open(DATA, "books.txt") or die "error opening file $!";
while (<DATA>) {
$matches=0;
foreach $word(@words) {
chomp($word);
if (/$word/i) {
print unless ($matches > 0);
$matches++;
}
}
}
-- zdog (Zenon Zabinski)
Go Bells!! | [reply] [d/l] |
|
|
One thing to note: The regex in your foreach loop has to be
compiled several times (potentially) for every line,
which can be a performance drain. A better approach is to
precompile your regexes using the qr// operator
(described in perlop).
#!/usr/bin/perl
print "Search for what: ";
chomp(my $search = <STDIN>);
@words = split(/ /, $search);
# Turn words into regular expressions
@words = map {qr/$_/i} @words;
# If you don't want the user to have to
# worry about regex syntax, use this instead:
# @words = map {qr/\Q$_/i} @words
open(DATA, "books.txt") or die "error opening file $!";
while (<DATA>) {
$matches=0;
foreach $word(@words) {
if ($_ =~ $word) {
print unless ($matches > 0);
$matches++;
}
}
}
| [reply] [d/l] |
(zdog) Re: Trying to make a search Part 2
by zdog (Priest) on Jun 05, 2000 at 20:00 UTC
|
Thanx guys. I got it to work like this:
#!/usr/bin/perl
use warnings;
print "Search for what: ";
chomp(my $search = <STDIN>);
@words = split(/ /, $search);
open(DATA, "books.txt") or die "error opening file $!";
while (<DATA>) {
foreach $word(@words) {
chomp($word);
if (/$word/i) {
print;
}
}
}
But now how would I get it to only print out the entry once even when there are multiple matches
-- zdog (Zenon Zabinski)
Go Bells!! | [reply] [d/l] |
|
|
But now how would I get it to only print out the entry once even when there are multiple matches
Like so:
#!/usr/bin/perl
use warnings;
print "Search for what: ";
chomp(my $search = <STDIN>);
my %found; #used as a set later
@words = split(/ /, $search);
open(DATA, "books.txt") or die "error opening file $!";
while (<DATA>) {
foreach $word(@words) {
chomp($word);
if (/$word/i) {
print unless defined($found{lc($word)});
$found{lc($word)}=1; #indicates that word has been found
}
}
}
Update: This prints the line for each word only once. If you instead want to print each line only once, regardless of how many words it matches, try this:
#!/usr/bin/perl
use warnings;
print "Search for what: ";
chomp(my $search = <STDIN>);
@words = split(/ /, $search);
open(DATA, "books.txt") or die "error opening file $!";
while (<DATA>) {
foreach $word(@words) {
chomp($word);
if (/$word/i) {
print;
last; #skips checking this line against oth
+er words
}
}
}
| [reply] [d/l] [select] |
|
|
I would use a hash, like this:
if (/$word/i) {
print unless (++$matches{$word} > 1)
}
I suppose you could use $_ in place of $word if you wanted.Update: After seeing swiftone's post I realize that I forgot to adjust case. Thanks swiftone. if (/$word/i) {
print unless (++$matches{lc $word} > 1)
}
| [reply] [d/l] [select] |
Re: Trying to make a search Part 2
by Adam (Vicar) on Jun 05, 2000 at 19:44 UTC
|
Two things. Don't use the pattern match if eq will work. And @data = <DATA>; only reads the first line of your file.UPDATE: I stand corrected. As always, I continue to learn daily. Thanks. | [reply] [d/l] |
|
|
Actually, @data = <DATA>; will normally slurp in the whole file.
| [reply] [d/l] |
|
|
A filehandle read called in a list context
populates the whole file into the list, one
line per element.
| [reply] |