为什么 Encode::decode 与非拉丁字母区域设置在本地化 strftime 输出上爆炸?

Why does Encode::decode with non-latin letter locales blow up on localised strftime output?

在 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월

这是怎么回事?

ko_KR.UTF-8strftime("%b", localtime(1552997524)) returns 20.33.C6D4 下。当解释为 Unicode 代码点时,这是“␠3월”("March",前导 space)。

de_DE.UTF-8strftime("%b", localtime(1552997524)) returns 4D.E4.72 下。当解释为 Unicode 代码点时,这是“Mär”("März"、"March" 的缩写形式)。

所以似乎返回了解码文本(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)';