Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

eval problem

by 7stud (Deacon)
on Dec 03, 2009 at 20:04 UTC ( [id://810927]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks,

Here is a simple program employing a simple regex match, which gives me the desired output:

use strict; use warnings; use 5.010; my $str = 'abcd'; my $pattern = '(ab)'; if ($str =~ $pattern) { my $repl = "--$1"; say '$repl: ', $repl; say 'old $str: ', $str; $str =~ s/$pattern/$repl/; say 'new $str: ', $str; } --output:-- $repl: --ab old $str: abcd new $str: --abcd

When I get the pattern from the command line, the result is the same:

my $str = 'abcd'; my $pattern = shift; if ($str =~ $pattern) { my $repl = "--$1"; say '$repl: ', $repl; say 'old $str: ', $str; $str =~ s/$pattern/$repl/; say 'new $str: ', $str; } --output:-- $ perl 2perl.pl '(ab)' $repl: --ab old $str: abcd new $str: --abcd

But if I also get the replacement from the command line, then there is a problem:

my $str = 'abcd'; my $pattern = shift; if ($str =~ $pattern) { my $repl = shift; say '$repl: ', $repl; say 'old $str: ', $str; $str =~ s/$pattern/$repl/; say 'new $str: ', $str; } --output:-- $ perl 2perl.pl '(ab)' '--$1' $repl: --$1 old $str: abcd new $str: --$1cd

I've tried using eval, but that doesn't work either:

my $str = 'abcd'; my $pattern = shift; if ($str =~ $pattern) { my $temp = shift; my $repl = eval $temp; say '$repl: ', $repl; say 'old $str: ', $str; $str =~ s/$pattern/$repl/; say 'new $str: ', $str; } --output:-- $ perl 2perl.pl '(ab)' '--$1' Use of uninitialized value $repl in say at 2perl.pl line 39. $repl: old $str: abcd Use of uninitialized value $repl in substitution (s///) at 2perl.pl li +ne 42. new $str: cd

How can I get perl to evaluate the replacement string in the context of my program? Note: I also tried the /e and /ee modifiers for s/// with no luck.

Replies are listed 'Best First'.
Re: eval problem
by ikegami (Patriarch) on Dec 03, 2009 at 20:17 UTC
    my $repl = "--$1"; === my $repl = '--'.$1; my $repl = shift; === my $repl = '--$1'; my $repl = eval shift; === my $repl = --$1; === Modification of a read-only value my $repl = eval qq{"$temp"}; === my $repl = "--$1"; === my $repl = '--'.$1;

    You should have checked if the eval succeeded.

    And inside an a substitution:

    s/.../eval qq{"$temp"}/e

    I hate hiding an eval EXPR as /ee. It's too dangerous to hide, and it prevents you from checking if the eval succeeded.

      Thanks. I don't understand this error:

      Modification of a read-only value

      I don't see how I'm trying to modify $1.

      You should have checked if the eval succeeded.

      I read the docs on eval(), and I have no idea what it does. I know what eval does in other languages, but I couldn't get a single example using eval to work in perl. The examples in the docs are really poor.

        Your evaluating --$1, where -- is the predecrement operator.

        I read the docs on eval(), and I have no idea what it does

        Seems pretty straight forward to me

        [For eval EXPR], the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program.

        As for errors,

        If there is a syntax error or runtime error, or a die statement is executed, eval returns an undefined value in scalar context or an empty list in list context, and $@ is set to the error message. If there was no error, $@ is guaranteed to be a null string.

        I couldn't get a single example using eval to work in perl.

        $ perl -le'print "Hello, World!";' Hello, World! $ perl -le'eval q{print "Hello, World!";};' Hello, World!
        The difference is that you can build the code dynamically
        $ perl -le'print "3$ARGV[0]4";' + 3+4 $ perl -le'print eval "3$ARGV[0]4"' + 7 $ perl -le'print eval "3$ARGV[0]4"' '*' 12

        Be careful about using external inputs:

        $ perl -le'print $ARGV[0]' '`rm -i *`' `rm -i *` $ perl -le'print eval $ARGV[0]' '`rm -i *`' rm: remove regular file `demo.pl'? ^C
Re: eval problem
by AnomalousMonk (Archbishop) on Dec 04, 2009 at 01:52 UTC
Re: eval problem
by bv (Friar) on Dec 04, 2009 at 04:25 UTC

    I'm sure you've gotten all the info you needed about eval, but if you use lookaheads, you could make this work without needing to specify captures (with parentheses) in your $pattern. (I'm assuming you don't want to define $repl based on user input, but it could be made to work that way too)

    #untested, but should work my $str = 'abcd'; my $pattern = shift; if ($str =~ $pattern) { my $repl = shift; say '$repl: ', $repl; say 'old $str: ', $str; $str =~ s/(?=$pattern)/$repl/; say 'new $str: ', $str; } __END__ $ perl 2perl.pl 'ab' '--' $repl: -- old $str: abcd new $str: --abcd

    @_=qw; Just another Perl hacker,; ;$_=q=print "@_"= and eval;
Re: eval problem
by 7stud (Deacon) on Dec 04, 2009 at 06:29 UTC
    I don't know why you used sprintf in any of the examples. 
    You do realize that
    
    '...'
    
    is just as much an expression as
    
    sprintf('%s', '...')
    
    right? 
    

    I tried evaling a string first, but it didn't work, so to be absolutely certain about what was happening I used sprintf. Now I understand that q{} is an operator that returns a string.

    
    Not true. eval EXPR doesn't spit out errors. It places them in $@ and you didn't even check $@.

    Jesus Christ, all these $ variables--I didn't even know there was such a thing. Now, I see that $@ is like a 'catch' to an eval BLOCK's 'try'.

    What you're missing is that Perl programs are compiled and executed in their own scope, usually called "file scope".

    Well, I would hope so. What else is there?
    $ perl -E'use strict; my $x = 10; eval q{ my $y = $x; }; say $y' Global symbol "$y" requires explicit package name at -e line 1. Execution of -e aborted due to compilation errors.

    But the docs say:

    The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren’t any errors, executed in the lexical context of the current Perl program, so that any variable settings or subroutine and format definitions remain afterwards.

    In my opinion, your examples prove that the bolded part is false. In actuality, eval EXPR acts like EXPR is evaluated inside a block, and the block is nested inside the main program. Therefore my variables do not survive the end of the block.

    Don't try to apply the docs for eval EXPR to eval BLOCK at all.

    I wasn't. I was trying to apply the eval BLOCK docs to eval BLOCK.

    eval BLOCK is a completely different operator. In Java, C++ and Perl6, it's known as try.

    Well, that explains the baffling behavior of eval BLOCK.
    I missed this question of yours originally
    
    Or, is it that eval() only does one pass of interpolation over "$temp"
    
    eval EXPR doesn't interpolate. It parses and executes the Perl code it is provided.
    
    As for Perl, it doesn't interpolate recursively. Nothing I know does. (Perl, bash, Template-Toolkit, ...) 
    quotemeta would become the most used function if it did.

    Yes, instead of this:

    And when "$temp" is eval()'ed wouldn't the qq{} operator around $temp return a string with the $variables interpolated? Or, is it that eval() only does one pass of interpolation over "$temp"...

    I should have said:

    And when "$temp" is eval()'ed wouldn't the qq{} operator around $temp return a string with the $variables interpolated? Or, is it that the qq{} operator only does one pass of interpolation over "$temp" when "$temp" is eval()'ed.

    =================

    I'm sure you've gotten all the info you needed about eval, but if you use lookaheads, you could make this work without needing to specify captures (with parentheses) in your $pattern.

    Very clever. Thanks.

    ============

    ikegami's replies have pretty well covered this question, but for further discussion of template evaluation in a substitution replacement (which is what I take the OP to be about), see nodes printig with variables in text and simple regular expression and, with a bit of redundancy, s/// treat rhs as regex.

    Thanks. The Template solution looks like a good alternative too.

      Now I understand that q{} is an operator that returns a string.

      q{} (aka single quotes) can be viewed that way, yes. It can also be viewed as a string literal. Is it a constant, the single quote operator or the const operator? It makes no difference.

      >perl -MO=Concise,-exec -e"$_ = q{abc};" 1 <0> enter 2 <;> nextstate(main 1 -e:1) v:{ 3 <$> const[PV "abc"] s 4 <#> gvsv[*_] s 5 <2> sassign vKS/2 6 <@> leave[1 ref] vKP/REFC -e syntax OK

      Jesus Christ, all these $ variables--I didn't even know there was such a thing.

      I made a point of mentioning it in my earlier post.

      But the docs say: [...] any variable settings or subroutine and format definitions remain afterwards.

      Which of those do you think my $y is?

      eval EXPR acts like EXPR is evaluated inside a block [...] Therefore my variables do not survive the end of the block.

      Yes. Lexicals created in the file scope of the program passed to eval EXPR cease to exist at the end of the scope.

      and the block is nested inside the main program.

      Specifically, nested where the eval is located ("executed in the lexical context of the current Perl program"). That means the evaluated code can see the surrounding variables.

      I should have said: And when "$temp" is eval()'ed wouldn't the qq{} operator around $temp return a string with the $variables interpolated? Or, is it that the qq{} operator only does one pass of interpolation over "$temp" when "$temp" is eval()'ed.

      I'm confused. The example (my $temp = 'xxx$1'; my $repl = eval q{"$temp"};) didn't have a qq{}. I thought you were referring to the double quotes when you said qq{}, but now you're talking about a qq{} in addition to the quotes.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://810927]
Approved by biohisham
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-26 01:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found