亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Newtonsoft.Json - 反序列化不帶引號的大寫布爾值

Newtonsoft.Json - 反序列化不帶引號的大寫布爾值

C#
開心每一天1111 2023-09-16 20:03:38
我從 API 收到一些不太符合 ISO 標準的 Json 內容。布爾值為大寫而不是小寫。{ "Bool": False }最初,我認為通過使用自定義應該很容易解決,例如如何讓 newtonsoft 將 yes 和 no 反序列化為布爾值。JsonConverter但看起來該方法從未被調用過。我認為原因是,該值不在引號中,因此永遠不會調用轉換器并創建異常。JsonConverter.ReadJsonFalseJsonTextReader處理這種情況的最佳方法是什么?public class BoolTests{    public class A    {        [JsonConverter(typeof(CaseIgnoringBooleanConverter))]        public bool Bool { get; set; }    }    [Theory]    [InlineData(false, "{'Bool': false}")] //ok    [InlineData(false, "{'Bool': 'False'}")] // ok    [InlineData(false, "{'Bool': False")] // fails    public void CasingMatters(bool expected, string json)    {        var actual = JsonConvert.DeserializeObject<A>(json);        Assert.Equal(expected, actual.Bool);    }}// taken from https://gist.github.com/randyburden/5924981public class CaseIgnoringBooleanConverter : JsonConverter{    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)    {        switch (reader.Value.ToString().ToUpperInvariant().Trim())        {            case "TRUE":                return true;            case "FALSE":                return false;        }        // If we reach here, we're pretty much going to throw an error so let's let Json.NET throw it's pretty-fied error message.        return new JsonSerializer().Deserialize(reader, objectType);    }    public override bool CanConvert(Type objectType)    {        return objectType == typeof(bool);    }    public override bool CanWrite => false;    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)    {        throw new NotImplementedException();    }}
查看完整描述

2 回答

?
30秒到達戰場

TA貢獻1828條經驗 獲得超6個贊

不幸的是,正如您所發現的,無效的 json 是無效的,因此無法由普通和常見的 json (de) 序列化程序(如 Json.net)處理。

對反序列化程序使用轉換器和策略設置也不起作用,因為它們旨在處理諸如空對象作為數組返回或名稱轉換/大小寫處理之類的事情。

一個天真的解決方案是做一個簡單的字符串替換,比如

string?json?=?invalidJson.Replace("False",?"false");

但是,這存在一些問題:

  1. 您需要將整個無效的 json 讀入內存,并創建它的固定副本,這意味著您將在內存中擁有兩個完整的數據副本,一個是壞的,一個是好的。

  2. 它也會替換內部字符串。這可能不是您的數據問題,但使用上述方法并不容易處理。False

另一種方法是編寫一個基本的分詞器,該分詞器可以理解基本的 JSON 語法,例如字符串、數字和標識符,并逐個令牌遍歷文件,替換錯誤的標識符。這將解決問題 2,但根據解決方案,可能需要更復雜的實現來修復內存問題 1。

下面發布了一個簡單的嘗試,創建一個可以使用的標識符,這將在找到標識符時修復它們,否則可以理解基本的 JSON 令牌。TextReader

請注意以下幾點:

  1. 它不是真正的性能。它始終分配臨時緩沖區。您可能希望研究“緩沖區租用”以更好地處理此方法,甚至只是直接流式傳輸到緩沖區。

  2. 它不處理數字,因為那時我停止編寫代碼。我把這個留作練習??梢跃帉懟镜臄底痔幚恚驗槟]有真正驗證文件是否具有有效的 JSON,因此可以添加任何可以獲取足夠字符來構成數字的內容。

  3. 我沒有用非常大的文件對此進行測試,只用小的示例文件進行測試。我復制了一個9.5MB的文本,它適用于此。List<Test>

  4. 我沒有測試所有 JSON 語法??赡艽嬖趹撎幚淼刺幚淼淖址?strong>如果您最終使用它,請創建大量測試!

但是,它的作用是根據您發布的標識符修復無效的 JSON,并且它以流式方式執行此操作。因此,無論您的 JSON 文件有多大,這都應該可用。

無論如何,這是代碼,再次注意有關數字的異常:

void Main()

{

? ? using (var file = File.OpenText(@"d:\temp\test.json"))

? ? using (var fix = new MyFalseFixingTextReader(file))

? ? {

? ? ? ? var reader = new JsonTextReader(fix);

? ? ? ? var serializer = new JsonSerializer();

? ? ? ? serializer.Deserialize<Test>(reader).Dump();

? ? }

}


public class MyFalseFixingTextReader : TextReader

