Unquoting booleans, numbers, etc. in a JSON string I have a method that takes a JSON string as input and "fixes" it. By that, I mean, that the JSON string comes in with all values quoted. My method un-quotes the values that shouldn't be quoted (i.e. true, false, numbers, {}, etc). The method was originally doing it by doing 4 string replaces (for the true / false, etc) and regex replace for the numbers. Kind of slow. So I re-wrote it with StringBuilder:

    protected static string FixupJson(string json)
    {
        if (json == null)
            throw new ArgumentNullException(nameof(json));

        int nLen = json.Length;

        StringBuilder sb = new StringBuilder(nLen);

        for (int i = 0; i &lt; nLen; i++)
        {
            char ch = json[i];

            if (ch == ':' &amp;&amp; json[i+1] == ' ' &amp;&amp; json[i + 2] == '\"')
            {
                int k = json.IndexOf('\"', i + 3);

                sb.Append(": ");

                string g = json.Substring(i + 3, k - i - 3);

                bool bQuote = true;

                if (g == "true" || g == "false" || g == "null" || g == "{}")
                    bQuote = false;
                else if (g == "NaN")
                    bQuote = true;
                else if (Double.TryParse(g, out double d))
                    bQuote = false;

                if (bQuote)
                    sb.Append('\"');

                sb.Append(g);

                if (bQuote)
                    sb.Append('\"');

                i = k;
            }
            else
            {
                sb.Append(ch);
            }
        }

        return sb.ToString();
    }


This got me a 35% improvement, but I want to see if there is a better approach or if I can get this faster. My first StringBuilder approach, instead of appending char by char would append chunks pulled out with SubString(). That was actually a lot slower then this version.

Yes, I understand the right way to do it would be to fix it at the source :), which I do control, but the way the json gets serialized out at the source, I don't know if the value needs to be quoted until the json is fully spit out (or at least until the value is fully spit out) as a single value can be a formatted string from multiple sources (i.e. "myVal": "(this part from one place)|(this part from another place))". So "fixing it there" would mean going from a single String.Format() for the entire json to a bunch of them for each value. Right now the JSON is "pre-rendered" (once) and passed into a String.Format() to fill in the values, so by fixing it there I'd have to go to a bunch of little String.Format()'s to format each value then pass it in to the big String.Format()… so I figure this is a decent compromise.

EDIT: Should handle any old json, but this was the one I was using in my test app in C# string format ready to paste :).

"{\r\n  \"xxx\": \"TRACE|1\",\r\n  \"Timestamp\": \"2019-01-01 12:44:36.529\",\r\n  \"Message\": {\r\n    \"a\": \"bbb\",\r\n    \"b1\": {\r\n      \"b2\": \"test2\",\r\n      \"b3\": \"Test1\",\r\n      \"b4\": \"true\",\r\n      \"b5\": \"178\"\r\n    }\r\n  },\r\n  \"ThreadId\": \"1\",\r\n  \"Exception\": \"{}\"\r\n}"
I find your method for fixing invalid JSON is the worst possible because it treats JSON as a pure string and not a tree of properties/keys and values. This increases the possibility of changing values that might not be values at all. IMO the optimal approach would be to parse it with JSON.NET by using JToken.Parse and recreate the resulting tree with correct values.

You can take a look how it could be done here where I'm using the Visitor Pattern to transform JSON too. 



But honestly, unless you need to be able to read some old data, you should really fix the serializer so that it outputs valid JSON instead of trying to fix its bugs with even more dirty workarounds.