LINUX.ORG.RU

Покритикуйте мою сериализацию в JSON

 , ,


1

2

Понадобилось написать самобытную сериализацию в JSON. Пока вот так:

# Poor man's JSON
sub serialize {
    my ($obj) = @_;
    my $result;

    if (ref $obj eq 'HASH') {
        $result = sprintf( '{ %s }', join(', ', map {
            sprintf '"%s": %s', $_, serialize($obj->{$_})
        } keys %$obj));
    } elsif (ref $obj eq 'ARRAY') {
        $result = sprintf('[ %s ]', join(', ', map { serialize($_) } @$obj));
    } elsif (!ref $obj) {
        if ($obj =~ /^\d+$/) {
            $result = $obj;
        } else {
            $obj =~ s/(["\\])/\\$1/g;
            $obj =~ s/\r/\\r/g;
            $obj =~ s/\n/\\n/g;
            $obj =~ s/\t/\\t/g;
            $result = sprintf('"%s"', $obj);
        }
    }

    return $result;
}

Зачем каждый раз вычислять ref $obj? Зачем использовать sprintf там, где хватит простой конкатенации?

no-such-file ★★★★★
()

1) ref многократно вычисляется;

2) лишние пробелы в перловом коде;

3) лишние (или так задумано?) пробелы в JS-литералах объекта и массива;

4) проверка на наличие числа регэкспом - может юзать looks_like_number?

5) синтаксический мусор - много «скобачек»;

outtaspace ★★★
()
Ответ на: комментарий от no-such-file

Зачем каждый раз вычислять ref $obj?

Не намного дороже лишней переменной. given ... when не хочу использовать во благо обратной совместимости со старыми версиями perl.

Зачем использовать sprintf там, где хватит простой конкатенации?

Читабельнее, имхо. Подход однообразный, чтоб не было смеси конкатенаций и sprintf.

KennyMinigun ★★★★★
() автор топика
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от outtaspace

4) проверка на наличие числа регэкспом

Кстати гуглил. По спецификации числа в JSON не имеют ограничения по длинне.

5) синтаксический мусор - много «скобачек»;

И правда, можно почистить

KennyMinigun ★★★★★
() автор топика

/^\d+$/

А почему проверка числа такая примитивная? Я правда perl не знаю, но разве оно совпадет с форматами 1.1 .1 1. 1/2 1,2 и тп?

terminator-101
()
Ответ на: комментарий от KennyMinigun

По спецификации числа в JSON не имеют ограничения по длинне.

Упс. Не знал. Теперь эта тема еще интересней, посмотрю другие реализации to_json.

И правда, можно почистить

Как раз к этому меньше всего вопросов - вкусовщина. Гораздо больше вопросов к отсутствию консистентности: где-то есть проблел внутри printf, где-то он отсутствует (видимо это отсутствие и есть стиль автора).

По пункту 3 хочу увидеть комент, зачем пробелы в литералах?

outtaspace ★★★
()
Последнее исправление: outtaspace (всего исправлений: 1)
Ответ на: комментарий от KennyMinigun

По спецификации числа в JSON не имеют ограничения по длинне.

По спецификации числа в JSON могут иметь и дробную часть, и экспоненту, и знак.

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от KennyMinigun

В перле нет адекватных маппингов для этого.

Можно использовать заранее определённые константы/объекты, как здесь, например: http://search.cpan.org/~mlehmann/JSON-XS-3.01/XS.pm#PERL_->_JSON

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от terminator-101

\d соответствует цифре, \d+ — «жадному» поиску последовательности цифр, то есть по сути целому числу, поэтому твоим примерам точно не соответствует

Virtuos86 ★★★★★
()
Ответ на: комментарий от terminator-101

Да, мы это уже выяснили. там единственный формат который нужен, кроме 1 — это 1.1

А также -1.1, 0.5e12, 42.0E-100500 и проч.

/^[\d.]+$/ подойдет, кажись.

Под такую регулярку подходит ....., .00., 1.1.1.1.1… Ну ты понел.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Переписал:

} elsif ($obj =~ /^ -? \d+ (?:\.\d+)? (?:e[+-]\d+)? $/x) {
    $result = $obj;
}

