JSON парсер

Обсуждение проектов наших жителей.
Вы можете выставить проект на тест или найти помощников для его реализации.

Модератор: BV

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

JSON парсер

Сообщение Filyus » 27.06.2012 (Ср) 10:02

Критикуем-критикуем, а если нечего критиковать - поддерживаем:)

Возможности:
  • Чтение и запись JSON из строки и файла настроек
  • Чтение JSON из командной строки и ресурсов
  • Загрузка JSON из одного объекта в другой (т.е. загрузка настроек по умолчанию)
  • Функции для проверки типов объектов
  • Функция вывода форматированного JSON
Отличия от RFC 4627 (в сторону увеличения возможностей):
  • Поддержка строк как в двойных кавычках ("" - по RFC), так и в одинарных ('' - не по RFC)
  • Поддержка записи "true", "false" и "null" в обоих регистрах, также можно записывать их одной буквой
  • Числами считаются и строки, начинающиеся на знак "+", а не только на знак "-"
  • Поддержка записи символов не только в виде \uFFFF, но и также в \uFFF, \uFF и \uF
  • Обработка пустых элементов и элементов с пустыми и одинаковыми ключами
  • Экранирование всех управляющих символов (не только из диапазона 0 - 1F)
  • Использование расширения ".txt" вместо ".json" в функциях сохранения настроек
