请考虑以下代码。这样我就可以在文件中获得“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
模块,这两个语句不起作用?为什么第二个有效?有没有更好的方法来处理它?我已经浏览了perluniintro和perlunicode,但这是我能够得到的。
答案 0 :(得分:2)
我从perluniintro,perlunicode和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
。