为什么使用非拉丁字母语言环境的Encode :: decode在本地化的strftime输出上会爆炸?

时间:2019-03-19 11:49:38

标签: perl utf-8 locale

在使用Perl 5.26.1的Ubuntu上,在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 个答案:

答案 0 :(得分:4)

ko_KR.UTF-8下,strftime("%b", localtime(1552997524))返回20.33.C6D4。当解释为Unicode代码点时,它是“␠3월”(“ March”,带有前导空格)。

de_DE.UTF-8下,strftime("%b", localtime(1552997524))返回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)';