Конвертировать строку UTF8 в ASCII в Perl - PullRequest
12 голосов
/ 04 сентября 2010

Я перепробовал все, что порекомендовали Google и StackOverflow (что я смог найти), включая использование Encode.Мой код работает, но он просто использует UTF8, и я получаю предупреждения широких символов.Я знаю, как обойти эти предупреждения, но я не использую UTF8 для чего-либо еще, поэтому я хотел бы просто преобразовать его и не нужно адаптировать остальную часть моего кода для его решения.Вот мой код:

my $xml = XMLin($content);
# Populate the @titles array with each item title.
my @titles;
for my $item (@{$xml->{channel}->{item}}) {
    my $title = Encode::decode_utf8($item->{title});
    #my $title = $item->{title};
    #utf8::downgrade($title, 1);
    Encode::from_to($title, 'utf8', 'iso-8859-1');
    push @titles, $title;
}
return @titles;

Закомментировано, вы можете увидеть некоторые другие вещи, которые я пробовал.Я хорошо знаю, что я не знаю, что я здесь делаю.Я просто хочу закончить простой старой строкой ASCII.Любые идеи очень приветствуются.Спасибо.

Ответы [ 3 ]

19 голосов
/ 04 сентября 2010

Ответ зависит от того, как вы хотите использовать заголовок. Есть 3 основных способа:

  • Байты, представляющие строку в кодировке UTF-8.

Это формат, который следует использовать, если вы хотите хранить строку в кодировке UTF-8 вне вашего приложения, будь то на диске или при отправке по сети или что-либо за пределами вашей программы.

  • Строка символов Юникода.

Концепция символов является внутренней для Perl. Когда вы выполняете Encode::decode_utf8, то попытка преобразования байта в строку символов выполняется, как это видно из Perl. Виртуальная машина Perl (и программист, пишущий Perl-код) не могут реализовать эту концепцию, кроме как путем декодирования байтов UTF-8 на входе и кодирования их в байты UTF-8 на выходе. Например, ваша программа получает два байта в качестве входных данных, которые, как вы знаете, представляют символ (ы) в кодировке UTF-8, скажем, 0xC3 0xB6. В этом случае decode_utf8 возвращает представление, которое вместо двух байтов видит один символ: ö.

Затем вы можете приступить к манипулированию этой строкой в ​​Perl. Чтобы проиллюстрировать разницу, рассмотрим следующий код:

my $bytes = "\xC3\xB6";
say length($bytes); # prints "2"
my $string = decode_utf8($bytes);
say length($string); # prints "1"
  • Особый случай ASCII, подмножество UTF-8.

    ASCII - это очень небольшое подмножество Unicode, где символы в этом диапазоне представлены одним байтом. Преобразование Unicode в ASCII является операцией с потерями, поскольку большинство символов Unicode не являются символами ASCII. Вы либо вынуждены отбросить каждый символ в вашей строке, которого нет в ASCII, либо попытаться отобразить символ Unicode в его ближайший эквивалент ASCII (что невозможно в подавляющем большинстве случаев), когда пытаетесь привести Unicode строка в ASCII.

Поскольку у вас есть предупреждения о широких символах, это означает, что вы пытаетесь манипулировать (возможно, выводить) символами Unicode, которые не могут быть представлены как ASCII или ISO-8859-1.

Если вам не нужно манипулировать заголовком из вашего XML-документа в виде строки, я бы рекомендовал оставить его в виде байтов UTF-8 (я бы сказал, что вам следует соблюдать осторожность, чтобы не смешивать байты и символы в строках ). Если вам нужно манипулировать им, то декодируйте, манипулируйте и на выходе кодируйте его в UTF-8.

Для дальнейшего чтения используйте perldoc для изучения perlunitut, perlunifaq, perlunicode, perluniintro и Encode.

6 голосов
/ 02 февраля 2012

Хотя это старый вопрос, я просто потратил несколько часов (!), Пытаясь сделать более или менее то же самое!То есть: читать данные из XML-файла UTF-8 и преобразовывать эти данные в кодовую страницу Windows-1252 (я мог бы также использовать Latin1, ISO-8859-1 и т. Д.), Чтобы иметь возможность создавать имена файлов с ударными буквами.

После долгих экспериментов и даже еще поиска, мне, наконец, удалось заставить преобразование работать.«Хитрость» заключается в том, чтобы использовать Encode :: encode вместо Encode :: decode .

Например, учитывая код в исходном вопросе, правильный (или, по крайней мере, один :-) способ конвертации из UTF-8 будет следующим:

my $title = Encode::encode("Windows-1252", $item->{title});

или

my $title = Encode::encode("ISO-8859-1", $item->{title});

или

my $title = Encode::encode("<your-favourite-codepage-here>", $item->{title});

Я надеюсь, что это помогает другим людям, имеющим схожие проблемы!

2 голосов
/ 18 апреля 2011

Вы можете использовать следующую строку, чтобы просто избавиться от предупреждения.Это предполагает, что вы хотите использовать UTF8, что обычно не должно быть проблемой.

binmode(STDOUT, ":encoding(utf8)");

...