Perl's YAML :: XS и Unicode - PullRequest
       7

Perl's YAML :: XS и Unicode

3 голосов
/ 19 июня 2011

Я пытаюсь использовать модуль perl YAML::XS для букв в юникоде, и он не работает должным образом.

Я пишу это в сценарии (который сохраняется в utf-8)1004 *

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;

Вместо чего-то вменяемого печатается -: Å.Согласно этой ссылке , все должно работать нормально.

Да, когда я YAML::XS::Load вернул его, я снова получил правильные строки, но мне не нравится тот факт, что сброшенная строка, кажется, находится в некоторой неправильной кодировке.делать что-то не так?Я всегда не уверен насчет юникода в perl, если честно ...

уточнение: моя консоль поддерживает UTF-8.Кроме того, когда я печатаю его в файл, открытый с помощью ручки utf8 с open $file, ">:utf8" вместо STDOUT, он все равно не печатает правильные буквы utf-8.

Ответы [ 3 ]

7 голосов
/ 19 июня 2011

Да, вы делаете что-то не так.Вы неправильно поняли, что означает ссылка, которую вы упомянули .Dump & Load работа с необработанными байтами UTF-8;то есть строки, содержащие UTF-8, но с выключенным флагом UTF-8 .

Когда вы печатаете эти байты в дескриптор файла со слоем :utf8, они интерпретируются как Latin-1 ипреобразован в UTF-8, производя двойной кодированный вывод (который может считываться успешно, пока вы дважды декодируете его).Вместо этого вы хотите binmode STDOUT, ':raw'.

Другой вариант - вызвать utf8 :: decode в строке, возвращаемой Dump.Это преобразует необработанные байты 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.

2 голосов
/ 19 июня 2011

Работает, если вы не используете binmode STDOUT, ":utf8";.Только не спрашивай меня почему.

1 голос
/ 06 июля 2013

Я использую следующее для utf-8 JSON и YAML. Нет обработки ошибок, но могу показать, как это сделать. Ниже позволяет мне:

  • использует нормализацию NFC на входе и NO NDF на выходе. Просто используя все в NFC
  • может редактировать файлы YAML / JSON с помощью инструментов vim и bash с поддержкой utf8
  • "внутри" Perl работает как \w регулярные выражения и lc uc и так далее (по крайней мере, для моих нужд)
  • исходный код - utf8, поэтому можно писать регулярные выражения /á/

Моя "жаровня" ...

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

---
á: ä
č: ď
é: ě
í: ĺ
ľ: ň
ó: ô
ö: ő
ŕ: ř
š: ť
ú: ů
ü: ű
ý: ž
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...