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

Red*_*ick 6 unicode perl utf-8

当我使用LWP :: UserAgent检索以UTF-8编码的内容时,似乎LWP :: UserAgent无法正确处理编码.

这是通过命令将命令提示符窗口设置为Unicode后的输出chcp 65001注意,这最初给出了一切都很好的外观,但我认为它只是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做正确的事情?

PS最终我想将Unicode数据转换为ASCII编码,即使它意味着用一个问号或其他标记替换每个非ASCII字符.


更新1

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

$r = decode("utf8", $r);
Run Code Online (Sandbox Code Playgroud)

更新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
  • 统一:: Map8
  • 的Unicode ::地图
  • 统一::逃生
  • 统一::音译

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

yst*_*sth 8

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