Ограничения (отсутствие НЕстандартных возможностей в пользу скорости):
  • Отсутствие поддержки комментариев (//... и /*...*/)
  • В функциях ToJSON и ToJSONFormatted не проверяются замкнутые друг на друга (вызывающие рекурсию) связи
Особенности:
  • Обработка всех возможных ошибок с возвратом наиболее возможного результата
Реализовано через:
  • Объекты Dictionary (как объект, т.е. ассоциативный массив) м Collection (как массив)
  • Функции "GetMem2", "StrSpnW", "StrPBrkW" и "SysAllocStringLen", объявленные через TLB
У вас нет доступа для просмотра вложений в этом сообщении.
Последний раз редактировалось Filyus 04.07.2012 (Ср) 16:52, всего редактировалось 33 раз(а).

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 27.06.2012 (Ср) 21:41

["\b\t\f\v\r\n"] ["\b\t\f\\v\r\n"]

А это верно?

1 null
[] [null]

Неверно.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 27.06.2012 (Ср) 21:48

А теперь - из моих экспериментов: {"\"":"\""} {""":"\""}

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 28.06.2012 (Чт) 8:57

Qwertiy писал(а):
["\b\t\f\v\r\n"] ["\b\t\f\\v\r\n"]

А это верно?
1 null
[] [null]

Неверно.

"\v" в строках, числа в корне и пустые значения в любых местах - не по RFC 4627, так что всё верно.
Вопрос в балансе скорости и функциональности, но и про совместимость с другими парсерами (прежде всего, встроенного в PHP) не следует забывать.

Qwertiy писал(а):А теперь - из моих экспериментов: {"\"":"\""} {""":"\""}

Добавил экранирование ключа. Думаю, ошибок теперь быть не должно, а могут быть только вопросы о неофициальных возможностях (вроде комментариев // и /**/, например).

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 28.06.2012 (Чт) 9:55

Filyus писал(а):"\v" в строках, числа в корне и пустые значения в любых местах - не по RFC 4627, так что всё верно.

Не смотрел стандарт...
Просто, чем '\v' - вертикальная табуляция принципиально отличается от обычной '\t', например?
И как записать обыкновенный пустой массив? Массив, содержащий null и пустой массив - это не одно и то же.

VBTerminator
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 415
Зарегистрирован: 19.11.2008 (Ср) 20:10

Re: JSON парсер

Сообщение VBTerminator » 28.06.2012 (Чт) 10:25

Вот набор тестов для проверки JSON-парсера на соответствие стандартам (взято из RapidJSON):

jsonchecker.zip

Обаботка файлов fail*** должна вылететь с ошибкой, а pass*** - парситься без ошибок.
У вас нет доступа для просмотра вложений в этом сообщении.

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 28.06.2012 (Чт) 11:56

Qwertiy писал(а):
Filyus писал(а):"\v" в строках, числа в корне и пустые значения в любых местах - не по RFC 4627, так что всё верно.

Не смотрел стандарт...
Просто, чем '\v' - вертикальная табуляция принципиально отличается от обычной '\t', например?

Тем, что её нет в стандарте, в данный момент вертикальная табуляция заменяется на \u000B, что понимают все парсеры.
Qwertiy писал(а):И как записать обыкновенный пустой массив? Массив, содержащий null и пустой массив - это не одно и то же.

Сделал поддержку пустых массивов, можно записывать как:
[Empty], [e], {Empty}, {e}, {e:}, {:e} и т.д.
В стандарте такого нет, но, всё же, ему не противоречит.

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 28.06.2012 (Чт) 12:42

VBTerminator писал(а):Вот набор тестов для проверки JSON-парсера на соответствие стандартам (взято из RapidJSON):

jsonchecker.zip

Обаботка файлов fail*** должна вылететь с ошибкой, а pass*** - парситься без ошибок.


Поскольоку парсер обрабатывает ошибки, он никуда вылетать не будет.

fail1.json
Код: Выделить всё
"A JSON payload should be an object or array, not a string."

Код: Выделить всё
null

fail10.json
Код: Выделить всё
{"Extra value after close": true} "misplaced quoted value"

Код: Выделить всё
{
  "Extra value after close":true
}

fail11.json
Код: Выделить всё
{"Illegal expression": 1 + 2}

Код: Выделить всё
{
  "Illegal expression":1
}

fail12.json
Код: Выделить всё
{"Illegal invocation": alert()}

Код: Выделить всё
{
  "Illegal invocation":null
}

fail13.json
Код: Выделить всё
{"Numbers cannot have leading zeroes": 013}

Код: Выделить всё
{
  "Numbers cannot have leading zeroes":13
}

fail14.json
Код: Выделить всё
{"Numbers cannot be hex": 0x14}

Код: Выделить всё
{
  "Numbers cannot be hex":0
}

fail15.json
Код: Выделить всё
["Illegal backslash escape: \x15"]

Код: Выделить всё
[
  "Illegal backslash escape: \\x15"
]

fail16.json
Код: Выделить всё
[\naked]

Код: Выделить всё
[
  null
]

fail17.json
Код: Выделить всё
["Illegal backslash escape: \017"]

Код: Выделить всё
[
  "Illegal backslash escape: \\017"
]

fail18.json
Код: Выделить всё
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]

Код: Выделить всё
[
  [
   [
    [
     [
      [
       [
        [
         [
          [
           [
            [
             [
              [
               [
                [
                 [
                  [
                   [
                    [
                     "Too deep"
                    ]
                   ]
                  ]
                 ]
                ]
               ]
              ]
             ]
            ]
           ]
          ]
         ]
        ]
       ]
      ]
     ]
    ]
   ]
  ]
]

fail19.json
Код: Выделить всё
{"Missing colon" null}

Код: Выделить всё
{
  "Missing colon":null
}

fail2.json
Код: Выделить всё
["Unclosed array"

Код: Выделить всё
[
  "Unclosed array"
]

fail20.json
Код: Выделить всё
{"Double colon":: null}

Код: Выделить всё
{
  "Double colon":null
}

fail21.json
Код: Выделить всё
{"Comma instead of colon", null}

Код: Выделить всё
{
  "Comma instead of colon":null,
  "":null
}

fail22.json
Код: Выделить всё
["Colon instead of comma": false]

Код: Выделить всё
[
  "Colon instead of comma"
]

fail23.json
Код: Выделить всё
["Bad value", truth]

Код: Выделить всё
[
  "Bad value",
  true
]

fail24.json
Код: Выделить всё
['single quote']

Код: Выделить всё
[
  "single quote"
]

fail25.json
Код: Выделить всё
["   tab   character   in   string   "]

Код: Выделить всё
[
  "\ttab\tcharacter\tin\tstring\t"
]

fail26.json
Код: Выделить всё
["tab\   character\   in\  string\  "]

Код: Выделить всё
[
  "tab\\   character\\   in\\  string\\  "
]

fail27.json
Код: Выделить всё
["line
break"]

Код: Выделить всё
[
  "line\nbreak"
]

fail28.json
Код: Выделить всё
["line\
break"]

Код: Выделить всё
[
  "line\\\nbreak"
]

fail29.json
Код: Выделить всё
[0e]

Код: Выделить всё
[
  0
]

fail3.json
Код: Выделить всё
{unquoted_key: "keys must be quoted"}

Код: Выделить всё
{
  "":"keys must be quoted"
}

fail30.json
Код: Выделить всё
[0e+]

Код: Выделить всё
[
  0
]

fail31.json
Код: Выделить всё
[0e+-1]

Код: Выделить всё
[
  0
]

fail32.json
Код: Выделить всё
{"Comma instead if closing brace": true,

Код: Выделить всё
{
  "Comma instead if closing brace":true,
  "":null
}

fail33.json
Код: Выделить всё
["mismatch"}

Код: Выделить всё
[
  "mismatch"
]

fail4.json
Код: Выделить всё
["extra comma",]

Код: Выделить всё
[
  "extra comma"
]

fail5.json
Код: Выделить всё
["double extra comma",,]

Код: Выделить всё
[
  "double extra comma",
  null
]

fail6.json
Код: Выделить всё
[   , "<-- missing value"]

Код: Выделить всё
[
  null,
  "<-- missing value"
]

fail7.json
Код: Выделить всё
["Comma after the close"],

Код: Выделить всё
[
  "Comma after the close"
]

fail8.json
Код: Выделить всё
["Extra close"]]

Код: Выделить всё
[
  "Extra close"
]

fail9.json
Код: Выделить всё
{"Extra comma": true,}

Код: Выделить всё
{
  "Extra comma":true
}

pass1.json
Код: Выделить всё
[
    "JSON Test Pattern pass1",
    {"object with 1 member":["array with 1 element"]},
    {},
    [],
    -42,
    true,
    false,
    null,
    {
        "integer": 1234567890,
        "real": -9876.543210,
        "e": 0.123456789e-12,
        "E": 1.234567890E+34,
        "":  23456789012E66,
        "zero": 0,
        "one": 1,
        "space": " ",
        "quote": "\"",
        "backslash": "\\",
        "controls": "\b\f\n\r\t",
        "slash": "/ & \/",
        "alpha": "abcdefghijklmnopqrstuvwyz",
        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
        "digit": "0123456789",
        "0123456789": "digit",
        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
        "true": true,
        "false": false,
        "null": null,
        "array":[  ],
        "object":{  },
        "address": "50 St. James Street",
        "url": "http://www.JSON.org/",
        "comment": "// /* <!-- --",
        "# -- --> */": " ",
        " s p a c e d " :[1,2 , 3

,

4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
: "A key can be any string"
    },
    0.5 ,98.6
,
99.44
,

1066,
1e1,
0.1e1,
1e-1,
1e00,2e+00,2e-00
,"rosebud"]

Код: Выделить всё
[
  "JSON Test Pattern pass1",
  {
   "object with 1 member":[
    "array with 1 element"
   ]
  },
  {},
  [],
  -42,
  true,
  false,
  null,
  {
   "integer":1234567890,
   "real":-9876.54321,
   "e":1.23456789E-13,
   "E":1.23456789E+34,
   "":2.3456789012E+76,
   "zero":0,
   "one":1,
   "space":" ",
   "quote":"\"",
   "backslash":"\\",
   "controls":"\b\f\n\r\t",
   "slash":"\/ & \/",
   "alpha":"abcdefghijklmnopqrstuvwyz",
   "ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ",
   "digit":"0123456789",
   "0123456789":"digit",
   "special":"`1~!@#$%^&*()_+-={\':[,]}|;.<\/>?",
   "hex":"g?????",
   "true":true,
   "false":false,
   "null":null,
   "array":[],
   "object":{},
   "address":"50 St. James Street",
   "url":"http:\/\/www.JSON.org\/",
   "comment":"\/\/ \/* <!-- --",
   "# -- --> *\/":" ",
   " s p a c e d ":[
    1,
    2,
    3,
    4,
    5,
    6,
    7
   ],
   "compact":[
    1,
    2,
    3,
    4,
    5,
    6,
    7
   ],
   "jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}",
   "quotes":"&#34; \" %22 0x22 034 &#x22;",
   "\/\\\"Я идиот! Убейте меня, кто-нибудь!?\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',.\/<>?":"A key can be any string"
  },
  0.5,
  98.6,
  99.44,
  1066,
  10,
  1,
  0.1,
  1,
  2,
  2,
  "rosebud"
]

pass2.json
Код: Выделить всё
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]

Код: Выделить всё
[
  [
   [
    [
     [
      [
       [
        [
         [
          [
           [
            [
             [
              [
               [
                [
                 [
                  [
                   [
                    "Not too deep"
                   ]
                  ]
                 ]
                ]
               ]
              ]
             ]
            ]
           ]
          ]
         ]
        ]
       ]
      ]
     ]
    ]
   ]
  ]
]

pass3.json
Код: Выделить всё
{
    "JSON Test Pattern pass3": {
        "The outermost value": "must be an object or array.",
        "In this test": "It is an object."
    }
}

Код: Выделить всё
{
  "JSON Test Pattern pass3":{
   "The outermost value":"must be an object or array.",
   "In this test":"It is an object."
  }
}
Последний раз редактировалось Filyus 29.06.2012 (Пт) 1:48, всего редактировалось 5 раз(а).

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 28.06.2012 (Чт) 13:04

Filyus писал(а):Сделал поддержку пустых массивов, можно записывать как:
[Empty], [e], {Empty}, {e}, {e:}, {:e} и т.д.
В стандарте такого нет, но, всё же, ему не противоречит.

Неужели так сложно сделать поддержку []?

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 28.06.2012 (Чт) 13:22

Qwertiy писал(а):
Filyus писал(а):Сделал поддержку пустых массивов, можно записывать как:
[Empty], [e], {Empty}, {e}, {e:}, {:e} и т.д.
В стандарте такого нет, но, всё же, ему не противоречит.

Неужели так сложно сделать поддержку []?

Несложно, только нелогично получится:
Код: Выделить всё
[] -> []
[,] -> [null,null]

Можно конечно сделать, чтобы первый пустой элемент игнорировался или вообще все пустые, но, думаю, это не самые лучшие решения.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 28.06.2012 (Чт) 14:08

Filyus писал(а):Несложно, только нелогично получится:
Код: Выделить всё
[] -> []
[,] -> [null,null]

По крайней мере пустые скобки должны обозначать пустой массив - это абсолютно очевидно и именно так и используется.

Кстати, C# игнорирует последнюю запятую при инициализации (в коде, естественно). Это ещё вариант как можно сделать:
Код: Выделить всё
[]     => []
[,]    => [null]
[,,]   => [null, null]
[,1]   => [null, 1]
[1,2,] => [1, 2]

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 29.06.2012 (Пт) 2:15

Qwertiy писал(а):По крайней мере пустые скобки должны обозначать пустой массив - это абсолютно очевидно и именно так и используется.

Кстати, C# игнорирует последнюю запятую при инициализации (в коде, естественно). Это ещё вариант как можно сделать:
Код: Выделить всё
[]     => []
[,]    => [null]
[,,]   => [null, null]
[,1]   => [null, 1]
[1,2,] => [1, 2]

Сделал, а ещё убрал три ошибки парсинга (вчера одну, сегодня две). Больше ошибок уже не нахожу:)

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 04.07.2012 (Ср) 16:52

Исправлена обработка null- и object-ключей в функциях: LoadDefault, ToJSON и ToJSONFormatted.

Filyus
Обычный пользователь
Обычный пользователь
 
Сообщения: 81
Зарегистрирован: 07.07.2011 (Чт) 11:54

Re: JSON парсер

Сообщение Filyus » 12.11.2012 (Пн) 17:36

Небльшой пример (без проверки на принадлежность чисел диапазону)...
Загрузка настроек:
Код: Выделить всё
Set DefSets = FromJson("{'Window':{}}")
Set Window = DefSets!Window
Window!Width = Me.Width \ Screen.TwipsPerPixelX
Window!Height = Me.Height \ Screen.TwipsPerPixelY

ReadSets
LoadDefault Sets, DefSets
Set Window = Sets!Window
Me.Width = Window!Width * Screen.TwipsPerPixelX
Me.Height = Window!Height * Screen.TwipsPerPixelY
Сохранение:
Код: Выделить всё
If Me.WindowState <> vbMinimized Then
  Window!Width = Me.Width \ Screen.TwipsPerPixelX
  Window!Height = Me.Height \ Screen.TwipsPerPixelY
  SaveSets
End If


Вернуться в Наши проекты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

    TopList