如何制作Mojolicious处理UTF-8?

时间:2018-03-18 01:17:58

标签: perl unicode utf-8

请考虑以下代码。这样我就可以在文件中获得“syswrite中的宽字符”,并在浏览器中获得垃圾:

use Mojolicious::Lite;
use Mojo::UserAgent;
use Mojo::File;

get '/' => sub {
    my $c = shift;
    my $ua  = Mojo::UserAgent->new;
    $res = $ua->get('https://...')->result;
    Mojo::File->new('resp')->spurt($res->dom->at('.some-selector')->text);
    $c->render(text => $res->body);
}

app->start;

但这种方式有效:

use Encode qw/encode_utf8 decode_utf8/;
Mojo::File->new('resp')->spurt(encode_utf8($res->dom->at('.some-selector')->text));
Mojo::File->new('resp')->spurt($res->body);
$c->render(text => decode_utf8($res->body));

你能解释一下这里发生了什么吗?为什么没有Encode模块,这两个语句不起作用?为什么第二个有效?有没有更好的方法来处理它?我已经浏览了perluniintroperlunicode,但这是我能够得到的。

1 个答案:

答案 0 :(得分:2)

我从perluniintroperlunicode和xxfelixxx link了解到的是,Unicode是一个复杂的问题。你通常不能让它正常工作。有字节(八位字节)和文本。在处理输入之前,您大部分时间都必须将字节转换为文本(decode),在输出之前,您必须执行相反的操作(encode)。如果不是第三方库,可以use open qw( :encoding(UTF-8) :std );binmode。但是对于第三方库,您并不总是能够这样做。

因此,$res->body是字节,$res->text是从响应中指定的编码解码的文本。 $res->dom需要$res->text作为输入。因此,$res->dom->at('.some-selector')->text是文本,Mojo::File->new(...)->spurt()期望得到字节。所以你别无他法,只能使用UTF-8对其进行编码。顺便说一下,utf8不是UTF-8。后者更安全,因此您最好使用encode / decode函数。

然后,$c->render(text => ...);需要文本,而不是字节。所以你要么必须decode('UTF-8', $res->body),要么通过$res->text