{

? ? private readonly TextReader _Reader;

? ? private readonly StringBuilder _Buffer = new StringBuilder(32768);


? ? public MyFalseFixingTextReader(TextReader reader) => _Reader = reader;


? ? public override void Close()

? ? {

? ? ? ? _Reader.Close();

? ? ? ? base.Close();

? ? }


? ? public override int Read(char[] buffer, int index, int count)

? ? {

? ? ? ? TryFillBuffer(count);


? ? ? ? int amountToCopy = Math.Min(_Buffer.Length, count);

? ? ? ? _Buffer.CopyTo(0, buffer, index, amountToCopy);

? ? ? ? _Buffer.Remove(0, amountToCopy);

? ? ? ? return amountToCopy;

? ? }


? ? private (bool more, char c) TryReadChar()

? ? {

? ? ? ? int i = _Reader.Read();

? ? ? ? if (i < 0)

? ? ? ? ? ? return (false, default);

? ? ? ? return (true, (char)i);

? ? }


? ? private (bool more, char c) TryPeekChar()

? ? {

? ? ? ? int i = _Reader.Peek();

? ? ? ? if (i < 0)

? ? ? ? ? ? return (false, default);

? ? ? ? return (true, (char)i);

? ? }


? ? private void TryFillBuffer(int count)

? ? {

? ? ? ? if (_Buffer.Length >= count)

? ? ? ? ? ? return;


? ? ? ? while (_Buffer.Length < count)

? ? ? ? {

? ? ? ? ? ? var (more, c) = TryPeekChar();

? ? ? ? ? ? if (!more)

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? switch (c)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? case '{':

? ? ? ? ? ? ? ? case '}':

? ? ? ? ? ? ? ? case '[':

? ? ? ? ? ? ? ? case ']':

? ? ? ? ? ? ? ? case '\r':

? ? ? ? ? ? ? ? case '\n':

? ? ? ? ? ? ? ? case ' ':

? ? ? ? ? ? ? ? case '\t':

? ? ? ? ? ? ? ? case ':':

? ? ? ? ? ? ? ? case ',':

? ? ? ? ? ? ? ? ? ? _Reader.Read();

? ? ? ? ? ? ? ? ? ? _Buffer.Append(c);

? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? case '"':

? ? ? ? ? ? ? ? ? ? _Buffer.Append(GrabString());

? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? case char letter when char.IsLetter(letter):

? ? ? ? ? ? ? ? ? ? var identifier = GrabIdentifier();

? ? ? ? ? ? ? ? ? ? _Buffer.Append(ReplaceFaultyIdentifiers(identifier));

? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? case char startOfNumber when startOfNumber == '-' || (startOfNumber >= '0' && startOfNumber <= '9'):

? ? ? ? ? ? ? ? ? ? _Buffer.Append(GrabNumber());

? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? throw new InvalidOperationException($"Unable to cope with character '{c}' (0x{((int)c).ToString("x2")})");

? ? ? ? ? ? }

? ? ? ? }

? ? }


? ? private string ReplaceFaultyIdentifiers(string identifier)

? ? {

? ? ? ? switch (identifier)

? ? ? ? {

? ? ? ? ? ? case "False":

? ? ? ? ? ? ? ? return "false";


? ? ? ? ? ? case "True":

? ? ? ? ? ? ? ? return "true";


? ? ? ? ? ? case "Null":

? ? ? ? ? ? ? ? return "null";


? ? ? ? ? ? default:

? ? ? ? ? ? ? ? return identifier;

? ? ? ? }

? ? }


? ? private string GrabNumber()

? ? {

? ? ? ? throw new NotImplementedException("Left as an excercise");

? ? ? ? // See https://www.json.org/ for the syntax

? ? }


? ? private string GrabIdentifier()

? ? {

? ? ? ? var result = new StringBuilder();

? ? ? ? while (true)

? ? ? ? {

? ? ? ? ? ? int i = _Reader.Peek();

? ? ? ? ? ? if (i < 0)

? ? ? ? ? ? ? ? break;


? ? ? ? ? ? char c = (char)i;

? ? ? ? ? ? if (char.IsLetter(c))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? _Reader.Read();

? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? }

? ? ? ? ? ? else

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? ? ? return result.ToString();

? ? }


? ? private string GrabString()

? ? {

? ? ? ? _Reader.Read();


? ? ? ? var result = new StringBuilder();

? ? ? ? result.Append('"');


? ? ? ? while (true)

? ? ? ? {

? ? ? ? ? ? var (more, c) = TryReadChar();

? ? ? ? ? ? if (!more)

? ? ? ? ? ? ? ? return result.ToString();


? ? ? ? ? ? switch (c)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? case '"':

? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? return result.ToString();


? ? ? ? ? ? ? ? case '\\':

? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? (more, c) = TryReadChar();

? ? ? ? ? ? ? ? ? ? if (!more)

? ? ? ? ? ? ? ? ? ? ? ? return result.ToString();


? ? ? ? ? ? ? ? ? ? switch (c)

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? case 'u':

? ? ? ? ? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? ? ? ? ? for (int index = 1; index <= 4; index++)

? ? ? ? ? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (more, c) = TryReadChar();

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!more)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return result.ToString();

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? break;


? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? result.Append(c);

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? }

? ? }

}


public class Test

{

? ? public bool False1 { get; set; }

? ? public bool False2 { get; set; }

? ? public bool False3 { get; set; }

}

示例文件:


{

? ? "false1": false,

? ? "false2": "false",

? ? "false3": False

}

輸出:

https://img1.sycdn.imooc.com/650599f60001190c00990093.jpg

查看完整回答
反對 回復 2023-09-16
?
藍山帝景

TA貢獻1843條經驗 獲得超7個贊

應在源中修復無效的 json。


如果你真的需要按原樣解析它,如果你想把它作為一個字符串,你可以用“False”替換 False,如果你想把它作為一個布爾值,你可以用 false 替換它。


// If you want a string

json.Replace("False", "\"False\"");


// If you want a bool

json.Replace("False", "false");

一個問題是,如果一個鍵或其他值包含“False”模式。


查看完整回答
反對 回復 2023-09-16
  • 2 回答
  • 0 關注
  • 247 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號