Perl 为什么使用非拉丁字母区域设置进行编码::解码会在本地化strftime输出上爆炸?

Perl 为什么使用非拉丁字母区域设置进行编码::解码会在本地化strftime输出上爆炸?,perl,utf-8,locale,Perl,Utf 8,Locale,在使用Perl 5.26.1的Ubuntu上,我在使用Dancer::Logger::Console时遇到了以下问题。我已经把这个密码从你的电脑里取出来了 要运行此操作,您需要生成以下区域设置: 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 Enc

在使用Perl 5.26.1的Ubuntu上,我在使用Dancer::Logger::Console时遇到了以下问题。我已经把这个密码从你的电脑里取出来了

要运行此操作,您需要生成以下区域设置:

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.
当使用德语语言环境运行时,它会成功(但会抛出一个宽字符警告,在本测试中我们可以忽略该警告)

%b
格式是缩写为本地化单词的月份(请参阅)

如果我们不
Encode::decode(“UTF-8”,…)
,它就可以工作,上面的韩语版本会产生
3월


这里发生了什么?

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)';

提示:我使用了
sprintf”%vX“
检查字符串的字符。Data::Dumper with
Useqq=1
也可以做到这一点。我对区域设置的经验很少,所以我的回答仅限于以下几点:在进行任何更改之前,确保使用不基于UTF-8的区域设置进行测试。很好,我不知道
-C
标志。如果有人想知道,请参阅:“C标志控制一些Perl Unicode特性。”,然后是“S”=stdin/out/err utf8,“D”=in/out streams utf8,“A”=@ARGV utf8.@simbabque我想说,尝试解码strftime的输出肯定是个bug。|如果有用的话,我制作了一个编码包装器,希望它具有更合理的函数,您可以在抛出异常和替换字符之间进行选择(至少,您可以查看它的源代码以了解如何正确地做到这一点):@Grinnz,请记住,直到最近,Perl对UTF-8语言环境的处理还是非常糟糕的。(5.20?)也许现在是个bug,但以前不是。所以,让我完善一下我之前的评论:也在旧版本的Perl上进行测试。我已经在上提交了一个针对Dancer2问题的修复程序。
use open ':std', ':encoding(UTF-8)';