@anonymouss

Какой есть эффективный и разумный способ парсинга JSON?

Посоветуйте инструменты которые есть и быстрые и эффективные для парсинга JSON файлов на .net
Кроме JObject
  • Вопрос задан
  • 1517 просмотров
Пригласить эксперта
Ответы на вопрос 4
MrMureno
@MrMureno
VR for all
у себя обычно использовали https://lbv.github.io/litjson/
не сказать что самый быстрый и эффективный. но достаточно хорош, и у нас в Unity3D проектах важно что под iOS с её AOT компиляцией отлично все прокатывало))

ах да и конечно же всегда есть еще
https://www.newtonsoft.com/json
если нужно поновее и чтоб умело прям почти все что угодно в json переварить) да и вроде как один из самых популярных.
Ответ написан
Комментировать
AlexanderYudakov
@AlexanderYudakov
C#, 1С, Android, TypeScript
Пользуюсь простым самописным механизмом:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace MyNamespace
{
    /// <summary>
    /// Выполняет преобразование текста формата JSON
    /// в граф объектов и обратно.
    /// </summary>
    public static class Json
    {
        /// <summary>
        /// Преобразует текст в формате JSON в граф объектов.
        /// </summary>
        /// <param name="text">Исходный текст в формате JSON</param>
        /// <returns>Граф объектов</returns>
        public static object Parse(string text)
        {
            return new JsonParser().Parse(text);
        }

        /// <summary>
        /// Преобразует граф объектов в текст формата JSON. Поддерживаются:
        /// - null
        /// - string
        /// - bool
        /// - int, double, decimal
        /// - List˂object˃
        /// - Dictionary˂string,object˃
        /// </summary>
        /// <param name="value">Граф объектов</param>
        /// <returns>Текст формата JSON</returns>
        public static string Stringify(object value)
        {
            return new JsonSerializer().ToString(value);
        }
    }

    class JsonSerializer
    {
        public string ToString(object obj)
        {
            return ObjectToString(obj);
        }

        private string ObjectToString(object o)
        {
            if (o == null)
                return "null";

            if (o is bool b)
                return b ? "true" : "false";

            if (o is int i)
                return i.ToString(CultureInfo.InvariantCulture);

            if (o is double db)
                return db.ToString(CultureInfo.InvariantCulture);

            if (o is decimal dc)
                return dc.ToString(CultureInfo.InvariantCulture);

            if (o is List<object> l)
                return ListToString(l);

            if (o is Dictionary<string, object> d)
                return DictionaryToString(d);

            if (o is string s)
                return StringToString(s);

            throw new ArgumentOutOfRangeException(nameof(o), o, "Unknown type.");
        }

        private static string StringToString(string s)
        {
            return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n") + "\"";
        }

        private string ListToString(List<object> a)
        {
            var sb = new StringBuilder();
            sb.Append("[");
            for (var i = 0; i < a.Count; ++i)
            {
                if (i > 0)
                    sb.Append(", ");

                var e = a[i];
                sb.Append(ObjectToString(e));
            }
            sb.Append("]");
            return sb.ToString();
        }

        private string DictionaryToString(Dictionary<string, object> d)
        {
            var sb = new StringBuilder();
            sb.Append("{");
            var isFirst = true;
            foreach (var pair in d)
            {
                if (isFirst)
                    isFirst = false;
                else
                    sb.Append(", ");

                sb.Append(StringToString(pair.Key) + ": ");
                sb.Append(ObjectToString(pair.Value));
            }
            sb.Append("}");
            return sb.ToString();
        }
    }

    class JsonParser
    {
        private string Source;

        private int Offset;

        public object Parse(string source)
        {
            Source = source;
            Offset = 0;
            return ReadObject();
        }

        private object ReadObject()
        {
            SkipWhitespace();
            var c = Source[Offset];
            ++Offset;
            object item;
            switch (c)
            {
                case '[':
                    item = ReadArray();
                    break;
                case '{':
                    item = ReadDictionary();
                    break;
                case '\"':
                case '\'':
                    --Offset;
                    item = ReadString();
                    break;
                case 'n':
                    item = ReadLiteral("ull", null);
                    break;
                case 't':
                    item = ReadLiteral("rue", true);
                    break;
                case 'f':
                    item = ReadLiteral("alse", false);
                    break;
                default:
                    if (Char.IsDigit(c) || c == '-' || c == '.')
                    {
                        --Offset;
                        item = ReadNumber();
                    }
                    else
                        throw new FormatException();
                    break;
            }

            return item;
        }

        private Dictionary<string, object> ReadDictionary()
        {
            var result = new Dictionary<string, object>();
            while (true)
            {
                SkipWhitespace();
                var c = Source[Offset];
                if (c == '}')
                {
                    ++Offset;
                    break;
                }

                var key = ReadString();
                SkipWhitespace();
                c = Source[Offset];
                if (c != ':')
                    throw new FormatException();

                ++Offset;
                var value = ReadObject();
                result.Add(key, value);

                SkipWhitespace();
                c = Source[Offset];
                if (c == ',')
                    ++Offset;
                else if (c == '}')
                {
                    ++Offset;
                    break;
                }
                else
                    throw new FormatException();
            }

            return result;
        }

        private void SkipWhitespace()
        {
            while (Offset < Source.Length && Char.IsWhiteSpace(Source[Offset]))
            {
                ++Offset;
            }
        }

        private decimal ReadNumber()
        {
            var sb = new StringBuilder();

            while (Offset < Source.Length)
            {
                var c = Source[Offset];
                if (Char.IsDigit(c) || c == '-' || c == '.')
                    sb.Append(c);
                else
                    break;

                ++Offset;
            }

            return decimal.Parse(sb.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
        }

        private object ReadLiteral(string literal, object value)
        {
            if (Source.Length - Offset > literal.Length)
            {
                if (Source.Substring(Offset, literal.Length) == literal)
                {
                    Offset += literal.Length;
                    return value;
                }
            }

            throw new FormatException();
        }

        private string ReadString()
        {
            SkipWhitespace();

            var result = new StringBuilder();

            var quote = '\0';
            var c = Source[Offset];
            if (c == '\"' || c == '\'')
            {
                quote = c;
            }
            else if (!Char.IsLetter(c))
                throw new FormatException();
            else
                result.Append(c);

            while (true)
            {
                ++Offset;
                c = Source[Offset];
                if (quote == '\0')
                {
                    if (!Char.IsLetter(c) && !Char.IsDigit(c) && c != '_')
                        break;
                }
                else if (c == quote)
                {
                    ++Offset;
                    break;
                }
                else if (c == '\\')
                {
                    ++Offset;
                    c = Source[Offset];
                    if (c == 'u')
                    {
                        c = ReadUnicodeChar();
                    }
                }

                result.Append(c);
            }

            return result.ToString();
        }

        private char ReadUnicodeChar()
        {
            ++Offset; // u
            if (Source.Length - Offset < 4)
                throw new FormatException();

            var digits = Source.Substring(Offset, 4);
            var result = ParseUnicodeChar(digits);
            Offset += 3; // 4 digits
            return result;
        }

        public static char ParseUnicodeChar(string digits)
        {
            if (!digits.ToCharArray().Any(Char.IsDigit))
                throw new FormatException();

            var decValue = Convert.ToInt32(digits, 16);
            var s = Char.ConvertFromUtf32(decValue);
            if (s.Length != 1)
                throw new FormatException();

            return s[0];
        }

        private List<object> ReadArray()
        {
            var result = new List<object>();
            while (true)
            {
                SkipWhitespace();

                var c = Source[Offset];
                if (c == ']')
                {
                    ++Offset;
                    break;
                }

                var obj = ReadObject();
                result.Add(obj);

                SkipWhitespace();
                c = Source[Offset];
                if (c == ',')
                {
                    ++Offset;
                    continue;
                }

                if (c == ']')
                {
                    ++Offset;
                    break;
                }
                
                throw new FormatException();
            }
            
            return result;
        }
    }
}
Ответ написан
@OwDafuq
Ответ написан
Комментировать
DarkRaven
@DarkRaven
разработка программного обеспечения
Можно посмотреть на https://github.com/kevin-montrose/Jil
Есть еще https://github.com/neuecc/Utf8Json , там обещают скорости. Сам не использовал, использовал JSON.Net, который вы не желаете и Jil.

Но, по факту, все они могут проиграть вашему десериализатору, заточенному под ваш формат. Если нужна скорость, лучше писать под формат.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы