note
Your Mother
<blockquote><i>I then run the usual on it ... It should be simple!</i></blockquote>
<p>There is a big assumption out there that this stuff is so easy that you can bypass the standard libraries. This assumption only holds if you know the dozens of related RFCs inside and out and if you do, you are going to lean on someone else's implementation anyway because it will be roughly identical functionally to anything you'd write.
</p>
<p>Using either of the standards ([mod://CGI], [mod://URI::Escape]) for this kind of thing would have saved you all that lost time and plenty more in the future.</p>
<code>
perl -MURI::Escape -le 'print uri_unescape("%C2%A3")'
£
perl -MCGI=param -le 'print param("q")' "q=%C2%A3"
£
</code>
<h4>Update</h4>
<p>
[Eliya] rightly points out that I was missing the point. So, here's a bit more answer instead of knee-jerk, use the CPAN. I am assuming the output is meant for web, though this isnít actually stated in the OP.
</p>
<p>[mod://Plack] is necessary for this but makes it super easy to try stuff soĖ</p>
<p>Plain uri_unescape, and therefore the original code snippet, is fine if you are sending the output, bytes that are utf-8, not Perl decoded strings. The response is fine because itís undecoded bytes.</p>
<code>plackup -e 'use URI::Escape; sub { [200, ["Content-Type" => "text/html; charset=utf-8"], [ uri_unescape("%C2%A3") ]]}'
HTTP::Server::PSGI: Accepting connections at http://0:5000/
--
£
</code>
<p>Now with decoding to Perlís utf-8. It doesnít work because the output needs to be encoded to bytes and youíll generally get errors or warnings to that effect.</p>
<code>plackup -e 'use Encode; use URI::Escape; sub { [200, ["Content-Type" => "text/html; charset=utf-8"], [ decode("UTF-8", uri_unescape("%C2%A3")) ]]}'
HTTP::Server::PSGI: Accepting connections at http://0:5000/
--
Error: Body must be bytes and should not contain wide characters (UTF-8 strings) at /usr/local/lib/perl5/site_perl/5.14.0/Plack/Middleware/Lint.pm line 153
</code>
<p>Now double encoded just to see because it seems to crop up a lot when mixing approaches.</p>
<code>plackup -e 'use Encode; use URI::Escape; sub { [200, ["Content-Type" => "text/html; charset=utf-8"], [ encode("UTF-8", uri_unescape("%C2%A3")) ]]}'
HTTP::Server::PSGI: Accepting connections at http://0:5000/
--
¬£
</code>
<p>And improved/corrected versions of the CGI example. Using the -utf8 arg CGI will automatically decode things for you. This is what you want so you can deal with content correctly in regular expressions and such. Itís your responsibility to make sure the output handle is UTF-8 <i>or</i> that you encode to bytes. The character is right in Perl here but wrong for the output layer.</p>
<code>perl -MCGI=param,-utf8 -le 'print param("q")' "q=%C2%A3"
?</code>
<p>Using -CO to get utf-8 on the output layer it works fine.</p>
<code>perl -CO -MCGI=param,-utf8 -le 'print param("q")' "q=%C2%A3"
£
</code>
<p>Or, encoding the utf-8 to bytes.</p>
<code>perl -MEncode -MCGI=param,-utf8 -le 'print encode("UTF-8", param("q"))' "q=%C2%A3"
£
</code>
<p>Anyway, the first answers in the thread were, taken together, all quite thorough. This was just to have a little to play with and recant my grumpy and erroneous first stab.</p>
964503
964503