-1

Consider json string:

var json = "{\"myfield\":5e-0000006}";

I want deserialize that json, and get field "myfield" as a raw string. Example:

JToken tok = <Deserialize> // how do this??
var val = tok["myfield"].ToString(); // need get "5e-0000006"

I need get EXACT string value that was in origin string ("5e-0000006" in example, but it may be any valid float string).

user3324131
  • 923
  • 8
  • 10
  • 1
    Why? This is *not* a string, it's a number. If you parse that JSON string the JToken will contain a numeric property. If you want to display that number in a certain way specify use String.Format or whatever your UI framework uses. `Standard deserialization returns val = "0.000005"` that's not the case. The code `tok["myfield"].ToString();` calls `ToString()` on that numeric value, which uses your locale's numeric format. If you wanted a different format you could use a format string. Eg `String.Format("{0:G2}");` or `((double)tok["myfield"]).ToString("G2");` – Panagiotis Kanavos Dec 20 '21 at 17:33
  • You question is not correct. You have to explain how many zeroes you need. Is 5E-06 ok for you? And why if it is not? – Serge Dec 20 '21 at 17:36
  • I need get EXACT string value that was in origin string ("5e-0000006" in example, but it may be any correct float string). – user3324131 Dec 20 '21 at 17:39
  • Then pls explain difference between 5e-0000006 and 5e-06 ? – Serge Dec 20 '21 at 17:41
  • @Serge, "5e-0000006" != "5e-06". I talk about RAW string in json STRING – user3324131 Dec 20 '21 at 17:43
  • You might have better luck parsing the JSON yourself if what you really want to retrieve is the text of the JSON file. – adv12 Dec 20 '21 at 17:50
  • @user3324131 there was no string field value in that JSON message. There was a decimal. If you deserialize this with any JSON parser you'll get a double, float or decimal. *MAYBE* if you deserialize to a class with a `string myfield` property you'll get what you want. Don't insist on calling this field a "string" - it's not. You could create a custom type converter that returns the string – Panagiotis Kanavos Dec 20 '21 at 17:51
  • @adv12 Parsing myself is option, but I thought so powerful library as newtonsoft json could do so simple task. – user3324131 Dec 20 '21 at 17:53
  • Or you may be able to use a [JsonReader.ReadAsString](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonReader_ReadAsString.htm) to read tokens one by one – Panagiotis Kanavos Dec 20 '21 at 17:54
  • @user3324131 `so simple a task`. It can. The problem is what you want to do. What you ask is the opposite of parsing though. Instead of parsing according to JSON rules you want the raw tokens. You can't get those from the *parsing results*. A JToken isn't the raw string, it's the *result* of parsing the JSON object – Panagiotis Kanavos Dec 20 '21 at 17:55
  • @Panagiotis Kanavos "You could create a custom type converter that returns the string" Can you provide any example pls? – user3324131 Dec 20 '21 at 17:56
  • 1
    You can't. `JsonTextReader` parses JSON floating-point numbers to `double` or `decimal` and discards the JSON character sequence. See [this comment from JamesNK](https://github.com/JamesNK/Newtonsoft.Json/issues/2622#issuecomment-991766654): *The right behavior is to not convert the value to anything when parsing and leave it as a `char[]` until a .NET type is requested. But that is a design decision that needed to be made in 2007. It's too late to change it now.* – dbc Dec 20 '21 at 21:28
  • 1
    You might consider switching to System.Text.Json whose `Utf8JsonReader` does retain the character sequence. See also [Json.Net not serializing decimals the same way twice](https://stackoverflow.com/a/60445232/3744182). – dbc Dec 20 '21 at 21:32
  • @dbc, thank you very much. Your information is very useful. Could you please formalize your comments as an answer, because switching to System.Text.Json is a OK solution. – user3324131 Dec 21 '21 at 08:01

3 Answers3

1

Since you want an exact string and the json you have actually is a number (which means 5e-0000006 will equal 5e-6) I would suggest using regex:

string json = "{\"myfield\":5e-0000006}";
Regex regex = new Regex("(?<=:)[^}]+");
string result = regex.Match(json).Value;

Explanation:

(?<=:) look behind for a colon (:)

[^}]+ match any character not being a right curly brace (}), one or more times.

