Comments 49
- Минимум лишних символов (никаких фигурных скобок, запятых и даже кавычек, если они явно не нужны)
- Неограниченная вложенность дерева (у JSON тоже, а вот седой INI таким похвастать не может)
- Комментарии как в конце строки, так и занимающие всю строку
- Многострочные значения
- Массивы в качестве значений
- Возможность переиспользовать поддеревья (пример)
Даже официальный сайт отформатирован как YAML: www.yaml.org/
А JSON хорош для передачи данных, или для их хранения, куда человеку лезть не нужно.
Один мой знакомый достаточно точно выразился. Yaml — для любителей python, а JSON — для тех, кто любит C и жить не может без скобочек.
А что касается js файла, далеко не везде есть возможность исполнять js. Если проект, например, на C++, то гораздо логичнее использовать JSON парсер, поддерживающий комментарии.
Собственно на js и так есть транслятор из коробки:
JSON.parse(JSON.minify(text))
Для других языков существуют специальные парсеры (как тот же jsoncpp).
А вот что касается трансляции в другии форматы с сохранением комментариев, имхо, во-первых, проблема надуманная, так как автоматически сгенерированное и не должно содержать комментариев, во-вторых, js не самый подходящий язык для подобных действий.
Ну а само решение проблемы — красивое, потому что короткое и всего одной регуляркой, но не поддерживаемое. Хотя, если вынести части регулярки в define секцию и дать им символьные имена, можно добиться гораздо большей читаемости и поддерживаемости, но труЪ кулл-хацкеры так не делают, да.
Например бывает в bower — нужно временно отключить какую-то библиотеку. Если ее просто удалить — то уже через пару дней просто забудешь что она вообще когда-то была. А вот если закомментировать — то вряд-ли
Хотя с точки зрения парсинга он очень приятен.
В одном из своих проектов я тоже использовал JSON с комментариями для человекочитаемых конфигов. «Выкусывал» комментарии с помощью регулярных выражений перед тем как отдавать JSON-парсеру.
Обоснование автором JSON отсутствия комментариев мне не понятно. Отсутствие комментариев из коробки просто раздражает.
OK, поясню с другой стороны. Почему Крокфорд удалил комментарии из стандарта? Потому что их парсили своим языком и использовали как данные, из-за этого процедуры становились проектно-зависимыми. Стали вынуждены писать комментарии как ключи и значения JSON, а значит, появился к ним доступ из JSON. Появилась возможность работать с ними без парсинга (и, в частности, конвертировать в другие форматы). Предложение хакерского комментирования снова выводит комментарии из поля доступности средствами JSON. Поэтому требуется инструмент возвращения их в это поле.
Но вместо того, чтобы работать с хакерскими комментариями, гораздо удобнее за стандарт принять обычные. (Удобнее не для «суровых программистов», а для всех.) Через jsonComm.comm2json() вводится процедура перевода в доступность из JSON, которую остаётся написать под нужный язык проекта.
Комментарии в схеме — это комментарии к грамматике. Если их использовать как комментарии к данным — это подобно стрелянию из пушки по воробьям (каждому данному сопоставляем грамматический элемент).
А вообще, если увлечься JSON-грамматиками, то они быстро закончат, как XSLT :).
Что проще понять:
{«question»:«42» //The Ultimate Question of Life, the Universe, and Everything}
или
{«question»:{«descripton»:«The Ultimate Question of Life, the Universe, and Everything», «value»:«42»}
Не вижу особого смысла в комментариях именно к данным, другое дело если нужно комментировать структуру.
Плюс такие данные в Json можно обрабатывать штатными средствами.
{
"order1":"N 21", // Накладная на принтер
"order2":"M 23", // Накладная на мышку
"order3":"S 231", // Чек за пицу и пиво
}
{
"order1" : {
"number": "N 21",
"name": "Накладная на принтер"
},
"order2": {
"number": "M 23",
"name": "Накладная на мышку"
},
"order3": {
"number": "S 231",
"name": "Чек за пицу и пиво"
}
}
Не знаю, для меня второй вариант хотя и более длинный, но куда более человекочитаемый и понятный.
Я вижу следующие проблемы у json'a с комментариями:
1) Лишние преобразования, лишний код, лишние возможности для ошибок,
2) Невозможно отправить json c комментариями другим системам и организациям,
3) Скорее всего при отправке с веба на бек, все комментарии исчезнут,
4) Отсутствие комментариев при отладке приложения, так как они удаляются намного раньше,
5) Сложность валидации и форматирование на уровне IDE,
6) Нестандартная форма json'a, требующая привыкания,
7) Требование танцев с бубном при преобразовании форматов,
То есть json с комментариями можно использовать только для локальных конфигов, которые никуда не передаются и используются в рамках одной системы, но при этом нет проблемы комментарии добавлять как отдельное поля (в формате выше).
1) возможны, но для того отлаживать и тестировать надо;
2) отправить можно, вместе с процедурой очистки, если роботам, без неё, если людям;
3) если напишут на бек-языках чистильщики, то можно пользоваться; Нода уже умеет;
4) как раз для неудаления комментариев задумывались и делались 2 другие функции (comm2json, change);
5) в IDE они распознаются как JS;
6) комментарии — полностью стандартны для JS и Пайтона;
7) это всегда;
> конфигов, которые никуда не передаются
--для этого и задумывалось. Но чтобы не добавлять в отдельные поля — чтобы комментарии для людей, JSON — для скриптов. comm2json — это так, задел для будущего, вклад в конверторы, показ того, что это в рамках подхода — просто и коротко.
В случае поиска одного ключа в конфиге обычно нет смысла сканировать конфиг дальше, если уже нашёл значение.
В вашем случае это будет комментарий.
yacc/bison:
dictionary: LBRACE dictionary_list RBRACE
{
$$ = $2;
}
| LBRACE RBRACE
{ return new Dictionary(); }
dictionary_list: dictionary_element
{
$$ = new Dictionary();
$$->Set($1->key, $1->value);
delete $1;
}
| dictionary_element COMMA dictionary_list
{
$$ = $3;
$$->Set($1->key; $1->value);
delete $1;
}
;
dictionary_element: string COLON value
{
$$ = new DictionaryElement($1, $3);
}
;
Сравните разницу в фрагменте:
Обратный порядок:
| dictionary_element COMMA dictionary_list
{
$$ = $3;
$$->Set($1->key, $1->value);
delete $1;
}
;
Прямой порядок:
| dictionary_list COMMA dictionary_element
{
$$ = $1;
$$->Set($3->key, $3->value);
delete $3;
}
;
Если не брать во внимание возможность того, что ключи в словаре могут повторяться (а с чего бы собственно это предусматривать?), то как именно писать — без разницы и скорее дело привычки того, кто пишет грамматику для лексического анализатора.
Из основных:
— подстановки (причем более продвинутые, чем в yaml);
— автоматические слияния объектов и файлов;
— чтение переменных окружения, если нужно;
— ну и комментарии конечно.
Правда не знаю, как там с реализацией для языков, отличных от java.
github.com/typesafehub/config/
var mod = require('mod'); // реквайрим mod.yaml
Причем это работает даже c browserify.
Так же нодовцам советую взгянуть на yapm — отличный поддерживаемый форк npm, позволяющий вместо package.json использовать package.yaml
Вы излишне все усложнили, поэтому получили трудночитаемое регулярное выражение и сложный код.
Все гораздо проще. Для того, чтобы удалить все комментарии надо найти альтернативы:
("(?:\\[\s\S]|[^"])*")
что означает- внутри кавычек есть: что-то экранированное, или что угодно, кроме кавычки((?:\/\/|#)[^\n]*)
что означает — однострочный комментарий(\/\*[\s\S]*?\*\/)
что означает многострочный комментарий
Результирующее выражение:
("(?:\\[\s\S]|[^"])*")|((?:\/\/|#)[^\n]*)|(\/\*[\s\S]*?\*\/)
и оставить от него только $1
в строке замены.
https://regex101.com/r/wD0gQ6/1
Почему это будет работать вообще и работать корректно? Движок регексов будет последовательно применять эти альтернативы к каждой позиции текста, встретив кавычку применит первую альтернативу (если JSON валиден), встретив начало комментариев применит другие альтернативы и при этом захватит всю эту составную часть целиком, то есть внутри комментария или кавычек может быть что угодно- ложного срабатывания не будет.
С заменой значения по ключу тоже все относительно просто при таком подходе, но сначала надо изменить регулярное выражение:
- Помимо чего-то внутри кавычек в тексте могут быть числа,
true
,false
,null
(массивы и объекты не рассматриваю, потому что в топике они тоже не учитываются) - Именованный ключ нам может встретиться после символов
{
и,
— необходимо установить флаг, что когда встретится что-то в кавычках — это будет ключ.
Результирующее регулярное выражение:
([,{])|("(?:\\[\s\S]|[^"])*"|true|false|null|[0-9.eE+-]+)|((?:\/\/|#)[^\n]*)|(\/\*[\s\S]*?\*\/)
Весь код помещается в несколько строк:
var regex = /([,{])|("(?:\\[\s\S]|[^"])*"|true|false|null|[0-9.eE+-]+)|((?:\/\/|#)[^\n]*)|(\/\*[\s\S]*?\*\/)/g;
var nextIsKey = false;
var nextIsReplaced = false;
var replaceKey = "aaa";
var replaceValue = '"Its works!"'; // заменяем строковым значением
var replacer = function( $0, $1, $2, $3, $4 ) {
if ( typeof $1 !== 'undefined' ) {
nextIsKey = true;
} else if ( typeof $2 !== 'undefined' ){
if ( nextIsReplaced ) {
nextIsKey = false;
nextIsReplaced = false;
return replaceValue;
};
if ( nextIsKey && $2 == '"'+replaceKey+'"' ) nextIsReplaced = true;
nextIsKey = false;
}
return $0; // не меняем ничего, если это не указано отдельно
};
console.log( jComm.replace( regex, replacer ) );
https://jsfiddle.net/hb5LzuL7/
При такой реализации возможно добавить в функцию replacer
флаги глубины вложенности, флаги начала массива или объекта и корректно их обрабатывать, но это не оговорено в топике, поэтому не буду это делать.
P.S. Не сочтите меня снобом, пожалуйста. Просто начал писать комментарий про неоправданно сложное регулярное выражение там где все решается значительно проще, но заодно накидал код замены, поэтому такой большой комментарий вышел.
JSON, который можно комментировать