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

Hi, i am currently writing a script to filter out an input file with a waiver file, to an output file. Input file format:

abcd123 klmn123 100.00 1000.00 -900.00 (VIOLATED) abcd124 klmn124 100.00 1000.00 -900.00 (VIOLATED) . .and so on

Waiver fileformat:

klmn124,100.00,2500.00,"justifiedbyChan","Date:14/4" . .and so on

Ps: waiver file is a filter, menas if watever inside it, the similiar content in input file should change to output format like this:

abcd123 klmn123 100.00 1000.00 -900.00 (VIOLATED) abcd124 klmn124 100.00 2500.00 -2400.00 (WAIVED)

Anyone has any ideas?

Replies are listed 'Best First'.
Re: Filter out an input file with a given waiver file, and output to a specific file
by hippo (Archbishop) on Jul 12, 2017 at 10:23 UTC
    Anyone has any ideas?

    Simple algorithm:

    1. Read the waiver file into a hash keyed on the field to be matched (the first, apparently, in your example)
    2. Read the input file line by line, extracting the second field for comparison. If there's a matching hash entry, apply it.
    3. Output the potentially modified line.
    4. Goto 2 until eof
Re: Filter out an input file with a given waiver file, and output to a specific file
by choroba (Cardinal) on Jul 12, 2017 at 10:18 UTC
    What do you mean by "similar content"? The same value in the 2nd column? It also seems you want to do some math with the numeric columns—can you describe what should happen?

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Filter out an input file with a given waiver file, and output to a specific file
by dbander (Scribe) on Jul 12, 2017 at 10:55 UTC

    This should get you moving in a useful direction; it demonstrates the use of a Hash (which happens to also be a Hash Of Hashes (HoH), which you could research on your own).

    CAVEAT: This is not production quality code. Its purpose is demonstration, not solution.

    #!/usr/bin/perl use strict; use warnings; # Set up a hash to receive the information my %violationdata = (); # Read the violations file into the hash open my $violations, '<', 'violations.txt' or die; while (my $vline = <$violations>) { my ($vkey, $ukey, $credit, $debit, $balance, $notes) = split /\s+/, $vline; $violationdata{$vkey}{UKEY} = $ukey; $violationdata{$vkey}{CREDIT} = $credit; $violationdata{$vkey}{DEBIT} = $debit; $violationdata{$vkey}{BALANCE} = $balance; $violationdata{$vkey}{NOTES} = $notes; } close $violations; # Display the contents of the hash foreach my $okey (sort keys %violationdata) { print " $okey:\n"; foreach my $skey (sort keys %{$violationdata{$okey}}) { my $sval = $violationdata{$okey}{$skey}; print " $skey: $sval\n"; } } # Now process the waivers and update the hash open my $waivers, '<', 'waivers.txt' or die; close $waivers; # Now write out the hash to the updated violations file open my $updated, '>', 'updated.txt' or die; close $updated;

    Results:

    $ ./violwaiv.pl abcd123: BALANCE: -900.00 CREDIT: 100.00 DEBIT: 1000.00 NOTES: (VIOLATED) UKEY: klmn123 abcd124: BALANCE: -900.00 CREDIT: 100.00 DEBIT: 1000.00 NOTES: (VIOLATED) UKEY: klmn124

      Hi dbander

      I would tend to do it the other way around: store the waivers into a hash (a simple hash) where the key is the common identifier between the two files, and then read the violations file line by line, changing the content of the line when the identifier is common between the two files and writing the line to the new files. This is often more efficient this way.

      But since we don't know about the size of the violations and waivers files, it actually may be that your solution is better (especially if there are many more waivers than violations, but that's seems rather unlikely).

        Hi Laurent_R

        Agreed, that would be an excellent production design consideration.

Re: Filter out an input file with a given waiver file, and output to a specific file
by DespacitoPerl (Acolyte) on Jul 13, 2017 at 06:01 UTC
    #! /tools/perl/5.8.8/linux/bin/perl use strict; use warnings; # Set up a hash to receive the information my %identifier = (); # Read the violations file into the hash open my $filter, '<', $waiver or die; while (my $vline = <$filter>) { my ($pins2, $threshold2, $newthreshold2, $note1, $note2, $note3, $ +note4, $note5) = split /\s+/, $vline; #$identifier{$pins2}{threshold2} = $threshold2; $identifier{$pins2}{newthreshold2} = $newthreshold2; } #Read input file line by line open my $input, '<', $report or die; open my $output, '>', $result or die; while (my $wline = <$input>){ my ($scenario, $pins1, $threshold1, $newthreshold1, $diff, $status +) = split /\s+/, $wline; print $output "$scenario $pins1 $threshold1 $newthreshold +1 $diff $status\n"; foreach my $okey (keys %identifier) { foreach my $skey (keys %{$identifier{$okey}}) { if (exists $identifier{$okey}) { #my $diff2 = $skey - $threshold1; print $output "$scenario $pins1 $threshold1 $skey +$diff (WAIVED)\n"; } } } } close $filter; close $input; close $output;

    guys, i still have some problems with this code, anyone has any ideas? Basically, my waiver file won't be larger tan input file, and i want the output format same as input file, just watever mention inside the waiver file, the fourth column value chg to waiver file value, and the status chg from "violated" to "waived"

      No need to loop through the hash keys to find a match

      foreach my $okey (keys %identifier) {
         foreach my $skey (keys %{$identifier{$okey}}) {
           if (exists $identifier{$okey}) {
      

      Try

      #!/tools/perl/5.8.8/linux/bin/perl use strict; use warnings; use Data::Dumper; my $report ="/ice_pnr/pnr19/nadder/lzhong/uibnd4h/lzhong.i14socnd.uibn +d4h.44/uibnd4h/r2g2/blocks/INTEL14.P1273.6/uibnd4h_bot_sta/40_finish/ +tmp/trans10/max_trans_summary.list"; my $waiver = "/home/leeyong1/waiver.csv"; my $result = "/home/leeyong1/output.file"; print "script -report ($report) -waiver ($waiver) -output ($result)\n" +; # Read the violations file into the hash #klmn124,100.00,2500.00,"justifiedbyChan","Date:14/4" my %identifier = (); open my $filter, '<', $waiver or die "$!"; while (my $vline = <$filter>) { next unless $vline =~ /\S/; # skip blank lines my ($pin, $t1, $t2, @note) = split /,/, $vline; $identifier{$pin}{'t1'} = $t1; $identifier{$pin}{'t2'} = $t2; } print Dumper \%identifier; #Read input file line by line open my $input, '<', $report or die "$!"; open my $output, '>', $result or die "$!"; #abcd123 klmn123 100.00 1000.00 -900.00 (VIOLATED) while (my $wline = <$input>){ my ($scenario, $pin, $t1, $t2, $diff, $status) = split /\s+/, $wline +; # overwrite values if match if (exists $identifier{$pin}) { $t1 = $identifier{$pin}{'t1'}; $t2 = $identifier{$pin}{'t2'}; $diff = sprintf "%.2f",$t1-$t2; $status = '(WAIVED)'; } print $output "$scenario $pin $t1 $t2 $diff $status\n"; } close $filter; close $input; close $output;
      poj
        in this line and loop, Global symbol "$pins2" requires explicit package name, for both $pin and $identifier

        Update:

        if (exists $identifier{$pin}) {

        in this line and loop, Global symbol "$pin" requires explicit package name, for both $pin and $identifier

        2017-07-15 Athanasius restored original content