Perl: строковый литерал в модуле в latin1 - я хочу utf8 - PullRequest
4 голосов
/ 14 июля 2011

В модуле Date::Holidays::DK названия определенных датских праздников пишутся в кодировке Latin1.Например, 1 января - это Nytårsdag.Что я должен сделать с $x ниже, чтобы получить правильную строку в кодировке utf8?

use Date::Holidays::DK;
my $x = is_dk_holiday(2011,1,1);

Я пробовал различные комбинации use utf8 и no utf8 до / после use Date::Holidays::DK, но, похоже, это не дает никакого эффекта.Я также пытаюсь использовать Encode decode, но не повезло.Более конкретно,

use Date::Holidays::DK;
use Encode;
use Devel::Peek;
my $x = decode("iso-8859-1", 
           is_dk_holiday(2011,1,1)
          );
Dump($x);
print "January 1st is '$x'\n";

дает вывод

SV = PV(0x15eabe8) at 0x1492a10
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK,UTF8)
  PV = 0x1593710 "Nyt\303\245rsdag"\0 [UTF8 "Nyt\x{e5}rsdag"]
  CUR = 10
  LEN = 16
January 1st is 'Nyt sdag'

(с недопустимым символом между t и s).

Ответы [ 2 ]

4 голосов
/ 14 июля 2011

используйте utf8 и не используйте utf8 до / после использования Date :: Holidays :: DK, но, похоже, это не имеет никакого эффекта.

Правильно. Прагма utf8 указывает только на то, что исходный код программы написан на UTF-8.

Я также попытался использовать декодирование Encode, но безуспешно.

Вы не правильно поняли это, вы на самом деле поступили правильно. Теперь у вас есть строка символов Perl, и вы можете манипулировать ею.

с недопустимым символом между t и s

Вы также неверно истолковываете это, на самом деле это символ å.


Вы хотите вывести UTF-8, поэтому вам не хватает шага кодирования.

my $octets = encode 'UTF-8', $x;
print $octets;

Пожалуйста, прочитайте http://p3rl.org/UNI для введения в тему кодирования. Вы всегда должны декодировать и кодировать, явно или косвенно.

2 голосов
/ 14 июля 2011

use utf8 только подсказка интерпретатору / компилятору perl, что ваш файл имеет кодировку UTF-8.Если у вас есть строки с установленным старшим битом, он автоматически закодирует их в Unicode.

Если у вас есть переменная, которая закодирована в iso-8859-1, вы должны ее декодировать.Тогда ваша переменная находится во внутреннем формате Unicode.Это utf8, но вам не важно, какой perl для кодирования использует внутренне.

Теперь, если вы хотите напечатать такую ​​строку, вам нужно преобразовать строку в юникоде обратно в строку байтов.Вам нужно сделать encode для этой строки.Если вы не делаете кодирование вручную, perl само закодирует его обратно в iso-8859-1.Это кодировка по умолчанию.

Прежде чем печатать переменную $ x, вам нужно сделать $x = encode('UTF-8', $x) для нее.

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

Чтобы изменить кодировку ввода / вывода по умолчанию, вы можете использовать что-то вроде этого.

use utf8;
use open ':encoding(UTF-8)';
use open ':std';

Первая строка говорит, что вашаИсходный код закодирован в utf8.Вторая строка говорит, что каждый вход / выход должен автоматически кодироваться в utf8.Важно отметить, что open() также открывает файл в режиме utf8.Если вы работаете с двоичными файлами, вам нужно вызвать binmode() на дескрипторе.

Но вторая строка не меняет обработку STDIN, STDOUT или STDERR.Третья строка изменит это.

Вы, вероятно, можете использовать модуль utf8: all , который облегчает этот процесс.Но всегда хорошо понимать, как все это работает за кадром.

Чтобы исправить ваш пример.Один из возможных способов заключается в следующем:

#!/usr/bin/env perl
use Date::Holidays::DK;
use Encode;
use Devel::Peek;
my $x = decode("iso-8859-1", 
           is_dk_holiday(2011,1,1)
          );
Dump($x);
print encode("UTF-8", "January 1st is '$x'\n");
...