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

Monks,

I am a little more experienced than a newbie, but I need help with s///. Here is my code:

#!/usr/local/bin/perl use strict; my $a; $a = "$$NETOBJ.parameter"; $a =~ s/\$\$NETOBJ\.//; print $a;
The output of this code is: .parameter

I was expecting: parameter

Can someone tell me why the \ didn't escape the . ?

Thanks,
Tii

Replies are listed 'Best First'.
Re: Need help with s///
by ZZamboni (Curate) on Jul 14, 2000 at 22:24 UTC
    The substitution is never happening, that's why. And there must be something else you omitted, because as shown, your code does not run because the $NETOBJ variable is not declared anywhere. Removing the "use strict" makes it run, and running it with the -w flag (always use -w and strict!) shows you the problem:
    Name "main::NETOBJ" used only once: possible typo at t.pl line 6. Use of uninitialized value in scalar dereference at t.pl line 6. Use of uninitialized value in concatenation (.) at t.pl line 6.
    Ok, here's what is happening:
    • Because "$$NETOBJ.parameter" is in double quotes, Perl is interpreting $NETOBJ as a variable, and trying to interpolate its value. Because it doesn't have a value, you get an undef value.
    • Now, the first "$" in "$$NETOBJ" is also interpolated by perl, trying to interpret it as a dereference to $NETOBJ (this is, if $NETOBJ contained a reference to a scalar value, $$NETOBJ would dereference it and give you the value). Because $NETOBJ is undef, the dereferencing fails too, This produces the "Use of uninitialized value in scalar dereference" error.
    • At this point $a contains already ".parameter".
    • The substitution is escaped correctly, therefore it looks for the string '$$NETOBJ'. But that string is not there, therefore the substitution doesn't happen, and you get ".parameter" as your final result
    The solution if you want the literal string '$$NETOBJ' in $a is to use single quotes instead of double quotes. The single quotes prevent interpolation. Like this:
    $a='$$NETOBJ.parameter';

    --ZZamboni

      Thanks to everyone for their helpful responses.
      Actually, I was trying to keep my post brief, but I ended up leaving out too much information and still getting helpful information, but not the exact information I was seeking.

      Ok, here's the story:
      I'm parsing a config file and I'm running into a parameter that has a value like $$NETOBJ.parameter. I want to remove the $$NETOBJ. part and be left with parameter. The code I submitted earlier was a little test that I had put together, but I mistyped it. Here is my test program as I was using it:

      #!/usr/local/bin/perl $a = "$$NETOBJ.parameter"; $a =~ s/\$\$NETOBJ\.//; print $a;
      Earlier, I typed use strict; out of habit. I usually use it, but left it out for this small example.
      What the code above gives me is .parameter. My question is: Why doesn't my regexp remove the dot? I don't need to know how to create the value because I'm already reading it from the config file. I need to know how to remove the dot.

      Sorry again for not being more specific. Thank you all for your feedback.

      Tii

        The regex doesn't remove the dot because the regex doesn't match. Let's make two small changes:
        #!/usr/local/bin/perl -w $a = "$$NETOBJ.parameter"; print ">>$a<<\n"; $a =~ s/\$\$NETOBJ\.//; print $a;
        You might also write it this way:
        $a = "$$NETOBJ.parameter"; if ($a =~ s/\$\$NETOBJ\.//) { print $a; } else { print "Substitution failed.\n"; }
        One other approach that may work for you is split:
        $a = '$$NETOBJ.parameter'; (undef, $a) = split(/\./, $a, 2); print $a;
        Of course, notice the single quotes in the declaration that time. That'll help even if you do use the regexp.
Re: Need help with s///
by mrmick (Curate) on Jul 14, 2000 at 22:20 UTC
    Actually, I tried your example and got the following:
    Global symbol "$NETOBJ" requires explicit package name at F:\reg.pl li +ne 7. Execution of F:\reg.pl aborted due to compilation errors.
    It seems as though it was trying to interpolate the variable in the double quoted string. Once I replaced the "s with 's , the program ran and gave the following output:
    parameter
    Here's the change:
    $a = '$$NETOBJ.parameter';
    Mick
Re: Need help with s///
by c-era (Curate) on Jul 14, 2000 at 22:17 UTC
    Your regex is fine, but you didn't escape the $$ initialy. This works for me.
    use strict; my $a; $a = "\$\$NETOBJ.parameter"; $a =~ s/\$\$NETOBJ\.//; print $a;
Re: Need help with s///
by Abigail (Deacon) on Jul 15, 2000 at 00:02 UTC
    That's pretty amazing that your program pretty anything at all, as I cannot get it to compile. Are you sure you have the use strict; there? Because that should tell you what you are doing wrong.

    -- Abigail

Re: Need help with s///
by target (Beadle) on Jul 15, 2000 at 00:51 UTC
    I LOVE PERL, so many different ways to get the same result. The single quotes turn off the interpolation as ZZamboni and mrmick offered and so does escaping both of the $'s as c-era offered.
RE: Need help with s///
by Adam (Vicar) on Jul 15, 2000 at 01:59 UTC
    At this point you already have your answer, but I wanted to point out something that would have helped you find the answer faster: check your s/// call for success.
    $a =~ s/\Q$$NETOBJ.// or die "$a is not right";
    UPDATE: Abigail points out that the \Q won't prevent variable interpretation (damn) but that wasn't my point. My point was that you can only be sure a regex matched something if you check. To make Abigail happy I give you:
    $a =~ s/\$\$NETOBJ\.// or die "$a is not right";
      Actually, that would not have helped at all. The \Q will turn off interpretation of regular expression meta characters, but it will not prevent interpolation to happen. Hence, with use strict; in effect, the thing would still not compile, and without strict $$NETOBJ would be the empty string (warnings were disabled - so you don't get that error message), and the substitution would successfully remove the dot. Hence, the die would not happen.

      -- Abigail

      I believe that "$!" would make the "or die" even better, by providing information on why the regex didn't check.

      If so, that gives you:

      $a =~ s/\$\$NETOBJ\.// or die "$a is not right: $!";
Re: Need help with s///
by Anonymous Monk on Jul 15, 2000 at 17:52 UTC
    I have an even better idea. Why create a string with text, and then remove it? Just by default have the string as "parameter".
      I mentioned in my reply to ZZamboni that I was testing a program in which I was reading data from a config file. I created the string with text to simulate what I was reading from the file.

      I decided a different approach:
      I created a text file with the line $$NETOBJ.parameter in it. Then I changed my code to the following:

      #!/usr/local/bin/perl open (F, "textfile") or die "Could not open file: $!"; $a = <F>; $a =~ s/\$\$NETOBJ\.//; print $a;
      This code outputs parameter. It turns out that the way I was simulating reading text from a file was part of my problem.
      Thanks to everyone for the help.

      Humbly,
      Tii