当我使用LWP :: UserAgent检索以UTF-8编码的内容时,似乎LWP :: UserAgent无法正确处理编码。
这是通过命令chcp 65001
将命令提示符窗口设置为Unicode后的输出。请注意,这最初给出了一切都很好的外观,但我认为它只是shell重新组装字节并解码UTF-8,来自另一个输出你可以看到perl本身没有正确处理宽字符。
C:\>perl getutf8.pl ====================================================================== HTTP/1.1 200 OK Connection: close Date: Fri, 31 Dec 2010 19:24:04 GMT Accept-Ranges: bytes Server: Apache/2.2.8 (Win32) PHP/5.2.6 Content-Length: 75 Content-Type: application/xml; charset=utf-8 Last-Modified: Fri, 31 Dec 2010 19:20:18 GMT Client-Date: Fri, 31 Dec 2010 19:24:04 GMT Client-Peer: 127.0.0.1:80 Client-Response-Num: 1 <?xml version="1.0" encoding="UTF-8"?> <name>Budějovický Budvar</name> ====================================================================== response content length is 33 ....v....1....v....2....v....3....v....4 <name>Budějovický Budvar</name> . . . . v . . . . 1 . . . . v . . . . 2 . . . . v . . . . 3 . . . . 3c6e616d653e427564c49b6a6f7669636bc3bd204275647661723c2f6e616d653e < n a m e > B u d � � j o v i c k � � B u d v a r < / n a m e >
上面你可以看到有效载荷长度是31个字符,但Perl认为它是33。 为了确认,在十六进制中,我们可以看到UTF-8序列c49b和c3bd被解释为四个单独的字符而不是两个Unicode字符。
这是代码
#!perl use strict; use warnings; use LWP::UserAgent; my $ua = LWP::UserAgent->new(); my $response = $ua->get('http://localhost/Bud.xml'); if (! $response->is_success) { die $response->status_line; } print '='x70,"\n",$response->as_string(), '='x70,"\n"; my $r = $response->decoded_content((charset => 'UTF-8')); $/ = "\x0d\x0a"; # seems to be \x0a otherwise! chomp($r); # Remove any xml prologue $r =~ s/^<\?.*\?>\x0d\x0a//; print "Response content length is ", length($r), "\n\n"; print "....v....1....v....2....v....3....v....4\n"; print $r,"\n"; print ". . . . v . . . . 1 . . . . v . . . . 2 . . . . v . . . . 3 . . . . \n"; print unpack("H*", $r), "\n"; print join(" ", split("", $r)), "\n";
请注意,Bud.xml是UTF-8编码的,没有BOM。
我如何说服LWP :: UserAgent做正确的事?
P.S。最终我想将Unicode数据转换为ASCII编码,即使它意味着用一个问号或其他标记替换每个非ASCII字符。
我接受了Ysth的“升级”答案 - 因为我知道在可能的情况下这是正确的做法。但是,有一种方法可以将数据修复为格式良好的Perl Unicode字符串。
$r = decode("utf8", $r);
我的数据被送到非Perl应用程序,该应用程序在许多位置使用Code to Putty / Reflection / Teraterm终端显示数据。该应用目前正在显示如下内容:
Bud├ä┬øjovick├â┬¢ Budvar
我将使用($r = decode("UTF-8", $r)) =~ s/[\x80-\x{FFFF}]/\xFE/g;
来显示应用:
Bud■jovick■ Budvar
远离CP437将是一项重要工作,因此在中短期内不会发生。
CPAN有一些有趣的Unicode模块,例如:
Text :: Unidecode将“BudějovickýBudvar”翻译成“Budejovicky Budvar” - 这对我来说似乎不是一个特别令人印象深刻的语音音译尝试,但后来我不会说捷克语。说英语的人可能更喜欢“Bud■jovick■Budvar”。
答案 0 :(得分:8)
升级到较新的libwwwperl。您正在使用的旧版本仅将decode_content的charset参数用于text / *内容类型;较新版本也适用于application / xml或任何以+ xml结尾的内容。