pglinx has asked for the wisdom of the Perl Monks concerning the following question:

I have this snippet of code that works great except I need it to match 3 elements of a line that are not in a row. I am trying to match LName FName and county to remove the line but it removes all lines based on county only, instead of all 3. So if a line has Jim Jones 77477 Dade Hollywood it needs to be deleted based on a match of Jim Jones Dade.
File entries are in this format "LName","FName","Zip","County","Town" code is here $log_name = "zipfile.txt"; my $exclude = "$input{'FName'}, $input{'LName'}, $input{'county'}"; my @excludes = split (/ /,$exclude); local @ARGV = ($log_name); local $^I = '.bak'; LOOP: while (<>) { foreach my $entry (@excludes) { next LOOP if (/$entry/); } print; } }

Replies are listed 'Best First'.
Re: Matching and removing a line from a file
by jethro (Monsignor) on Dec 10, 2008 at 04:20 UTC

    Apart from the problem with @excludes mentioned by the others your code simply deletes a line if any one of the @excludes is found on the line, instead of only if all are found. Reversing this logic would be easy but it still would be wrong, because your are searching the whole line. If for example you were trying to delete Jim Dale from Dale County you would also delete any other Jim from Dale County.

    So you have to check for the names at their right position, something like this:

    while (<>) { my($fn,$ln,$zip,$cn,$to)= split(/","/); $fn=substr($fn,1); #get rid of the first " next if ($fn eq $input{'FName'} and $ln eq $input{'LName'} and $cn e +q $input{'county'}); print; }

    This should work when your lines really look like '"Jim","Jones","77477","Dade","Hollywood"'. If the delimiters are only commas, change the split accordingly and remove the substr line

Re: Matching and removing a line from a file
by jwkrahn (Abbot) on Dec 10, 2008 at 03:32 UTC
    my $exclude = "$input{'FName'}, $input{'LName'}, $input{'county'}"; my @excludes = split (/ /,$exclude);

    That should probably be written as:

    my @excludes = @input{ 'FName', 'LName', 'county' };
Re: Matching and removing a line from a file
by ikegami (Patriarch) on Dec 10, 2008 at 03:02 UTC
    split (/, /,$exclude) ^ | missing

    I'm assuming $exclude comes from a file or something? If not, the following would be better than creating a string and splitting it:

    my @excludes = ( $input{'FName'}, $input{'LName'}, $input{'county'} );

    Also,
    /$entry/
    should be
    /^\Q$entry\E\z/
    or
    $_ eq $entry
    \Q..\E convert the text to a regexp pattern. ^..\z makes sure $entry is not just part of the $_.

      /^\Q$entry\E\z/
      If the entry field for which a record is to be excluded is anchored to the start and end of the string against which it is matching (so that the match is the same as testing for string equality), doesn't that mean that no record will ever match (and so no record will ever be excluded) because no exclusion field will ever match the entire record?

      Also, because the exclusion fields are never paired to any specific fields of the record in the code of the OP, if one was seeking to exclude Jim Jones of Dade county, would not Jim Dade of Jones county (or, indeed, any record having 'Jim', 'Dade' or 'Jones' in any field) also be excluded?

        Oops, I was rushed when I wrote that.

        While $_ eq $entry should still be used, it should be after extracting the fields.

        while (<>) { my @fields = split /,/; # Text::CSV_XS would be better. next if $field[0] eq $input{FName} || $field[1] eq $input{LName} || $field[3] eq $input{county}; print; }
        or
        while (<>) { my @fields = split /,/; # Text::CSV_XS would be better. next if $field[0] eq $input{FName} && $field[1] eq $input{LName} && $field[3] eq $input{county}; print; }

        depending on what the OP wants.