我正在尝试在unicode字母上使用perl的YAML::XS
模块,它看起来并不像它应该的那样。
我在脚本中写了这个(保存在utf-8中)
use utf8;
binmode STDOUT, ":utf8";
my $hash = {č => "ř"}; #czech letters with unicode codes U+010D and U+0159
use YAML::XS;
my $s = YAML::XS::Dump($hash);
print $s;
而不是理智的东西,-: Å
被打印出来。但是,根据this link,它应该工作正常。
是的,当我YAML::XS::Load
回来时,我再次获得了正确的字符串,但我不喜欢转储字符串似乎处于错误编码的事实。
我做错了吗?我总是不确定perl中的unicode,坦率地说......
澄清:我的控制台支持UTF-8。此外,当我将其打印到文件时,使用带有open $file, ">:utf8"
而不是STDOUT
的utf8句柄打开,它仍然无法打印正确的utf-8字母。
答案 0 :(得分:7)
是的,你做错了什么。你误解了the link you mentioned的含义。 Dump
& Load
使用原始UTF-8字节;即包含UTF-8但且UTF-8标志关闭的字符串。
当您使用:utf8
图层将这些字节打印到文件句柄时,它们会被解释为Latin-1并转换为UTF-8,从而产生双编码输出(只要您可以成功读回双重解码它)。您想改为binmode STDOUT, ':raw'
。
另一种选择是在Dump
返回的字符串上调用utf8::decode。这会将原始UTF-8字节转换为字符串(打开UTF-8标志)。然后,您可以将字符串打印到:utf8
文件句柄。
所以,
use utf8;
binmode STDOUT, ":raw";
my $hash = {č => "ř"}; #czech letters with unicode codes U+010D and U+0159
use YAML::XS;
my $s = YAML::XS::Dump($hash);
print $s;
或者
use utf8;
binmode STDOUT, ":utf8";
my $hash = {č => "ř"}; #czech letters with unicode codes U+010D and U+0159
use YAML::XS;
my $s = YAML::XS::Dump($hash);
utf8::decode($s);
print $s;
同样,从文件中读取时,您希望在:raw
模式下阅读或在字符串上使用utf8::encode
,然后再将其传递给Load
。
如果可能,您应该使用DumpFile
& LoadFile
,让YAML :: XS处理正确打开文件。但是如果你想使用STDIN / STDOUT,你将不得不处理Dump
& Load
。
答案 1 :(得分:2)
如果您不使用binmode STDOUT, ":utf8";
,则有效。只是不要问我为什么。
答案 2 :(得分:1)
我正在使用下一个用于utf-8 JSON和YAML。没有错误处理,但可以显示如何操作。 波纹管允许我:
\w
正则表达式和lc
uc
等内容(至少根据我的需要)/á/
我的“肉鸡”......
use 5.014;
use warnings;
use utf8;
use feature qw(unicode_strings);
use charnames qw(:full);
use open qw(:std :utf8);
use Encode qw(encode decode);
use Unicode::Normalize qw(NFD NFC);
use File::Slurp;
use YAML::XS;
use JSON::XS;
run();
exit;
sub run {
my $yfilein = "./in.yaml"; #input yaml
my $jfilein = "./in.json"; #input json
my $yfileout = "./out.yaml"; #output yaml
my $jfileout = "./out.json"; #output json
my $ydata = load_utf8_yaml($yfilein);
my $jdata = load_utf8_json($jfilein);
#the "uc" is not "fully correct" but works for my needs
$ydata->{$_} = uc($ydata->{$_}) for keys %$ydata;
$jdata->{$_} = uc($jdata->{$_}) for keys %$jdata;
save_utf8_yaml($yfileout, $ydata);
save_utf8_json($jfileout, $jdata);
}
#using File::Slurp for read/write files
#NFC only on input - and not NFD on output (change this if you want)
#this ensure me than i can edit and copy/paste filenames without problems
sub load_utf8_yaml { return YAML::XS::Load(encode_nfc_read(shift)) }
sub load_utf8_json { return decode_json(encode_nfc_read(shift)) }
sub encode_nfc_read { return encode 'utf8', NFC read_file shift, { binmode => ':utf8' } }
#more effecient
sub rawsave_utf8_yaml { return write_file shift, {binmode=>':raw'}, YAML::XS::Dump shift }
#similar as for json
sub save_utf8_yaml { return write_file shift, {binmode=>':utf8'}, decode 'utf8', YAML::XS::Dump shift }
sub save_utf8_json { return write_file shift, {binmode=>':utf8'}, JSON::XS->new->pretty(1)->encode(shift) }
您可以尝试下一个in.yaml
---
á: ä
č: ď
é: ě
í: ĺ
ľ: ň
ó: ô
ö: ő
ŕ: ř
š: ť
ú: ů
ü: ű
ý: ž