Почему Encode :: decode с нелатинскими буквенными локалями взрывается при локализованном выводе strftime? - PullRequest
2 голосов
/ 19 марта 2019

В Ubuntu с Perl 5.26.1 я столкнулся со следующей проблемой при работе над Dancer :: Logger :: Console.Я поднял этот код из Dancer2 :: Core :: Role :: Logger .

Чтобы выполнить это, вам нужно сгенерировать следующие локали:

sudo locale-gen de_DE.UTF-8
sudo locale-gen ko_KR.UTF-8

Этот пример кода использует корейский язык и завершается с ошибкой без сообщения об ошибке.$@ пусто.

$ LC_ALL=ko_KR.UTF-8 perl -MPOSIX -MEncode -E 'eval {
    say Encode::decode("UTF-8", strftime("%b", localtime))
  }; 
  say $@;
  '
Wide character at -e line 1.

При запуске с немецким языковым стандартом это удается (но выдает предупреждение о широком символе, которое мы можем игнорировать для этого теста).

$ LC_ALL=de_DE.UTF-8 perl -MPOSIX -MEncode -E 'eval {
    say Encode::decode("UTF-8", strftime("%b", localtime))
  }; 
  say $@;
  '
Wide character in say at -e line 2.
M�r

Форматирование %b - это сокращенный месяц как локализованное слово (см. http://strftime.net/).

. Если мы не Encode::decode("UTF-8", ...), это работает, и приведенная выше версия с корейским дает 3월.

Что здесь происходит?

1 Ответ

4 голосов
/ 19 марта 2019

Под ko_KR.UTF-8, strftime("%b", localtime(1552997524)) возвращает 20.33.C6D4. Когда интерпретируется как кодовые точки Unicode, это "& # x2420; 3 & # xC6D4;" («Март», с пробелом).

Под de_DE.UTF-8, strftime("%b", localtime(1552997524)) возвращает 4D.E4.72. Когда интерпретируется как кодовые точки Unicode, это "& # x4D; & # xE4; & # x72;" (краткая форма «Мярз», «Март»).

Таким образом, кажется, что возвращается декодированный текст (кодовые точки Unicode), что идеально Осталось только кодировать выходы.

$ LC_ALL=ko_KR.UTF-8 perl -CSD -MPOSIX -e'CORE::say strftime("%b", localtime)'
 3월

$ LC_ALL=de_DE.UTF-8 perl -CSD -MPOSIX -e'CORE::say strftime("%b", localtime)'
Mär

В программе (в отличие от однострочного) вместо -CSD можно использовать что-то вроде следующего:

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