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

I have 2 files... one which contains 98% of what I need I will call DATA the second KEY. Key has 2 fields, field one will match a field in DATA. When it matches I want it to set variable $custnmbr = $field2. Then output to a new file which is created. The problem is it doesn't work and I just can't seem to figure out why (probably wrong since I did write it) Here is the simple simple simple code (Yes Grasshoper has a long way to go =P ) The $variables in the CONVERTED file are declared at the top they have been omitted to conserve space.
$LOCK_EX = 2; $LOCK_UN = 8; # open the Vendor file use Date::Calc qw/Add_Delta_Days/; open(DATA,"/usr/local/download/chenny/goodsold-raw1.txt") || &error("E +rror reading /usr/local/download/chenny/invoice-raw1.txt -> $!"); flock(DATA, $LOCK_EX); # lock the INVOICE1 file open(CONVERTED,">>/usr/local/download/chenny/invoicedetail.txt") || &e +rror("Error opening /usr/local/download/chenny/invoicedetail.txt -> $ +!"); flock(CONVERTED, $LOCK_EX); # lock the CONVERTED file open(KEY,"/usr/local/download/chenny/invoicecheck") ||&error("Error op +ening invoicecheck for reading -> $!"); flock(KEY, $LOCK_EX); while(<DATA>){ ($c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$c10,$c11,$c12,$c13,$c14, +$c15,$c16,$c17,$c18,$c19,$c20,$c21,$c22,$c23,$c24,$c25,$c26,$c27,$c28 +,$c29,$c30,$c31,$c32,$c33,$c34,$c35,$c36) = split(/ /); $flag = 0; while(<KEY>){ ($s1,$s2) = split(/,/); if (($s1) eq ($c5)) { $custnmbr = $s2; $flag = 1; print $s1; print $custnmbr; } }; if ($flag == 1 ) { my $delta = $c2; my ($year,$month,$day) = Add_Delta_Days(1800,12,28,$delta); $date = sprintf("%4d%02d%02d", $year, $month, $day); print CONVERTED ("$c1,$invoicecount,$custnumbr,$c2,$c8 +,$store,$productlocation,$c9,$c11,$productvendor,$c15,$quantityordere +d,$quantityshipped,$quantitybackordered,$c17,$c18,$replacementcost,$f +et,$recapordernumber,$recaporderlinenumber,$recapdealercustomer,$reca +pdealerinvoice,$comissioncode,$treaddepth,$percentageofwear,$releasen +umber,$pricechanged,$costchanged,$addlineitem,$spifamount,$mechanic,$ +c20,$itemdiscount,$serialnumber,$brandnumber,$brandcustomer,$contract +number,$claimnumber,$tireposition,$adjustment,$productexempt,$mapcode +,$casingpurchase,$message,$linemsgassoc\n"); } }; flock(DATA, $LOCK_UN); close(DATA); flock(CONVERTED, $LOCK_UN); close(CONVERTED); flock(INVOICE, $LOCK_UN); close(INVOICE); flock(KEY, $LOCK_UN); close(KEY);

Replies are listed 'Best First'.
Re: How to compare a field in 2 files and set a value if it matches?
by tall_man (Parson) on May 20, 2003 at 21:16 UTC
    The big problem here is that you try to read KEY over and over, once for each line of DATA. It will read the KEY file once for the first line of DATA and then fail. Instead, you should store the values from KEY in a hash first:
    my %keyval = (); while(<KEY>){ ($s1,$s2) = split(/,/); $keyval{$s1} = $s2; }
    In the DATA loop, look up $c5 in the hash:
    if (exists $keyval{$c5}) { $custnmbr = $keyval{$c5}; $flag = 1; }
    Also, you might want to split into an array instead of using such repetitive variable names.
      Your solution worked like a charm. I appreciate your assistance =)......I do normally use @c to split things out but when I get into trouble I break things down to their simplest form (and easiest way of understanding them) to sort them out. Mainly cause I always forget that and array starts at 0 not 1 and always figure I fubared myself by skewing everything by forgetting to start at 0.... aschroh
      should this also work for strings...I have tried this on data(numbers) and it works ok but on a string it does not work
Re: How to compare a field in 2 files and set a value if it matches?
by chromatic (Archbishop) on May 20, 2003 at 21:20 UTC

    I think the nested file reads are getting in your way. First you read a line from DATA, then you read all of KEY, a line at a time. Then you read another line from DATA. Since you've already read all of KEY, you can't read anymore. Only the keys matching the first line in DATA will be processed.

    Seems to me that a better approach is to read all of DATA into an array of hashes, then loop through KEY, but I'm fuzzy on what you're trying to accomplish.

    Oh, and you've just reinvented arrays the hard way. Consider this instead:

    while(<DATA>) { my @c = split / /, $_; # ... }
Re: How to compare a field in 2 files and set a value if it matches?
by pzbagel (Chaplain) on May 20, 2003 at 21:35 UTC

    First off, change that ugly split command. Instead of 36 $c variables, how about a @c array? You have to reference using the indexes so you'll have to change the numbers to one less when you update your code(since arrays index starts @ 0).

    #from this: ($c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$c10,$c11,$c12,$c13 +,$c14, +$c15,$c16,$c17,$c18,$c19,$c20,$c21,$c22,$c23,$c24,$c25,$c26,$c27,$c28 +,$c29,$c30,$c31,$c32,$c33,$c34,$c35,$c36) = split(/ /); #to this: @c=split(/ /);

    As mentioned before, you can only read the <KEY> file once and the next time through you will miss records. Also, in the while(<KEY>) loop I see you setting $custnmbr you then print it, but in the print CONVERTED statement you misspell it $custnumbr. This may be part of the problem.

    HTH

Re: How to compare a field in 2 files and set a value if it matches?
by benn (Vicar) on May 20, 2003 at 21:19 UTC
    The words 'It doesn't work' aren't generally the best ones to use when attempting to precisely define your problem :), but it looks like the *main* problem here is that your 'read the KEY file' loop is inside your 'read the DATA file' loop, so KEY only gets read the first time through, then is 'exhausted'. As KEY is small, it'd be easy to read it into an array first.

    Forgive the emphasis, but have you seen arrays? Very handy - they save you having to type "$c1,$c2,$c3...". Have a look at how "my @fields = split(/ /)" might help you cut down the amount of 'noise' here, which would help you analyse your poblem a little better.

    Cheers
    Ben.

      Your right let me clarify the problem. When I run the script it runs through it's entirity and the invoicedetail.txt is empty. I set it to print $s1 and $s2 to the screen and I get nothing. I am pretty sure the problem is exactly what benn stated....hadn't thought about that part of it. I do normally use arrays but when things break I take it to down to the simplest manner of expression as possible (even if it does make it look ugly) for the simple reason that when i pull elements from arrays I have a VERY nasty habbit of forgetting they start with 0 not 1....which completely messes me up...still trying to burn that one into my brain. Thanks for your help =).