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

What is the difference between s!!! and s///. I noticed that when I use
s/(^\d+[.]\s.+)/<h1>$1</h1>/g ;
it doesn't work but if I used
s!(^\d+[.]\s.+)!<h1>$1</h1>!g ;
it works. Why's that?

Replies are listed 'Best First'.
Re: s!!! vs. s///
by dws (Chancellor) on Nov 10, 2002 at 20:49 UTC
    There's a subtle trap awaiting those who use s/// to modify HTML.
    s/(^\d+[.]\s.+)/<h1>$1</h1>/g ; ^
    Escape that character, or use something other than / to delimit the substitution.

Re: s!!! vs. s///
by Zaxo (Archbishop) on Nov 10, 2002 at 20:52 UTC

    There is no real difference. The substitution op can take nearly any character as delimiter. See perlop for the rules concerning that.

    The reason your s/// fails is that you have an additional slash in the substitution string. Backwhack it (escape with \ ) to make that version work.

    s/(^\d+[.]\s.+)/<h1>$1<\/h1>/g ; # ^

    After Compline,
    Zaxo

Re: s!!! vs. s///
by Aristotle (Chancellor) on Nov 10, 2002 at 22:13 UTC
    In addition to what everyone else has said, I'll note that you can also use an opening bracket, paren or curly, and will get to use the closing ones as might seem expectable: s{(^\d+[.]\s.+)}{<h1>$1</h1>}g; in which case you can also put space between the parts
    s {(^\d+[.]\s.+)} {<h1>$1</h1>} g;
    which can be helpful for readability in complex substitutions, and esp a series of them.

    Makeshifts last the longest.

      Not just parens, braces and brackets have this property. "<>" is considered such a pair as well. And there's no need for the second pair to be the same as the first one. These are all equivalent:
      s/foo/bar/; s!foo!bar!; s(foo)(bar); s{foo}{bar}; s[foo][bar]; s<foo><bar>; s{foo}[bar];
      And: the pairs nest poperly. That means that you can use properly nested pairs inside your delimiter pair as well. The same goes for q()/qq(), to which it very similar in rules &mdqh; and that's no coincidence. So even this will work:
      s[(^\d+[.]\s.+)]<<h1>$1</h1>>g;
      (provided the original does what you want. ;-)
      For any other, unpaired delimiter inside your string, you'll have to escape it, by prepending it with a backslash.

      For the official docs, see quote and quote-like operators in perlop.

Re: s!!! vs. s///
by ClosetPacifist (Beadle) on Nov 10, 2002 at 20:54 UTC
    The /s can be any charactor that you want- you could also use s###, s\\\, or most any other charactor. The difference in your code is that, in the first, you're already using the / in the , and you'd have to change the </h1> to <\/h1>- escaping the slash- for it to work.
      you could also use s###, s\\\, or most any other charactor.

      It is probably best to reserve s\\\ for obfuscations though. :-)

      -sauoq
      "My two cents aren't worth a dime.";
      
Re: s!!! vs. s///
by pg (Canon) on Nov 10, 2002 at 23:05 UTC
    When it is true that you can almost use anything as delimiter, you have to be aware that "'" behaves differently, as it will prevent $1 being interpreted.
    s'(^\d+[.]\s.+)'<h1>$1</h1>'g;
    does NOT work as you exepcted, unless you use /e modifier.
Re: s!!! vs. s///
by pg (Canon) on Nov 10, 2002 at 23:17 UTC
    in my last reply, I mentioned /e, here I made a little trick to explain, the examples at least looks interesting to me ;-)
    $a = "1234567890"; $a =~ s/(\d)/$1 x $1/g; print $a, "\n"; $a =~ s/(\d)/$1 x $1/ge; print $a, "\n"; $a =~ s/(\d{2})/$1 x $1/g; print $a, "\n"; $a =~ s/(\d{2})/$1 x $1/ge; print $a, "\n";
    cut and paste to your kit, and try it.