From: nick <http://kiev.pm.org>
Date: Mon, 27 Apr 2008 17:02:14 +0000 (UTC)
Subject: Perl JSON модули с поддержкой UTF-8
Оригинал: http://kiev.pm.org/?q=node/153
Статья представляет обзор perl модулей для работы с JSON в контексте
UTF-8. Подразумевается работа с UTF-8 на уровне символов, а не байтов.
Если нужна работа на уровне байт, то подойдет любой из
нижеперечисленных моделей, который устроит по скорости.
На CPAN существуют следующие модули:
JSON - parse and convert to JSON (JavaScript Object Notation).
JSON::XS - JSON serialising/deserialising, done correctly and fast
JSON::Syck - JSON is YAML
JSON::PC - fast JSON Parser and Converter (JSON::PC is a XS version of JSON).
JSON::DWIW - JSON converter that Does What I Want
В качестве тестовых данных будем использовать следующий JSON:
{ "hello":"Hello, u00abu043fu0440u0438u0432u0435u0442u00bbu2116 u263a. Good by." }
В JSON содержится фраза ``Hello, <<привет>> #. Good by.'', в которой
кавычки, номер и смайлик ``уникодные''. Именно как uxxxx в JSON
кодируются UTF-8 символы (http://json.org).
Этому JSON соответствует следующая Perl структура:
{ 'hello' => "Hello,
x{ab}x{43f}x{440}x{438}x{432}x{435}x{442}x{bb} x{2116}
x{263a}. Good by." }
Ну что-ж теперь приступим к тесту моделей.
Обзор модулей
JSON.
Для работы у UTF-8 в конструкторе необходимо это указать:
JSON->new(utf8 => 1);
Модуль корректно ставит UTF-8 флаги, и обратном преобразовании кодирует
UTF-8 символы. Но есть большое но: модель споткнулся на символах
кавычки елочкой.
JSON::PC.
Как указано в документации на модуль, JSON::PC является XS версией
модуля JSON, и как истинный приемник наследует туже проблему с русскими
или французскими кавычками.
Модуль сам разбирается где UTF-8, ничего явно указывать не нужно.
JSON::Syck.
Модуль JSON::Syck написан сообразительной японкой, которая заметила что
JSON по сути является YAML, и просто использовала библиотеку libsyck.
UTF-8 не поддерживается вообще, модель ориентирован на работу с
октетами, о чем честно написано в документации. Подразумевается uxxxx,
а не ImplicitUnicode опция.
JSON::XS.
А вот модуль JSON::XS показал себя достойно со всех сторон. Правда
перед преобразованием из JSON в Perl надо указать флаг utf8, а при
обратном преобразовании - флаг ascii.
Из JSON в Perl:
use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs->utf8(1);
$json_xs->decode($json_data);
Из Perl в JSON:
use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs->ascii(1);
$json_xs->encode($perl_data);
Можно также задать флаг pretty для красивого форматирования
результирующего JSON.
JSON::DWIW.
Последний модуль JSON::DWIW также ведет себе отлично, необходимо лишь в
конструкторе сообщить об UTF-8:
use JSON::DWIW;
my $json_dwiw = JSON::DWIW->new({ escape_multi_byte => 1 });
$json_dwiw->from_json($json_data);
$json_dwiw->to_json($perl_data);
Бонусы
Два пакета JSON::XS и JSON::DWIW нормально обрабатывают ситуацию, когда
передаваемая им JSON строка не является последовательностью октетов, а
является perl строкой с UTF-8 - не надо делать лишнюю проверку.
Benchmark
До этапа тестирования производительности успешно добрались лишь два
модуля: JSON::XS и JSON::DWIW, - к которым нет ни одной претензии.
Собственно тест скорости на не слишком большой структуре:
use Benchmark qw(cmpthese);
cmpthese(10000, {
'JSON::XS' => sub {
my $json_xs = JSON::XS->new();
$json_xs->utf8(1);
$json_xs->decode($json_data_u);
$json_xs->ascii(1);
$json_xs->encode($perl_data_expected)
},
'JSON::DWIW' => sub {
my $json_obj = JSON::DWIW->new({ escape_multi_byte => 1 });
$json_obj->from_json($json_data_u);
$json_obj->to_json($perl_data_expected)
},
});
Для меня вывод однозначен --- JSON::XS. Модуль ведет себя отлично с
UTF-8, корректно преобразовывает данные в Perl строки и к тому же
обладает приличной скоростью.