Perl LWP :: UserAgent неправильно обрабатывает ответ UTF-8 - PullRequest
6 голосов
/ 31 декабря 2010

Когда я использую LWP :: UserAgent для извлечения контента, закодированного в UTF-8, кажется, что LWP :: UserAgent не обрабатывает кодировку правильно.

Вот вывод после установки окна командной строки в Unicode с помощьюкоманда chcp 65001 Обратите внимание, что изначально создается впечатление, что все хорошо, но я думаю, что это просто оболочка, повторно собирающая байты и декодирующая 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 без спецификации.

КакМогу ли я убедить LWP :: UserAgent сделать все правильно?

PS В конечном итоге я хочу перевести данные Unicode в кодировку ASCII, even, если это означает замену каждого не-ASCII символа на один знак вопроса или другой маркер.


Обновление 1

Я принял обновление Ysth "«Ответ - потому что я знаю, что это правильно делать, когда это возможно.Однако есть способ обойти данные в хорошо сформированную строку Perl Unicode.

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

Обновление 2

Мои данные поступают в не-Perl-приложение, котороеотображает данные с использованием кодовой страницы 437 для терминалов 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 :: Map
  • Unicode :: Escape
  • Unicode :: Transliterate

Text :: Unidecode перевел "Budějovický Budvar" в "Budejovicky Budvar" - что не показалось мне особенно впечатляющей попыткой фонетической транслитерации, но я не говорю по-чешски.Тем не менее, носители английского языка могут предпочесть его «Bud ■ jovick ■ Budvar».

1 Ответ

8 голосов
/ 01 января 2011

Обновить до новой версии libwwwperl.Старая версия, которую вы используете, учитывает только аргумент charset для decoded_content для типов содержимого text / *;более новая версия также делает это для application / xml или чего-либо, заканчивающегося + xml.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...