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

HI,
I have this code and below mentioned are the actual and expected results
use strict; my($a,$b,$c,$d); my $str="a b c d"; if($str=~m/(\S)\s(\S)\s(\S)\s(\S)/) { ($a,$b,$c,$d)=map {eval(\$$_)} (1..4);} print $a,"\n",$b,"\n",$c,"\n",$d;
Actual result:
Can't use string ("1") as a SCALAR ref while "strict refs" in use at .... line 6.

Expected result:
a
b
c
d


Awaiting your replys

Replies are listed 'Best First'.
Re: Can't use string ("1") as a SCALAR ref while "strict refs" in use
by almut (Canon) on Mar 09, 2010 at 15:19 UTC
    ($a,$b,$c,$d)=map {eval(\$$_)} (1..4);}

    You probably meant

    ... = map {eval "\$$_"} (1..4);

    i.e. you want to evaluate the strings '$1', etc., which you get by interpolating $_ into the double-quoted expression "\$$_".  In this case it would also run under strict.

    That said, I agree with Corion that there are better ways to achieve the same...

Re: Can't use string ("1") as a SCALAR ref while "strict refs" in use
by Corion (Patriarch) on Mar 09, 2010 at 15:00 UTC

    What part of

    Can't use string ("1") as a SCALAR ref while "strict refs" in use at . +... line 6.

    do you have a problem with? You seem to be trying to use symbolic references for a really minor task, and strict forbids that, for good reason.

    Most likely, you wanted:

    my %values = ( a => 'value a', b => 'value b', c => 'value c', d => 'value d', ); if( $str=~ m/(\S)\s(\S)\s(\S)\s(\S)/) { my @captured = ($1, $2, $3, $4); ($a,$b,$c,$d)= map { $values{ $_ } || $_ } @captured; }; print $a,"\n",$b,"\n",$c,"\n",$d;

    Maybe you want to use a real templating system instead.

      This is the part of my actual code:
      .............. if($body_text=~m/Opening Balance (.*) Net Transaction (.*) Cash Total +(.*) Card Total (.*) Cheque Total (.*) Grand Total ([^ ]*) /) { $open_bal=join "",split ",",substr($1,1); $net_trx=join "",split ",",substr($2,1); $cash_total=join "",split ",",substr($3,1); $card_total=join "",split ",",substr($4,1); $cheque_total=join "",split ",",substr($5,1); $grand_total=join "",split ",",substr($6,1); print "Open Balance: ",$open_bal,"\n"; print "Net Transaction: ",$net_trx,"\n"; print "Cash Total: ",$cash_total,"\n"; print "Card Total: ",$card_total,"\n"; print "Cheque Total: ",$cheque_total,"\n"; print "Grand Total: ",$grand_total,"\n"; } .....................

      I just wanted to shorten the code using this line instead
      ($open_bal,$net_trx,$cash_total,$card_total,$cheque_total,$grand_total +)=join "",split ",",substr($$_,1) for (1..6);

      May be im doing something awkward
      :)
        if ( my ($open_bal, $net_trx, $cash_total, $card_total, $cheque_total, $grand_total) = $body_text =~ / Opening[ ]Balance[ ](.*)[ ]Net[ ]Transaction[ ](.*)[ ] Cash[ ]Total[ ](.*)[ ]Card[ ]Total[ ](.*)[ ] Cheque[ ]Total[ ](.*)[ ]Grand[ ]Total[ ]([^ ]*) /x ) { tr/$,//d for $open_bal, $net_trx, $cash_total, $card_total, $cheque_total, $grand_total; print ... }
        Update: I hadn't escaped all the spaces. Fixed.

        This may also work:

        if ( my ($open_bal, $net_trx, $cash_total, $card_total, $cheque_total, $grand_total) = $body_text =~ /\$(\S+)/g ) { tr/,//d for $open_bal, $net_trx, $cash_total, $card_total, $cheque_total, $grand_total; print ... }

        With both this solution and the original solution, you can use apply to shorten the code.

        use List::MoreUtils qw( apply ); if ( my ($open_bal, $net_trx, $cash_total, $card_total, $cheque_total, $grand_total) = apply { tr/,//d; } $body_text =~ /\$(\S+)/g ) { print ... }
        You most certainly are doing something not only awkward, but pointless. Matching in a list context returns the contents of the match variables as a list in numerical order. You should assign that to an array or list of scalars (ikegami's solution right here is a list of scalars). You gain absolutely nothing by delving into the bottomless pit of symbolic references in this case.
      Why not split?
      my($foo, $bar, $baz, $quux) = split /\s+/, $str;
      Plus it is easy to change that one line if your input format changes. Better yet:
      # Change this line if the number of entries changes. use constant ENTRIES_PER_LINE => 4; ... my @entries = split /\s+/, $str; if (@entries != ENTRIES_PER_LINE) { warn "Wrong number of entries: '$str' at line $.\n"; } else { # And update this one as well. my($foo, $bar, $baz, $quux) = @entries; # continue with your code }
      You could also capture the entries into a hash once the split is done:
      ... my %template_value_for; my @fields = qw(foo bar baz quux); @template_value_for{@fields} = @entries;
      And now $template_value_for{foo} has field 1, and so on.
Re: Can't use string ("1") as a SCALAR ref while "strict refs" in use
by ikegami (Patriarch) on Mar 09, 2010 at 15:24 UTC
    use strict; my $str="a b c d"; if(my($a,$b,$c,$d) = $str =~ m/(\S)\s(\S)\s(\S)\s(\S)/) { print $a,"\n",$b,"\n",$c,"\n",$d; }