Заодно обнаружил багофичу Perl:

12.34e-5.7 == 0.00012347

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от theNamelessOne

определённые константы/объекты

Такой уровень мне не нужен. Для задачи хватит, что 1 — это true

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от KennyMinigun

Кстати «юнит-тест», если кому интересно:

#!/usr/bin/env perl

use strict;
use warnings;

my @numbers = (
    1,
    2.3,
    2e+3,
    4.5e+4,
    0.89e-5,
    12.34e-56,
    12.34E-56,
    12.34e-5.7,
    88e-44,
    11e-13.66,
    0.1,
    -10,
    -0.4,
    -6.3e-7,
    'aaa',
    '10aa10',
    '10.10aaa',
    'a11e-11',
    'b88.3e-44'
);

for my $n (@numbers) {
    print "$n : ";
    if ($n =~ /^ -? \d+ (?:\.\d+)? (?:e[+-]\d+)? $/x) {
        print "NUMBER";
    } else {
        print "NOT NUMBER";
    }
    print "\n";
}

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от KennyMinigun

Кстати «юнит-тест», если кому интересно:

Вот примеры, на которых твоя регулярка валится:

  • 042 — должно быть NOT NUMBER;
  • 42e42 — должно быть NUMBER;
  • 42.42E42 — должно быть NUMBER.
theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Починил. Спасибо

/^ -? (?:0|[1-9]\d*) (?:\.\d+)? (?:[eE][+-]?\d+)? $/x

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

По 5 пункту не согласен - скобки лучше ставить всегда. Гораздо проще будет добавить вторую строку в выражение + визуальное разделение блоков

ncuxer
()
Ответ на: комментарий от ncuxer

Это вкусовщина. Если уровень подготовки программиста позволяет ему писать без скобок, то можно без них обходиться, изредка добавляя для уточнения контекста.

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

Если уровень подготовки программиста позволяет ему писать без скобок,

Дело не в уровне программиста, а у уровне целой команды общепринятых соглашений. Т.е. читаемость прежде всего. И, надо признать, стеки скобок ее ухудшают. Например:

if (defined $smth) {
    # ...
}
читается быстрее, чем
if (defined($smth)) {
    # ...
}

Казалось бы, это мелочи, но когда эти "мелочи" скапливаются — начинает болеть голова.

KennyMinigun ★★★★★
() автор топика
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от KennyMinigun

Да, читаемость важна, но не в ущерб корректности кода.

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

По пункту 3 хочу увидеть комент, зачем пробелы в литералах?

Для читаемости самого JSON. Дешево и сердито. А отступы делать сложнее.

Короче, для дебага. Потом уберу.

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от KennyMinigun

Можно и

if (defined $smth) 
    # ...

сделать, но ты будешь материться каждый раз, как тебе понадобится расширить условие под if. А круглая скобка тут лишняя, согласен (при условии что нет code convention с обратным правилом)

ncuxer
()
Ответ на: комментарий от ncuxer

Можно и

if (defined $smth) 
    # ...

А нельзя. По крайней мере в Perl.

как тебе понадобится расширить условие под if.

Процесс разработки (написания кода) уже предполагает редактирование. Оно хоть и напрягает добавлять скобки, но (в идеале) ты будешь делать гораздо больше, чем просто добавлять один стейтмент (опять же, исключения есть и я могу их сам назвать).

KennyMinigun ★★★★★
() автор топика
Последнее исправление: KennyMinigun (всего исправлений: 2)
Ответ на: комментарий от KennyMinigun

А нельзя. По крайней мере в Perl.

Упс, перл не знаю, думал, что можно. В плюсах и джаве очень не люблю стиль, когда их убирают для однострочного выражаения.

Процесс разработки (написания кода) уже предполагает редактирование. Оно хоть и напрягает добавлять скобки, но (в идеале) ты будешь делать гораздо больше, чем просто добавлять один стейтмент (опять же, исключения есть и я могу их сам назвать).

Тогда всё. Ты и сам всё знаешь :)

ncuxer
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.