variables inside a string

Discussion in 'Perl Misc' started by Martin Keiter, Dec 3, 2010.

  1. Hi,

    I would like to do something like this:

    $sentence = "$1 is here!";
    ....
    if ($string =~ m/(.*) comes in/) {
    print $sentence;
    }

    This of course does not work, as $1 is evaluated when $sentence is
    initialized. But also setting

    $sentence = "\$1 is here!"

    does not work - it just prints

    $1 is here!

    is there a way to evaluate th "$1" inside of $sentence at the time when
    $sentence is used?
     
    Martin Keiter, Dec 3, 2010
    #1
    1. Advertising

  2. Martin Keiter <> wrote:
    >is there a way to evaluate th "$1" inside of $sentence at the time when
    >$sentence is used?


    If you want to evaluate a string I suggest you look at the eval()
    function.

    jue
     
    Jürgen Exner, Dec 3, 2010
    #2
    1. Advertising

  3. Ok, I found "eval", and it works, although I do not yet fully understand
    why :)

    This does what I want:

    my $sentence = "\$1 is here!";
    my $string = "foo comes in";

    if ($string =~ m/(.*) comes in/) {
    my $code =" \"$sentence\" ";
    print "code: $code\n";
    my $bar = eval $code;
    print "$bar\n";
    }

    but do I really have to introduce this additional variable $code ?
    I tried:
    eval \"$sentence\";
    eval "$sentence";
    eval $sentence;
    but all of them produce errors...



    --
    Meine Mailadresse funktioniert!
     
    Martin Keiter, Dec 3, 2010
    #3
  4. On 03.12.2010 11:55, Martin Keiter wrote:
    > Ok, I found "eval", and it works, although I do not yet fully understand
    > why :)
    >
    > This does what I want:
    >
    > my $sentence = "\$1 is here!";

    ^^^^
    > my $string = "foo comes in";
    >
    > if ($string =~ m/(.*) comes in/) {
    > my $code =" \"$sentence\" ";

    ^^^^^^^^^^^^^^^^^^
    > print "code: $code\n";
    > my $bar = eval $code;
    > print "$bar\n";
    > }


    That's awful to read. Don't use too many \ if they can be avoided
    easily. Use q (or ') or qq instead.

    > but do I really have to introduce this additional variable $code ?
    > I tried:


    Try
    print eval qq("$sentence");

    Another way without eval is:

    sub sentence { "$1 is here" }
    .... print sentence;


    Wolf
     
    Wolf Behrenhoff, Dec 3, 2010
    #4
  5. On Dec 3, 3:55 pm, Martin Keiter <> wrote:
    [text removed]

    It may help you to check "How can I expand variables in text strings?"
    in Perl FAQ 4. Your example's harmless for educational purposes, but,
    for any serious code, be careful for any unpredictability or tainted
    text in $string (especially if it comes from an outside source). Also,
    if you use eval, check for $@. Of course, nothing beats avoiding this
    problem in the 1st place...don't have double interpolations unless
    you've a very good reason to.
     
    Krishna Chaitanya, Dec 3, 2010
    #5
  6. On Fri, 03 Dec 2010 09:32:42 +0000, Martin Keiter wrote:

    > Hi,
    >
    > I would like to do something like this:
    >
    > $sentence = "$1 is here!";
    > ...
    > if ($string =~ m/(.*) comes in/) {
    > print $sentence;
    > }
    >
    > This of course does not work, as $1 is evaluated when $sentence is
    > initialized. But also setting
    >
    > $sentence = "\$1 is here!"
    >
    > does not work - it just prints
    >
    > $1 is here!
    >
    > is there a way to evaluate th "$1" inside of $sentence at the time when
    > $sentence is used?


    $sentence =~ s/\$1/$1/;

    HTH,
    M4
     
    Martijn Lievaart, Dec 3, 2010
    #6
  7. On 2010-12-03, Krishna Chaitanya <> wrote:
    >
    > It may help you to check "How can I expand variables in text strings?"
    > in Perl FAQ 4. Your example's harmless for educational purposes, but,
    > for any serious code, be careful for any unpredictability or tainted
    > text in $string (especially if it comes from an outside source). Also,
    > if you use eval, check for $@. Of course, nothing beats avoiding this
    > problem in the 1st place...don't have double interpolations unless
    > you've a very good reason to.


    As I only today discovered "eval" I was not aware of potential dangers.
    Thank you very much for pointing that out!
    (yes, the string will come from an outside source!)

    --
    Meine Mailadresse funktioniert!
     
    Martin Keiter, Dec 3, 2010
    #7
  8. On 2010-12-03, Wolf Behrenhoff <> wrote:
    > On 03.12.2010 11:55, Martin Keiter wrote:
    >> my $code =" \"$sentence\" ";

    > ^^^^^^^^^^^^^^^^^^
    >
    > That's awful to read. Don't use too many \ if they can be avoided
    > easily. Use q (or ') or qq instead.


    yes, it is!

    >> but do I really have to introduce this additional variable $code ?
    >> I tried:

    >
    > Try
    > print eval qq("$sentence");


    looks much better - thanks!

    --
    Meine Mailadresse funktioniert!
     
    Martin Keiter, Dec 3, 2010
    #8
  9. On 2010-12-03, Martijn Lievaart <> wrote:

    > $sentence =~ s/\$1/$1/;


    this produces:
    Use of uninitialized value in substitution iterator at .//test.pl line 13.

    what I do now is:

    my $sentence = "\$1 is here!";
    my $string = "foo comes in";
    my $reg = "(.*) comes in";

    my $text = $sentence;
    if ($string =~ m/$reg/)
    {
    foreach my $i (1..9) {
    if (${$i}) {
    my $tmp = ${$i};
    $text =~ s/\$$i/$tmp/
    }
    }
    print "$text\n";
    }


    no eval any more, so it should be safe, although I find it a bit ugly.
     
    Martin Keiter, Dec 3, 2010
    #9
  10. Martin Keiter

    J. Gleixner Guest

    Martin Keiter wrote:
    > On 2010-12-03, Martijn Lievaart <> wrote:
    >
    >> $sentence =~ s/\$1/$1/;

    >
    > this produces:
    > Use of uninitialized value in substitution iterator at .//test.pl line 13.
    >
    > what I do now is:
    >
    > my $sentence = "\$1 is here!";
    > my $string = "foo comes in";
    > my $reg = "(.*) comes in";
    >
    > my $text = $sentence;
    > if ($string =~ m/$reg/)
    > {
    > foreach my $i (1..9) {
    > if (${$i}) {
    > my $tmp = ${$i};
    > $text =~ s/\$$i/$tmp/
    > }
    > }
    > print "$text\n";
    > }
    >
    >
    > no eval any more, so it should be safe, although I find it a bit ugly.


    Maybe you're making this more complex than you need to. Provided your
    example is close to your actual code you could simplify it a lot.

    if( $string =~ m/$reg/ ){ print "$1 is here"; }
     
    J. Gleixner, Dec 3, 2010
    #10
  11. Martin Keiter <> wrote:
    >Ok, I found "eval", and it works, although I do not yet fully understand
    >why :)


    Actually it is very simple.
    You just have to understand the difference between code and data.

    >This does what I want:
    >
    >my $sentence = "\$1 is here!";


    This line, including the double-quoted text is code. It is executed at
    runtime and at that moment the content of the variable becomes data.
    Obviously you cannot execute data.

    > my $bar = eval $code;


    Exception being eval(), which converts data (i.e. text) back into code,
    such that it can be executed again.

    > my $code =" \"$sentence\" ";
    >but do I really have to introduce this additional variable $code ?
    >I tried:
    >eval \"$sentence\";
    >eval "$sentence";
    >eval $sentence;
    >but all of them produce errors...


    The thingy that you pass to eval must be legal Perl code.
    $1 is here!
    is not legal Perl code.

    jue
     
    Jürgen Exner, Dec 3, 2010
    #11
  12. On 2010-12-03, J. Gleixner <> wrote:
    > Martin Keiter wrote:
    >> On 2010-12-03, Martijn Lievaart <> wrote:
    >>
    >>> $sentence =~ s/\$1/$1/;

    >>
    >> this produces:
    >> Use of uninitialized value in substitution iterator at .//test.pl line 13.
    >>
    >> what I do now is:
    >>
    >> my $sentence = "\$1 is here!";
    >> my $string = "foo comes in";
    >> my $reg = "(.*) comes in";
    >>
    >> my $text = $sentence;
    >> if ($string =~ m/$reg/)
    >> {
    >> foreach my $i (1..9) {
    >> if (${$i}) {
    >> my $tmp = ${$i};
    >> $text =~ s/\$$i/$tmp/
    >> }
    >> }
    >> print "$text\n";
    >> }
    >>
    >>
    >> no eval any more, so it should be safe, although I find it a bit ugly.

    >
    > Maybe you're making this more complex than you need to. Provided your
    > example is close to your actual code you could simplify it a lot.
    >
    > if( $string =~ m/$reg/ ){ print "$1 is here"; }


    the example is relatively close to my code, but of course I have
    simplified a bit: actually I have regexps and corresponding sentences in
    an array, and then do a test of $string against all regexps inside a
    loop. Most of the sentences will not contain a "$1", but some will.


    $test[0]{'regexp'} = "(.*) comes in";
    $test[0]{'sentence'} = "\$1 is here!";
    ....
    ....

    # actually this will come from the outside world:
    my $string = "foo comes in";

    foreach my $i (0..$#talk)
    {
    if ($string =~ m/$test[$1]{'regexp'} /)
    {
    $text = $test[$i]{'sentence'};
    # now if there is a (XXX) inside of $test[$1]{'regexp'}
    # replace $1 in $text by XXX
    }
    }
     
    Martin Keiter, Dec 3, 2010
    #12
  13. On 2010-12-03, Jürgen Exner <> wrote:
    > Martin Keiter <> wrote:
    >>Ok, I found "eval", and it works, although I do not yet fully understand
    >>why :)

    >
    > Actually it is very simple.


    So I hoped!

    > You just have to understand the difference between code and data.


    I think I did, but am quite shure, I do not yet understand all this
    quoting stuff.

    >>This does what I want:
    >>
    >>my $sentence = "\$1 is here!";

    >
    > This line, including the double-quoted text is code. It is executed at
    > runtime and at that moment the content of the variable becomes data.
    > Obviously you cannot execute data.


    agreed :)

    >> my $bar = eval $code;

    >
    > Exception being eval(), which converts data (i.e. text) back into code,
    > such that it can be executed again.


    ok.

    >> my $code =" \"$sentence\" ";
    >>but do I really have to introduce this additional variable $code ?
    >>I tried:
    >>eval \"$sentence\";
    >>eval "$sentence";
    >>eval $sentence;
    >>but all of them produce errors...

    >
    > The thingy that you pass to eval must be legal Perl code.
    > $1 is here!
    > is not legal Perl code.


    ok.
    But why does this work then?

    my $sentence = "\$1 is here!";
    my $code =" \"$sentence\" ";
    eval $code;

    is it that
    "$1 is here!"
    is passed to eval (including the quotes) and this is a valid expression?

    Thanks for your patience!
     
    Martin Keiter, Dec 3, 2010
    #13
  14. Martin Keiter

    Guest

    On 3 Dec 2010 16:09:34 GMT, Martin Keiter <> wrote:

    >On 2010-12-03, J. Gleixner <> wrote:
    >> Martin Keiter wrote:
    >>> On 2010-12-03, Martijn Lievaart <> wrote:
    >>>
    >>>> $sentence =~ s/\$1/$1/;
    >>>
    >>> this produces:
    >>> Use of uninitialized value in substitution iterator at .//test.pl line 13.
    >>>
    >>> what I do now is:
    >>>
    >>> my $sentence = "\$1 is here!";
    >>> my $string = "foo comes in";
    >>> my $reg = "(.*) comes in";
    >>>
    >>> my $text = $sentence;
    >>> if ($string =~ m/$reg/)
    >>> {
    >>> foreach my $i (1..9) {
    >>> if (${$i}) {
    >>> my $tmp = ${$i};
    >>> $text =~ s/\$$i/$tmp/
    >>> }
    >>> }
    >>> print "$text\n";
    >>> }
    >>>
    >>>
    >>> no eval any more, so it should be safe, although I find it a bit ugly.

    >>
    >> Maybe you're making this more complex than you need to. Provided your
    >> example is close to your actual code you could simplify it a lot.
    >>
    >> if( $string =~ m/$reg/ ){ print "$1 is here"; }

    >
    >the example is relatively close to my code, but of course I have
    >simplified a bit: actually I have regexps and corresponding sentences in
    >an array, and then do a test of $string against all regexps inside a
    >loop. Most of the sentences will not contain a "$1", but some will.
    >
    >
    >$test[0]{'regexp'} = "(.*) comes in";
    >$test[0]{'sentence'} = "\$1 is here!";
    >...
    >...
    >
    ># actually this will come from the outside world:
    >my $string = "foo comes in";
    >
    >foreach my $i (0..$#talk)
    >{
    > if ($string =~ m/$test[$1]{'regexp'} /)
    > {
    > $text = $test[$i]{'sentence'};
    > # now if there is a (XXX) inside of $test[$1]{'regexp'}
    > # replace $1 in $text by XXX
    > }
    >}


    If you going to use eval, you could always use the suggs posted
    by others with something like this.

    -sln

    use strict;
    use warnings;

    my @template = (
    { regexp => q{(.*) comes in},
    sentence => qq{"\$1 is here!\\n"}
    },
    { regexp => q{(.*) sometimes comes in},
    sentence => qq{"\$1 is sometimes there!\\n"}
    },
    );

    my @instrings = (
    'foo comes in here',
    'bar sometimes comes in',
    'baz comes in here',
    );

    for my $sample (@instrings)
    {
    for my $i (0..$#template)
    {
    if ( $sample =~ /$template[ $i ]{'regexp'}/ ) {
    print eval $template[ $i ]{'sentence'};
    }
    }
    }

    __END__
     
    , Dec 3, 2010
    #14
  15. Martin Keiter

    Willem Guest

    Martin Keiter wrote:
    ) On 2010-12-03, Martijn Lievaart <> wrote:
    )
    )> $sentence =~ s/\$1/$1/;
    )
    ) this produces:
    ) Use of uninitialized value in substitution iterator at .//test.pl line 13.

    Obviously, since the substitution itself makes a new $1.

    ) what I do now is:
    )
    ) my $sentence = "\$1 is here!";
    ) my $string = "foo comes in";
    ) my $reg = "(.*) comes in";
    )
    ) my $text = $sentence;
    ) if ($string =~ m/$reg/)
    ) {
    ) foreach my $i (1..9) {
    ) if (${$i}) {
    ) my $tmp = ${$i};
    ) $text =~ s/\$$i/$tmp/
    ) }
    ) }
    ) print "$text\n";
    ) }
    )
    )
    ) no eval any more, so it should be safe, although I find it a bit ugly.

    Try this:

    if (my @matches = $string =~ m/$reg/) {
    $text =~ s/\$(\d+)/$matches[$1]/g;
    }


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Dec 3, 2010
    #15
  16. Martin Keiter

    Willem Guest

    Willem wrote:
    ) Try this:
    )
    ) if (my @matches = $string =~ m/$reg/) {
    ) $text =~ s/\$(\d+)/$matches[$1]/g;
    ) }

    Oops, off-by-one error.

    if (my @matches = $string =~ m/$reg/) {
    $text =~ s/\$(\d+)/$matches[$1-1]/g;
    }



    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Dec 3, 2010
    #16
  17. On 2010-12-03, Willem <> wrote:
    > Willem wrote:
    > ) Try this:
    > )
    > ) if (my @matches = $string =~ m/$reg/) {
    > ) $text =~ s/\$(\d+)/$matches[$1]/g;
    > ) }
    >
    > Oops, off-by-one error.
    >
    > if (my @matches = $string =~ m/$reg/) {
    > $text =~ s/\$(\d+)/$matches[$1-1]/g;
    > }
    >


    That's good:
    - it works
    - I understand how it works
    - it does not use eval :)

    thank you!
     
    Martin Keiter, Dec 3, 2010
    #17
  18. On 2010-12-03, <> wrote:

    > If you going to use eval, you could always use the suggs posted
    > by others with something like this.
    >
    > -sln
    >
    > use strict;
    > use warnings;
    >
    > my @template = (
    > { regexp => q{(.*) comes in},
    > sentence => qq{"\$1 is here!\\n"}
    > },
    > { regexp => q{(.*) sometimes comes in},
    > sentence => qq{"\$1 is sometimes there!\\n"}
    > },
    > );


    I definitely have to learn about all this quoting! (you don't need to
    explain it - I'll read and learn!

    > my @instrings = (
    > 'foo comes in here',
    > 'bar sometimes comes in',
    > 'baz comes in here',
    > );
    >
    > for my $sample (@instrings)
    > {
    > for my $i (0..$#template)
    > {
    > if ( $sample =~ /$template[ $i ]{'regexp'}/ ) {
    > print eval $template[ $i ]{'sentence'};
    > }
    > }
    > }


    this also works. But is it not dangerous if the instrings are provided
    by potentially dangerous users?
     
    Martin Keiter, Dec 3, 2010
    #18
  19. Martin Keiter

    Guest

    On 3 Dec 2010 18:31:34 GMT, Martin Keiter <> wrote:

    >On 2010-12-03, <> wrote:
    >
    >> If you going to use eval, you could always use the suggs posted
    >> by others with something like this.
    >>
    >> -sln
    >>
    >> use strict;
    >> use warnings;
    >>
    >> my @template = (
    >> { regexp => q{(.*) comes in},
    >> sentence => qq{"\$1 is here!\\n"}
    >> },
    >> { regexp => q{(.*) sometimes comes in},
    >> sentence => qq{"\$1 is sometimes there!\\n"}
    >> },
    >> );

    >
    >I definitely have to learn about all this quoting! (you don't need to
    >explain it - I'll read and learn!
    >
    >> my @instrings = (
    >> 'foo comes in here',
    >> 'bar sometimes comes in',
    >> 'baz comes in here',
    >> );
    >>
    >> for my $sample (@instrings)
    >> {
    >> for my $i (0..$#template)
    >> {
    >> if ( $sample =~ /$template[ $i ]{'regexp'}/ ) {
    >> print eval $template[ $i ]{'sentence'};
    >> }
    >> }
    >> }

    >
    >this also works. But is it not dangerous if the instrings are provided
    >by potentially dangerous users?


    Eval in itself is not dangerous, its what's in the eval after its code.
    If, after its code, its result is a STRING scalar as opposed to bareword functions,
    thats all it is. It depends on how you quote it.

    Consider this:

    print eval qq{"system(\\"dir aa.*\\");\\n"};
    print eval qq{system("dir aa.*");};

    I think the first cannot be executed, so if you set up
    'sentence' by qq{ " <capture from user> "} you are quoting "" and it
    ( here ^ and here ^ )
    is a scalar.
    Anyway, thats the theory I think, but there could be oddities I guess.

    -sln
     
    , Dec 3, 2010
    #19
  20. Martin Keiter

    Guest

    On Fri, 03 Dec 2010 11:18:25 -0800, wrote:

    >On 3 Dec 2010 18:31:34 GMT, Martin Keiter <> wrote:
    >
    >>On 2010-12-03, <> wrote:
    >>
    >>> If you going to use eval, you could always use the suggs posted
    >>> by others with something like this.
    >>>

    [...]
    >>this also works. But is it not dangerous if the instrings are provided
    >>by potentially dangerous users?

    >
    >Eval in itself is not dangerous, its what's in the eval after its code.
    >If, after its code, its result is a STRING scalar as opposed to bareword functions,
    >thats all it is. It depends on how you quote it.
    >
    >Consider this:
    >
    > print eval qq{"system(\\"dir aa.*\\");\\n"};
    > print eval qq{system("dir aa.*");};
    >
    >I think the first cannot be executed, so if you set up
    >'sentence' by qq{ " <capture from user> "} you are quoting "" and it
    > ( here ^ and here ^ )
    >is a scalar.
    >Anyway, thats the theory I think, but there could be oddities I guess.
    >


    I'm going to have to backtrack on this whole thing.
    So forget everything I said with the eval "" format.
    It is not safe at all if using external, possibly malicious data.

    The docs say that eval BLOCK is compiled only once. But that won't
    do any good for dynamic variable substitution ala \$var.
    The eval "" form will recompile every time.

    The fact is that if a user knows (or guesses) your statement form,
    he/she will be able to splice in code, in any construction of eval "".

    I see no way around it, it is dangerous, so use another method.
    Test case:

    my $val = ").system('dir a*.*').qq(";
    eval "print qq($val)";

    -sln
     
    , Dec 4, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andy Eshtry
    Replies:
    0
    Views:
    628
    Andy Eshtry
    Mar 1, 2004
  2. Dave
    Replies:
    0
    Views:
    805
  3. DC Gringo
    Replies:
    4
    Views:
    4,825
    mfreidge
    Dec 17, 2007
  4. Replies:
    9
    Views:
    955
  5. arnuld

    Finding a string inside string

    arnuld, Nov 23, 2010, in forum: C Programming
    Replies:
    3
    Views:
    348
    Dann Corbit
    Nov 23, 2010
Loading...

Share This Page