Issue
I have written a perl
script to read an input file line-by-line for a given search string. I have done two implementations using the inbuilt perl
functions grep
and index
, but I'm not able to get the output for the exact string match.
My sample code, input file and the desired output is shown below. Please help me understand the issue with this script which can help me to get the required output.
SAMPLE_CODE
#!/usr/bin/perl
my $myfile = "/path/to/the/file/list.txt";
my $details = "1234,5678";
my @required;
open FH, "$myfile" or die "Cannot open file for reading\n";
while(<FH>)
{
$line = $_;
chomp $line;
@list = split(/\,/, $details);
foreach my $var (@list)
{
chomp($var);
#if (grep /$var/, $line) # partially working
if (index($line, $var) >= 0) # partially working
{
my @arr = split(/[\:]/, $line);
push (@required, $arr[0]);
}
}
}
close FH;
print "required array is @required \n";
INPUT_FILE
$> cat /path/to/the/file/list.txt
CAT:1234,5678
RAT:12345,9871
OUTPUT
required array is CAT CAT RAT
DESIRED_OUTPUT
required array is CAT CAT
Here the problem is that, Since the variable $details
has a string 1234
, the grep
or index
checks should not pass the search criteria for the second line in input file list.txt
for 12345
.
How can i fix this issue for exact match?
Solution
It already was indicated that your code will match partial pattern, it is not what you desire. You need implement exact match and regular expression has \b
to indicate the boundary of element.
It is a good practice to include in the begin of the script
use strict;
use warnings;
what allows to warn you about undesired effect of your code.
Perhaps for this case you can utilize <>
(null handle/diamond operator) instead of opening filehandle, it simplifies the code and allows code's double usage as script.pl list.txt
or cat list.txt | script.pl
NOTE: @list = split(/,/, $details);
should be placed outside of loop to save CPU cycles
Please see the following snippet code producing desired output
#!/usr/bin/env perl
#
# vim: ai ts=4 sw=4
use strict;
use warnings;
use feature 'say';
my $details = "1234,5678";
my(@list, @required);
@list = split(/,/, $details);
while(<>) {
for my $element ( @list ) {
if( /\b$element\b/ ) {
my @arr = split(/[:,]/, $_);
push @required, $arr[0];
}
}
}
say "Required array is @required";
Output
Required array is CAT CAT
Answered By - Polar Bear Answer Checked By - Pedro (WPSolving Volunteer)