0

I'm new to programming so bear with me. I'm working on a Perl script that asks the user the number of different items they want to search for and what those items are, separating them by pressing ENTER. That part works okay.

Then, the script is to open up a file, parse through, and print each line that matches with the items that the user initially listed. This is the part that I haven't been able to figure out yet. I've tried different variations of the code. I saw many people suggest using the index function but I had no luck with it. It does seem to be working when I swap $line =~ $array for $line =~ /TEXT/. I'm hoping someone here can shed some light.

Thanks in advance!

#!usr/bin/perl
use strict;
use warnings;

my $line;
my $array;

print "Enter number of items: ";        
chomp(my $n = <STDIN>);

my @arrays;                                                     
print "Enter items, press enter to separate: \n";
for (1..$n) {
    my $input = <STDIN>;
    push @arrays, $input;
}

open (FILE, "file.txt") || die "can't open file!";      
chomp(my @lines = <FILE>);
close (FILE); 

foreach $array (@arrays) {                                      
        foreach $line (@lines) {
            if ($line =~ $array) {
                print $line, "\n";
        }
    }
}
  • Possible duplicate of [Perl Regex - Print the matched value](https://stackoverflow.com/questions/5617314/perl-regex-print-the-matched-value) – jww Oct 11 '17 at 01:03
  • You forgot to chomp. – ikegami Oct 11 '17 at 03:59
  • You forgot to turn text into a regex pattern using `quotemeta` – ikegami Oct 11 '17 at 04:00
  • You forgot to anchor with `^` and `\z`. – ikegami Oct 11 '17 at 04:00
  • You forgot to avoid printing the same line more than once. – ikegami Oct 11 '17 at 04:00
  • You forgot that could you could just read until EOF rather awkwardly asking for how much information in coming. – ikegami Oct 11 '17 at 04:01
  • You forgot that you could use the more flexible `ARGV` (the default handle for `<>`) instead of `STDIN`. – ikegami Oct 11 '17 at 04:02
  • @ikegami seems like there are a lot of things I forgot to do. "You forgot that could you could just read until EOF rather awkwardly asking for how much information in coming." This is what I wanted to do initially but didn't know how to go about it. Thanks for the responses :) – purplekushbear Oct 11 '17 at 18:36
  • `while (defined( my $input = )) { ... }`, or with `ARGV`, `while (defined( my $input = <> )) { ... }` – ikegami Oct 11 '17 at 18:41
  • This helps! I tried the following: 'while (defined(my $input = )) { chomp $input; last if $input eq "end"; push @items, $input; }' Is there a better way to break from the loop. This one seems to exit the entire script after I enter "end". – purplekushbear Oct 11 '17 at 19:01
  • @ikegami figured it out. Thanks for the help! – purplekushbear Oct 11 '17 at 19:44
  • Yeah, remove `last if ...;`. Again, you should just read until EOF – ikegami Oct 11 '17 at 21:28

2 Answers2

0

@purplekushbear Welcome to Perl! In Perl, there is more than one way to do it (TIMTOWTDI) so please take this in the spirit of teaching that it is given. First off your line one -- the #! (sha bang line) is missing the leading / in the path to perl. In Linux/UNIX environments if your script is executable the path after the #! is used to run your program. --- If you do an ls on /usr/bin/perl you should see it. Sometimes it is found at /bin/perl or /usr/local/bin/perl. When the person mentioned you forgot to chomp they where referring to where you are setting the $input variable. Just chomp like you did for $n and you will be ok. As for the main part of your program go back and read what you wanted to do and do exactly that might be simpler to do. I think you have a good start on the problem and seem to know that arrays start with a @ and scalar variables use the $ sigil, and you use strict which is great. Here is one way to solve your problem:

#!/usr/bin/perl
use strict;
use warnings;

print "Enter number of items: ";
chomp(my $num = <STDIN>);

my @items = ();
print "Enter items, press enter to separate: \n";
for (1 .. $num)
{
    chomp(my $input = <STDIN>);
    push @items, $input;
}
open (FILE, "file.txt") || die "can't open file because $!";
while (my $line = <FILE>)
{
    foreach my $item (@items)
    {
        if ($line =~ m/$item/)
        {
            print $line;
            last;
        }
    }
}
close (FILE);

Notice I used the name @items for your items instead of @arrays which will make understanding the code easier when you come back to it someday. Always write with an eye towards maintainability. Anyways, ask if you have any questions but since I left much of the code the same I don't think you will have much trouble figuring it out. Perldoc and google are your friends. E.g. you can type:

perldoc -f last 

to find out how last works. Have fun!

Ken Schumack
  • 719
  • 4
  • 11
  • Hi! I appreciate the warm welcome, Ken. I think I'm going to find myself on Stack Overflow quite a lot for the next couple of months. As for your response, TIMTOWTDI is something I'm quickly starting to learn. Thanks for the advice on maintainability. I read somewhere that the best code is the one that is self-explanatory with little to no comments. – purplekushbear Oct 11 '17 at 18:26
0

In you script you have forgot to add the chomp while giving the user input, then you need to last the inside for loop when pattern is matched.

Then here is another way,You can try the following, same thing with different method.

I'm making variable name $regex instead of @array. In $regex variable I'm concatenating user input values with | separated. (In regex | behave like or). While concatenating I'm making the quotemeta to escape the special characters. Then I'm making the precompiled regex with qr for $regex variable

#!usr/bin/perl
use strict;
use warnings;

print "Enter number of items: ";        
chomp(my $n = <STDIN>);

my $regex;
print "Enter items, press enter to separate: \n";

for (1..$n) 
{
    chomp(my $input = <STDIN>);
    $regex .= quotemeta($input)."|";
}

chop $regex; #remove the last pipe
$regex = qr($regex);

open my $fh,"<", "file.txt" || die "can't open file!";      

while(<$fh>)
{
    print if(/$regex/i);
}

Then user @ikegami said his comment, you can use the Perl inbuilt @ARGV method instead of STDIN , for example

Your method

my @array = @ARGV;

Another method

my $regex = join "|", map { quotemeta $_ } @ARGV; 

Then run the script perl test.pl input1 input2 input3.

And always use 3 arguments to open a file

mkHun
  • 5,891
  • 8
  • 38
  • 85
  • This works perfectly! I'm still a bit unfamiliar with some of the concepts you use in your code but it's great for exposure. I appreciate the response, thank you! – purplekushbear Oct 11 '17 at 18:17