Skip to content

Instantly share code, notes, and snippets.

@alec1o
Forked from robertcoltheart/json.md
Created December 11, 2024 13:09
Show Gist options
  • Select an option

  • Save alec1o/20fb9df4441fc8b70dcccd3632ca29bc to your computer and use it in GitHub Desktop.

Select an option

Save alec1o/20fb9df4441fc8b70dcccd3632ca29bc to your computer and use it in GitHub Desktop.
Json parser in < 100 lines
public class JsonParser
{
    public object Parse(string value)
    {
        return value.Trim() switch
        {
            {Length: 0} => null,
            var json when json[0] == '{' && json[^1] == '}' => JsonObject(json),
            var json when json[0] == '[' && json[^1] == ']' => JsonArray(json),
            var json when char.IsDigit(json[0]) || json[0] == '-' => JsonNumber(json),
            var json when json[0] == '"' && json[^1] == '"' => json[1..^1],
            "true" => true,
            "false" => false,
            _ => null
        };
    }

    private Dictionary<string, object> JsonObject(string value)
    {
        var jsonObject = new Dictionary<string, object>();
        var elements = Token(value).ToArray();

        for (var i = 0; i < elements.Length; i += 2)
        {
            jsonObject[elements[i][1..^1]] = Parse(elements[i + 1]);
        }

        return jsonObject;
    }

    private object[] JsonArray(string value)
    {
        return Token(value).Select(Parse).ToArray();
    }

    private object JsonNumber(string value)
    {
        if (value.Contains("."))
        {
            return double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
        }

        return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
    }

    private IEnumerable<string> Token(string value)
    {
        var depth = 0;
        var result = new StringBuilder();

        for (var i = 1; i < value.Length - 1; i++)
        {
            if (value[i] == '{' || value[i] == '[')
            {
                depth++;
            }
            else if (value[i] == '}' || value[i] == ']')
            {
                depth--;
            }
            else if (value[i] == '"')
            {
                while (i < value.Length)
                {
                    result.Append(value[i++]);

                    if (value[i] == '\\' && i < value.Length - 1)
                    {
                        result.Append(value[++i]);
                    }
                    else if (value[i] == '"')
                    {
                        break;
                    }
                }
            }
            else if ((value[i] == ',' || value[i] == ':') && depth == 0)
            {
                yield return result.ToString();
                result.Clear();
            }

            if (!char.IsWhiteSpace(value[i]) && !((value[i] == ',' || value[i] == ':') && depth == 0))
            {
                result.Append(value[i]);
            }
        }

        yield return result.ToString();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment