Perl LWP :: UserAgent错误处理UTF-8响应

时间:2010-12-31 19:44:56

标签: perl unicode utf-8

当我使用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字符。


更新1

我接受了Ysth的“升级”答案 - 因为我知道在可能的情况下这是正确的做法。但是,有一种方法可以将数据修复为格式良好的Perl Unicode字符串。

$r = decode("utf8", $r);

更新2

我的数据被送到非Perl应用程序,该应用程序在许多位置使用Code to Putty / Reflection / Teraterm终端显示数据。该应用目前正在显示如下内容:

Bud├ä┬øjovick├â┬¢ Budvar

我将使用($r = decode("UTF-8", $r)) =~ s/[\x80-\x{FFFF}]/\xFE/g;来显示应用:

Bud■jovick■ Budvar

远离CP437将是一项重要工作,因此在中短期内不会发生。


更新3

CPAN有一些有趣的Unicode模块,例如:

  • 文本:: Unidecode
  • 的Unicode :: Map8
  • 的Unicode ::地图
  • 的Unicode ::逃生
  • 的Unicode ::音译

Text :: Unidecode将“BudějovickýBudvar”翻译成“Budejovicky Budvar” - 这对我来说似乎不是一个特别令人印象深刻的语音音译尝试,但后来我不会说捷克语。说英语的人可能更喜欢“Bud■jovick■Budvar”。

1 个答案:

答案 0 :(得分:8)

升级到较新的libwwwperl。您正在使用的旧版本仅将decode_content的charset参数用于text / *内容类型;较新版本也适用于application / xml或任何以+ xml结尾的内容。