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

What's the right way to escape a string that will be encased in quotes and then handed off to a parser of some kind?

I'm generating some javascript and I want to be confidant that my quotes won't be out of whack. Here's an example of what I do not want to do.

sub alert { my $mesg = shift; print "alert('$mesg')\n"; } alert("Don't do that!");

The "'" in "Don't" will make the resulting javascript broken.

The obvious wrong solution is to replace "'" with "\'", but that would fail if I tried to be smart and called alert("Don\'t do that!") because it would turn it into "alert('Don\\'t do that)".

So, my question to you Monks is, what is the right way?

Update:

Waitaminute.. am I overthinking this..? Will

sub quote { my $str = shift; # escape all slashes $str =~ s/\\/\\\\/g; # escape all single-quotes $str =~ s/'/\\'/g; return $str; }

work?

Replies are listed 'Best First'.
Re: Quote Escape
by Lawliet (Curate) on Feb 06, 2009 at 23:58 UTC

    Perhaps quotemeta. Also, I think you should say "What is a right way?" instead of "What is the right way?" (keeping with the whole TIMTOWTDI thing :P)

    And you didn't even know bears could type.

      Good point, "What's a right way?"

      Sadly, quotemeta won't work because it will slash-escape all non word characters. So, "Don't do that" would turn out like "Don\'t\ do\ that".

Re: Quote Escape
by salazar (Scribe) on Feb 07, 2009 at 03:59 UTC
    (JavaScript, as far as I am aware, does not allow for interpolation of variables. You have to concatenate them in using the + sign. As for escaping, JS works just like you'd expect it to.)

    Am I mistaken, or will something like this work?
    sub alert { my $mesg = shift; print "alert(\"$mesg\")\n"; }
Re: Quote Escape
by roboticus (Chancellor) on Feb 07, 2009 at 06:27 UTC
    bucket o' tadpoles:

    Unfortunately, perl quoting and shell quoting and and their interrelations can be a bit tricky. I tend to cop out and do things like:

    alert("Do *not* do that!");

    Cheesy? Absolutely! But sometimes, it's (oh, I mean it is!) simpler to just avoid the apostrophe...

    ...roboticus
Re: Quote Escape
by AnomalousMonk (Archbishop) on Feb 07, 2009 at 02:31 UTC
    I'm not familiar with javascript or its quoting, escape and interpolation rules for strings. Could you provide a link to a concise reference?
Re: Quote Escape
by Anonymous Monk on Feb 07, 2009 at 05:26 UTC
      Here's example. There's a few bugs, but easy to fix
      #!/usr/bin/perl -- use strict; use warnings; use JavaScript::Code; foreach( "hey i'm message", q~h'e"'y"''"~, qq~ab&!@#$%^&*()_\n\t\nra~ # found another bug, \t\n are left as l +iterals, not legal ){ my $str = $_; $str =~ s/\n/\\n/g;#temporary workaround, easy fix for JavaScript: +:Code $str =~ s/\t/\\t/g; my $mesg = JavaScript::Code::String->new()->value($str); my $alert = JavaScript::Code::Function->new(name => 'alert'); print $alert->call($mesg)->output,"\n"; } # fixes a bug , where keeps calling ->args, but no such method # Can't locate auto/JavaScript/Code/Function/args.al in @INC (@INC con +tains: D:/Perl/site/lib D:/Perl/lib .) at D:/Perl/site/lib/JavaScript +/Code/Function.pm line 88 sub JavaScript::Code::Element::args { shift->__args(@_) } __END__ alert ( "hey i'm message" ) alert ( "h'e\"'y\"''\"" ) alert ( "ab&!@#0^&*()_\n\t\nra" )
Re: Quote Escape
by dsheroh (Monsignor) on Feb 07, 2009 at 14:41 UTC
    Perhaps escapeHTML would encode your string in a suitable format?
    perl -MCGI -e "print CGI::escapeHTML(qq(Don't do that!\n));" Don't do that!
    It's just a question of whether the JS alert would convert the ' back to an apostrophe for display.
      It wouldn't :) Data::JavaScript may help
      use Data::JavaScript; print 'alert("', Data::JavaScript::__quotemeta(qq,ab\x22q\x27uo\x27te\x22cd,), '");',"\n"; __END__ alert("ab\"q'uo'te\"cd");
      To get something you can inline
      perl -MData::JavaScript -MData::Dumper -e ' $Data::Dumper::Deparse=1; +die Dumper \&Data::JavaScript::__quotemeta '
      which you can use like
      $VAR1 = sub { package Data::JavaScript; use strict 'refs'; local $_ = shift @_; if ($OPT{'JS'} >= 1.3 and &Encode::is_utf8($_)) { s/([\x{0080}-\x{fffd}]+)/sprintf '\\u%0*v4X', '\\u', $ +1;/eg; } { use bytes; s/((?:[^ \x21-\x7E]|(?:\\(?!u)))+)/sprintf '\\x%0*v2X' +, '\\x', $1;/eg; } s/\\x09/\\t/g; s/\\x0A/\\n/g; s/\\x0D/\\r/g; s/"/\\"/g; s/\\x5C/\\\\/g; s[</script>][\\x3C\\x2Fscript\\x3E]g; return $_; }; print 'alert("', $VAR1->(qq,ab\x22q\x27uo\x27te\x22cd,), '");',"\n"; __END__ alert("ab\"q'uo'te\"cd");