0

I'm trying to parse a CSV file that is formatted like this:

    dog cats,yellow blue tomorrow,12445
    birds,window bank door,-novalue-
    birds,window door,5553
    aspirin man,red,567

(there is no value where -novalue- is written)


use strict;
use warnings;


my $filename = 'in.txt';
my $filename2 = 'out.txt';

open(my $in, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";

my $word = "";

while (my $row = <$in>) {
    chomp $row;

    my @fields = split(/,/,$row);

    #Save the first word of the second column
    ($word) = split(/\s/,$fields[1]);

    if ($word eq 'importartWord')
    {
        printf $out "$fields[0]".';'."$word".';'."$fields[2]";
    }   
    else #keep as it was
    {
        printf $out "$fields[0]".';'."$fields[1]".';'."$fields[2]";
    }

Use of uninitialized value $word in string ne at prueba7.pl line 22, <$in> line 10.

No matter where I define $word I cannot stop receiving that error and can't understand why. I think I have initialized $word correctly. I would really appreciate your help here.

Please if you are going to suggest using Text::CSV post a working code example since I haven't been able to apply it for the propose I have explained here. That's the reason I ended up writing the above code.


PD: Because I know you are going to ask for my previous code using Text::CSV, here it is:

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

use Text::CSV;

my $csv = Text::CSV->new({ sep_char => ';', binary => 1 }) or 
                    die "Cannot use CSV: ".Text::CSV->error_diag ();


#directorio donde esta esc_prim2.csv
my $file = 'C:\Users\Sergio\Desktop\GIS\perl\esc_prim2.csv';
my $sal = 'C:\Users\Sergio\Desktop\GIS\perl\esc_prim3.csv';


open my $data, "<:encoding(utf8)", "$file" or die "$file: $!";
open my $out, ">:encoding(utf8)", "$sal" or die "$sal: $!";

$csv->eol ("\r\n");


#initializing variables
my $row = "";
my $word = "";
my $validar = 0;
my $line1 = "";
my @mwords = [""];#Just a try to initialize mwords... doesn't work, error keeps showing


#save the first line with field names on the other file
$line1 = <$data>;
$csv->parse($line1);
my @fields = $csv->fields();
$csv->print($out,[$fields[0], $fields[1], $fields[2]]);



while ($row = <$data>) {

    if ($csv->parse($row)) {
        @fields = $csv->fields();

        #save first word of the field's second element 
        @mwords = split (/\s/, $fields[1]);

        #keep the first one
        $word = $mwords[0];

        printf($mwords[0]);

        #if that word is not one of SAN, EL y LA... writes a line in the new file with the updated second field.
        $validar = ($word ne 'SAN') && ($word ne 'EL') && ($word ne 'LA');
        if ($validar)
        {
            $csv->print($out,[$fields[0], $word, $fields[2]]);
        }
        else { #Saves the line in the new file as it was in the old one.
            $csv->print($out,[$fields[0], $fields[1], $fields[2]]);
        }


    } else {#error procesing row
        warn "La row no se ha podido procesar\n";
    }
}

close $data or die "$file: $!";
close $out or die "$sal: $!";

Here the line where $validar is declared brings the same error of "uninitialized value" although I did it.

I also tried the push @rows, $row; approach but I don't really know how to handle the $rows[$i] since they are references to arrays (pointers) and I know they can't be operated as variables... Couldn't find a working example on how to use them.

9
  • What is line 22? What's on line 10 of the input? Commented Mar 20, 2016 at 20:20
  • N° 107 9 de Julio;alberdi juan bautista 942;4724473\n N° 1078 John F. Kennedy;grandoli 4800;4729682\n N° 1080 Gabriela Mistral;san lorenzo 8154;4727581\n Commented Mar 20, 2016 at 20:23
  • Input is like that... And these are lines that cause trouble in the upper code ($word) = split(/\s/,$fields[1]); if (($word ne 'SAN')&&($word ne 'LA')&&($word ne 'EL')) These line produce the error I posted Commented Mar 20, 2016 at 20:30
  • Please note that I wrote \n in the example of the input because I wasn't able to insert a line-break when editing the comment Commented Mar 20, 2016 at 20:31
  • John Kennedy seems to have no $fields[1], hence the warnings (it's not an error). Commented Mar 20, 2016 at 20:36

2 Answers 2

1

I think you're misunderstanding the error. It's not a problem with the declaration of the variable, but with the data that you're putting into the variable.

Use of uninitialized value

This means that you are trying to use a value that is undefined (not undeclared). That means you are using a variable that you haven't given a value.

You can get more details about the warning (and it's a warning, not an error) by adding use diagnostics to your code. You'll get something like this:

(W uninitialized) An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.

To help you figure out what was undefined, perl will try to tell you the name of the variable (if any) that was undefined. In some cases it cannot do this, so it also tells you what operation you used the undefined value in. Note, however, that perl optimizes your program and the operation displayed in the warning may not necessarily appear literally in your program. For example, "that $foo" is usually optimized into "that " . $foo, and the warning will refer to the concatenation (.) operator, even though there is no . in your program.

So, when you're populating $word, it's not getting a value. Presumably, that's because some lines in your input file have an empty record there.

I have no way of knowing whether or not that's a valid input for your program, so I can't really give any helpful suggestions on how to fix this.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, that was the warning cause, an empty line in the input text file. Thank you.
1

The error message you provided ends with: line 22, <$in> line 10. but your question doesn't show line 10 of the data ($in) requiring some speculation in this answer - but, I'd say that the second field, $field[1], of line 10 of in.txt is empty.

Consequently, this line: ($word) = split(/\s/,$fields[1]); is causing $word to be undefined. As a result, some use of it latter - be it the ne operator (as displayed in the message) or anything else is going to generate an error.

As an aside - there's little point in interpolating a variable in a string on its own; instead of "$fields[0]", say $fields[0] unless you're going to put something else in there, like "$fields[0];". You may want to consider replacing

printf $out "$fields[0]".';'."$word".';'."$fields[2]"; 

with

printf $out $fields[0] . ';' . $word . ';' . $fields[2];

or

printf $out "$fields[0];$word;$fields[2]"; 

Of course, TMTOWTDI - so you may want to tell me to mind my own business instead. :-)

2 Comments

As you and Dave pointed out the warning was appearing due to an empty line on the input file... I know that you entered your answer first, but I think Dave one is going to be more enlightening for newbies entering this question so I'm going to select his answer as solution. I wish I could select both since both of you are right on point but I can't.
Your motivation is to help newbies and you've acknowledged my answering first - I'm happy with that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.