That should give you the value as an exact string.

Update:

If you want to match based on the myfield variable, you can expand the regex to contain that information:

string json = "{\"myfield\":5e-0000006}";
Regex regex = new Regex("(?<=\"myfield\":)[^}]+");
string result = regex.Match(json).Value;

Now you will only get the line where you have \"myfield\" in front - in case you have many lines.

You can of course replace \"myfield\" with a variable, like this:

string json = "{\"myfield\":5e-0000006}";
string myvar = "myfield";
Regex regex = new Regex("(?<=\"" + myvar + "\":)[^}]+");
string result = regex.Match(json).Value;
Poul Bak
  • 10,450
  • 5
  • 32
  • 57
  • Thanks for that solution, but it is not option for me. My actual json has deep hierarchy and I need know where value is. – user3324131 Dec 20 '21 at 18:04
1

With some info, and inspiration, from:

        static void Main(string[] args)
        {
            var json = "{\"myfield\":5e-0000006}";

            MyJson j = JsonConvert.DeserializeObject<MyJson>(json);
            string mf = j.myfield;
            Console.WriteLine(mf);
        }

        public class MyJson 
        {
            [JsonProperty("myfield")]
            public string myfield { get; set; }
        }

This will output: 5e-0000006

And I am still wondering why I am not using JRaw ...

Luuk
  • 12,245
  • 5
  • 22
  • 33
0

I ended up by creating a simple wrapper around a System.Text.Json

class MyJToken {

        JsonElement cur;
        string fieldName;
        public bool IsNull { get; private set; }

        public MyJToken(JsonElement cur, string fieldName) {
            this.cur = cur;
            this.fieldName = fieldName;
        }
        public MyJToken() {
            IsNull = true;
        }

        public override string ToString() {
            if (IsNull) {
                return "null";
            }
            return cur.ToString();
        }

        public static MyJToken Parse(string json) {
            JsonDocument doc = JsonDocument.Parse(json);
            return new MyJToken(doc.RootElement, "root");
        }

        public IEnumerable<(string, MyJToken)> EnumKeyVal() {
            foreach(var elem in cur.EnumerateObject()) {
                yield return (elem.Name, new MyJToken(elem.Value, elem.Name));
            }
            yield break;
        }

        public IEnumerable<MyJToken> EnumList() {
            foreach (var elem in cur.EnumerateArray()) {
                yield return new MyJToken(elem, "");
            }
            yield break;
        }

        public MyJToken get(string name) {
            return this[name];
        }

        public MyJToken this[string key] {
            get {
                if (!cur.TryGetProperty(key, out var value))
                    return new MyJToken();
                return new MyJToken(value, key);
            }
        }

        public MyJToken this[int key] {
            get => new MyJToken(cur[key], key.ToString());
        }

        void SayNotFound() {
            throw new Exception($"Filed {fieldName} not found");
        }

        public string STR() {
            if (IsNull) SayNotFound();
            return cur.GetString();
        }
        public string STR(string def) {
            if (IsNull) return def;
            return STR();
        }

        public string RAW() {
            if (IsNull) SayNotFound();
            return cur.GetRawText();
        }
        public string RAW(string def) {
            if (IsNull) return def;
            return RAW();
        }

        public decimal DEC() {
            if (IsNull) SayNotFound();
            return cur.GetDecimal();
        }
        public decimal DEC(decimal def) {
            if (IsNull) return def;
            return DEC();
        }

        public long LONG() {
            if (IsNull) SayNotFound();
            return cur.GetInt64();
        }
        public long LONG(long def) {
            if (IsNull) return def;
            return LONG();
        }
    }

Now I can get whatever I want:

    var json = "{\"myfield\":5e-0000006}";
    var root = MyJToken.Parse(json);
    var tok = root["myfield"];
    Console.WriteLine($"num={tok.DEC()} raw={tok.RAW()}");
user3324131
  • 923
  • 8
  • 10