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

Hi,

I am pretty new to perl and need some ideas on how to build a regular expression to perform some substitutions, if at all possible. The input to the regular expression would be a string consisting of mathematical operations with variables '$<name>'. Basically, anytime the '$' keyword is found, replace with $sym{'$name'). Is this possible with regular expressions or do I need a parser?

eg. $x + $y = 7

$x * ($x - $y) + 10

$x + $x1 + $x2 ... = n

substitute with

$sym{'$x'} + $sym{'$y'} = 7

$sym{'$x'} * ($sym{'$x'} - $sym{'$y'}) + 10

$sym{'$x'} + $sym{'$x1'} + $sym{'$x2'} ... = n

This regular expression works for 1 letter variables, however it doesn't handle multiple vars.

$ref =~ s/(\$\S)/\$sym->{'$1'}/g;

Thanks in advance, -P

Replies are listed 'Best First'.
Re: Regular expression match and substitution
by ikegami (Patriarch) on Nov 09, 2004 at 18:19 UTC

    Change
    $ref =~ s/(\$\S)/\$sym->{'$1'}/g
    to
    $ref =~ s/(\$\S+)/\$sym->{'$1'}/g

    Of course, that won't work too well if the person uses
    $x+$y=7
    instead of
    $x + $y = 7
    so you might want to use
    $ref =~ s/(\$\w+)/\$sym->{'$1'}/g

    I presume you will later eval this string? I don't think that's a very good idea. I would indeed recommend using a parser.

      Thanks for the reply....

      I will be using eval on the string later on. However, before executing the eval I ensure that all variables have been defined. Why isn't this a good idea?

      Does eval() work on string's?

      $b = "hello"

      $strconcat = "$b_world"

      after subs...

      $strconcat = "$sym{'$b'}_world"

      <code> $tmp = eval("$sym{'$b'}_world") print "\$strconcat = $tmp\n"; <\code>

      I get the following error Use of uninitialized value in concatenation (.) or string at ./genParse.pl line 418, <DATA> chunk 1.

      Thanks!

        not "a good idea," cuz you'll be setting eval to work on what may be malicious input from user. read about untainting and generally, security.

        It's not a good idea because it's too easy to inject code. Even if the current user of the code wouldn't do so, it might eventually make its way to where an untrusted user supplies the data. A parser is the easiest way to make sure the input is safe.

        You're getting "Use of uninitialized value" error because you didn't give any value to $sym{'$b'}.

        yes, eval works on strings:

        $expr = '$x + 1'; print("$expr = "); $expr =~ s/(\$\w+)/\$sym{'$1'}/g; $sym{'$x'} = 3; $val = eval $expr; die("Bad equation: $@$/") if $@; print("$val$/");

        But please don't do that!

Re: Regular expression match and substitution
by TedPride (Priest) on Nov 09, 2004 at 22:17 UTC
    The following works without errors:
    use strict; use warnings; my %sym = ('x' => 4, 'y' => 7); while (<DATA>) { chomp; s/==/=/g; s/=/==/g; while (m/\$([a-zA-Z]\w*)/g) { $sym{$1} = 0 if ! exists $sym{$1}; } s/\$([a-zA-Z]\w*)/\$sym{'$1'}/g; print "$_ evals as " . (eval() - 0) . "\n"; } __DATA__ $x + $y = 11 $x + $y == 14 $x * ($x - $y) + 10 $x + $x1 + $x2
    Note the substitutions to fix cases of = instead of ==, and to fix instances of $sym{'key'} that don't exist. 0 is also subtracted from the eval so 0 is displayed when a bool comes out false, rather than nothing.