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

Hi monks, Once again back with a problem. I am reading from a file in which each line contains staremnet in the form
$step1 1 $step2 1 $step3 1
Now I am ryng to read this file and initialize some variables in my code but the variables are not getting initialized.Some problem is there with my logic..plz help me out..I am writting a sample code for your conviniennce
#!/usr/bin/perl my $step1; my $step2; my $step3; my @array1; my @array; my $i = 0; open(FILE, "assign"); $line = <FILE>; while ($line ne ""){ chomp($line); if($line =~ /^(\S+)\s+(\d+)$/) { print "inside\n"; $hash{$1} = $2; $i++; } $line = <FILE>; } while( ($key, $value) = each %hash) { print "$key +> $value\n"; $key = $value; } if($step1){ print "first\n"; } if($step2) { print "second\n"; } if($step3) { print "thisrd\n"; }
the print statement in the if loops are not getting executed and that where my problem lies

Replies are listed 'Best First'.
Re: reading from a file and initializing a variable
by davido (Cardinal) on Oct 04, 2005 at 07:01 UTC

    There are several problems here. First I'll address the big one. You really REALLY don't want to do what you think you want to do. What you are trying to do is use symbolic references. What you should do is be happy with the hash. You know, the global symbol table itself is a glorified hash too. If Perl thinks a hash is good enough for it, a hash should be good enough for you too. Don't initialize global values based on symbolic references. What if the file contained some variable name that you hadn't planned for, or one that you were using for something else? You would have a difficult to track down bug.

    The second problem is related to the first one. Symbolic references can only be used on package globals, but you've declared $step1, $step2, and $step3 to be lexical variables. That won't prevent you from initializing package globals of the same name, by the way. Imagine the confusion of having both lexicals and package globals with the same name! You're headed down that road.

    The third problem is that your $key = $value assignment simply clobbers the symbol name held in $key, it doesn't assign anything to the package global variable of that name. You can learn how to do this if you dive into the Camel book or Perl's POD, but that would mean learning how to manipulate symbolic references, which you shouldn't be doing anyway. ;)

    The fourth problem is this line:

    while ($line ne ""){ chomp($line);

    $line will never equal "". That's because it will always at least contain a "\n" newline character, except possibly for the last line. chomp first, and then test. Here's the cannonical way to do it:

    while ( $line = <FILE> ) { chomp $line; next if $line eq ""; #...... do your stuff here } # end of while loop.

    The biggest point to be made here is that instead of trying to initialize $step1, $step2, and $step3, you should be initializing $hash{step1}, $hash{step2}, and so on. Just say no to symbolic refs.


    Dave

Re: reading from a file and initializing a variable
by blazar (Canon) on Oct 04, 2005 at 07:58 UTC
    #!/usr/bin/perl
    no strict; # Yuk! no warnings; # Yuk! # s/no/use/gsm;
    my $step1; my $step2; my $step3; my @array1; my @array; my $i = 0;
    • Avoid predeclaring long lists of variables,
    • don't do this, use a hash, instead!
    open(FILE, "assign");
    open my $fh, '<', 'assign' or die "hard, but say why (\$!): $!\n";
    $line = <FILE>; while ($line ne ""){
    Huh?!? Do you mean to iterate over the lines of your file? If so... the you're not doing it. Just do it the perl idiomatic way:
    while (<$fh>) { ... # or while (my $line=<$fh>) { ...
    chomp($line); if($line =~ /^(\S+)\s+(\d+)$/) { print "inside\n"; $hash{$1} = $2;
    So you are using a hash after all! Then stop here and stick with it!! Don't try useless symref hacking...
    $i++;
    Am I missing something or are you doing... ehm! nothing, with that self mainteined counter?
    while( ($key, $value) = each %hash) { print "$key +> $value\n"; $key = $value; }
    Worth repeating: don't! (even if you knew how to do it correctly!)

    Proof of concept:

    #!/usr/bin/perl -ln use strict; use warnings; BEGIN { @ARGV='assign' } our %hash; $hash{$1}=$2 if /^(\S+)\s+(\d+)/; END { my @msg=qw/FOO 1st 2nd 3rd/; $hash{"\$step$_"} and print $msg[$_] for 1..3; } __END__
Re: reading from a file and initializing a variable
by sk (Curate) on Oct 04, 2005 at 06:58 UTC
    the print statement in the if loops are not getting executed and that where my problem lies

    which if are you talking about?

    #!/usr/bin/perl -w use strict; my $line = <DATA>; my %hash = (); while ($line) { # and $line ne ""){ chomp($line); if($line =~ /^(\S+)\s+(\d+)$/) { print "inside\n"; $hash{$1} = $2; } $line = <DATA>; } print +($_ , " -> ", $hash{$_},$/) for (keys %hash); __DATA__ $step1 1 $step2 1 $step3 1

    Output

    inside inside inside $step2 -> 1 $step3 -> 1 $step1 -> 1

    Are you sure the data does not contain leading spaces?

Re: reading from a file and initializing a variable
by gargle (Chaplain) on Oct 04, 2005 at 07:46 UTC

    UPDATE:corrected a type, I meant hash, not bash!

    Hi,

    It's doable, but, please read the other comments first: it's a whole lot better to stick with a hash!

    #!/usr/bin/perl use strict; use warnings; # but you really don't want to do this # stick with a hash! # here we have 3 vars, but what if if there's more than 3? my ($step1,$step2,$step3); while (<DATA>) { my $line = $_; chomp $line; my ($var,$val) = split / /, $line; eval "$var=$val"; } # here we have 3 vars, but what if if there's more than 3? print $step1 . "\n"; print $step2 . "\n"; print $step3 . "\n"; __DATA__ $step1 1 $step2 1 $step3 1
    --
    if ( 1 ) { $postman->ring() for (1..2); }