【问题标题】:c# Newtonsoft json: how to deserialize json and get raw strings for float fieldsc# Newtonsoft json:如何反序列化 json 并获取浮点字段的原始字符串
【发布时间】:2022-01-22 06:48:36
【问题描述】:

考虑json字符串:

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

我想反序列化该 json,并将字段“myfield”作为原始字符串获取。 示例:

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

我需要获取原始字符串中的 EXACT 字符串值(例如“5e-0000006”,但它可能是任何有效的浮点字符串)。

【问题讨论】:

  • 为什么?这不是一个字符串,它是一个数字。如果您解析该 JSON 字符串,则 JToken 将包含一个数字属性。如果您想以某种方式显示该数字,请指定使用 String.Format 或您的 UI 框架使用的任何内容。 Standard deserialization returns val = "0.000005" 并非如此。代码tok["myfield"].ToString(); 对该数值调用ToString(),它使用您的语言环境的数字格式。如果您想要不同的格式,您可以使用格式字符串。例如String.Format("{0:G2}");((double)tok["myfield"]).ToString("G2");
  • 你的问题不正确。你必须解释你需要多少个零。 5E-06 适合你吗?如果不是,为什么?
  • 我需要获取原始字符串中的确切字符串值(例如“5e-0000006”,但它可能是任何正确的浮点字符串)。
  • 你不能。 JsonTextReader 将 JSON 浮点数解析为 doubledecimal 并丢弃 JSON 字符序列。请参阅this comment from JamesNK正确的行为是在解析时不将值转换为任何值,并将其保留为char[],直到请求 .NET 类型。但这是一个需要在 2007 年做出的设计决策。现在改变它为时已晚。
  • 您可能会考虑切换到 System.Text.Json,其 Utf8JsonReader 确实保留了字符序列。另请参阅Json.Net not serializing decimals the same way twice

标签: c# json json.net


【解决方案1】:

我最终围绕 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();
        }
    }

现在我可以得到我想要的任何东西:

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

【讨论】:

    【解决方案2】:

    一些信息和灵感来自:

            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; }
            }
    

    这将输出:5e-0000006

    我仍然想知道为什么我不使用JRaw ...?

    【讨论】:

    • 这完全解决了我的问题!谢谢你!
    【解决方案3】:

    由于您想要一个确切的字符串,而您实际上拥有的 json 是一个数字(这意味着 5e-0000006 将等于 5e-6)我建议使用正则表达式:

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

    解释

    (?&lt;=:) 在后面查找冒号 (:)

    [^}]+ 匹配任何不是右花括号 (}) 的字符一次或多次。

    这应该给你一个精确字符串的值。

    更新

    如果您想根据myfield 变量进行匹配,您可以扩展正则表达式以包含该信息:

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

    现在你只会得到前面有\"myfield\" 的那一行——以防你有很多行。

    您当然可以将\"myfield\" 替换为变量,如下所示:

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

    【讨论】:

    • 感谢您的解决方案,但这不是我的选择。我的实际 json 有很深的层次结构,我需要知道价值在哪里。
    猜你喜欢
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多