Когда я использую 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».