亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#實現JSON解析器MojoUnityJson功能(簡單且高效)

2019-10-29 21:06:30
字體:
來源:轉載
供稿:網友

MojoUnityJson 是使用C#實現的JSON解析器 ,算法思路來自于游戲引擎Mojoc的C語言實現 Json.h 。借助C#的類庫,可以比C的實現更加的簡單和全面,尤其是處理Unicode Code(/u開頭)字符的解析,C#的StringBuilder本身就支持了UnicodeCodePoint。

MojoUnityJson使用遞歸下降的解析模式,核心解析代碼只有450行(去掉空行可能只有300多行),支持標準的JSON格式。算法實現力求簡潔明了,用最直接最快速的方法達到目的,沒有復雜的概念和模式。除了解析JSON,還提供了一組方便直觀的API來訪問JSON數據,整體實現只有一個文件,僅依賴 System.Collections.Generic , System.Text , System 三個命名空間,MojoUnityJson可以很容易的嵌入到其它項目里使用。

本文主要介紹一下,超級簡單又高效,并且看一眼就完全明白的解析算法,幾乎可以原封不動的復制粘貼成其它語言版本的實現。

保存上下文信息

使用一個簡單的結構體,用來在解析的過程中,傳遞一些上下文數據。

private struct Data{ // 需要解析的JSON字符串 public string  json; // 當前JSON字符串解析的位置索引 public int   index; // 緩存一個StringBuilder,用來摳出JSON的一段字符。 public StringBuilder sb; public Data(string json, int index) {  this.json = json;  this.index = index;  this.sb = new StringBuilder(); }}

抽象JSON的值

我們把JSON的值抽象成以下幾個類型:

public enum JsonType {  Object,  Array,  String,  Number,  Bool,  Null, }

整體解析步驟

// 解析 JsonValueprivate static JsonValue ParseValue(ref Data data);// 解析 JsonObjectprivate static JsonValue ParseObject(ref Data data);// 解析 JsonArrayprivate static JsonValue ParseArray(ref Data data);// 解析 stringprivate static JsonValue ParseString(ref Data data);// 解析 numberprivate static JsonValue ParseNumber(ref Data data)

這就是全部的解析流程,在ParseValue中會根據字符判斷類型,分別調用下面幾個不同的解析函數。JsonValue就對應一個JSON的值,它有一個JsonType代表了這個值的類型。這是一個遞歸的過程,在ParseValue,ParseObject和ParseArray過程中,會遞歸的調用ParseValue。JSON一定是始于一個,Object或Array,當這個最頂層的值解析完畢的時候,整個JSON也就解析完成了。

解析空白字符

解析過程中,會有很多為了格式化存在的空白字符,需要剔除這些,才能獲得有信息的字符,這是一個重復的過程,需要一個函數統一處理。

private static void SkipWhiteSpace(ref Data data){ while (true) {  switch (data.json[data.index])  {   case ' ' :   case '/t':   case '/n':   case '/r':    data.index++; // 每次消耗一個字符,就向后推進JSON的索引    continue;  }  break; }}

解析JsonValue

private static JsonValue ParseValue(ref Data data){ // 跳過空白字符 SkipWhiteSpace(ref data); var c = data.json[data.index]; switch (c) {  case '{':    // 表示Object   return ParseObject(ref data);  case '[':   // 表示Array   return ParseArray (ref data);  case '"':   // 表示string   return ParseString(ref data);  case '0':  case '1':  case '2':  case '3':  case '4':  case '5':  case '6':  case '7':  case '8':  case '9':  case '-':   // 表示數值   return ParseNumber(ref data);  case 'f': // 表示可能是false   if     (     data.json[data.index + 1] == 'a' &&      data.json[data.index + 2] == 'l' &&     data.json[data.index + 3] == 's' &&     data.json[data.index + 4] == 'e'    )   {    data.index += 5;    // 表示是false    return new JsonValue(JsonType.Bool, false);   }   break;  case 't': // 表示可能是true   if     (     data.json[data.index + 1] == 'r' &&      data.json[data.index + 2] == 'u' &&     data.json[data.index + 3] == 'e'    )   {    data.index += 4;    // 表示是true    return new JsonValue(JsonType.Bool, true);   }   break;  case 'n': // 表示可能是null   if     (     data.json[data.index + 1] == 'u' &&      data.json[data.index + 2] == 'l' &&     data.json[data.index + 3] == 'l'    )   {    data.index += 4;    // 表示可能是null    return new JsonValue(JsonType.Null, null);   }   break; } // 不能處理了 throw new Exception(string.Format("Json ParseValue error on char '{0}' index in '{1}' ", c, data.index));}
  • ParseValue是解析的主入口,代表著解析JsonValue這個抽象的JSON值,其真實的類型在解析的過程中逐漸具體化。
  • 在剝離掉空白字符之后,就可以很容易的通過單個字符,就判斷出其可能的數值類型,而不需要向前或向后檢索。
  • true,false,null 這幾個固定的類型,直接就處理掉了,而其它稍微復雜的類型需要使用函數來處理。
  • 這里沒有使用if else,而是大量使用了case,是為了提高效率,減少判斷次數。

解析JsonObject

private static JsonValue ParseObject(ref Data data){ // Object 對應 C#的Dictionary var jsonObject = new Dictionary<string, JsonValue>(JsonObjectInitCapacity); // skip '{' data.index++; do {  // 跳過空白字符  SkipWhiteSpace(ref data);  if (data.json[data.index] == '}')  {   // 空的Object, "{}"   break;  }  DebugTool.Assert  (   data.json[data.index] == '"',    "Json ParseObject error, char '{0}' should be '/"' ",    data.json[data.index]  );  // skip '"'  data.index++;  var start = data.index;  // 解析Object的key值  while (true)  {   var c = data.json[data.index++];   switch (c)   {    case '"':     // check end '"'     break;    case '//':     // skip escaped quotes     data.index++;     continue;    default:     continue;   }   // already skip the end '"'   break;  }  // get object key string  // 扣出key字符串  var key = data.json.Substring(start, data.index - start - 1);  // 跳過空白  SkipWhiteSpace(ref data);  DebugTool.Assert  (   data.json[data.index] == ':',    "Json ParseObject error, after key = {0}, char '{1}' should be ':' ",    key,   data.json[data.index]  );  // skip ':'  data.index++;  // set JsonObject key and value  // 遞歸的調用ParseValue獲得Object的value值  jsonObject.Add(key, ParseValue(ref data));  // 跳過空白  SkipWhiteSpace(ref data);  if (data.json[data.index] == ',')  {   // Object的下一對KV   data.index++ ;       }  else  {   // 跳過空白   SkipWhiteSpace(ref data);   DebugTool.Assert   (    data.json[data.index] == '}',     "Json ParseObject error, after key = {0}, char '{1}' should be '{2}' ",    key,    data.json[data.index],    '}'   );   break;  } } while (true); // skip '}' and return after '}' data.index++; return new JsonValue(JsonType.Object, jsonObject);}

JsonObject類型就簡單的對應C#的Dictionary,value是JsonValue類型。當解析完成后,value的類型就是確定的了。

JsonValue是遞歸的調用ParseValue來處理的,其類型可能是JsonType枚舉的任意類型。

解析JsonArray

private static JsonValue ParseArray(ref Data data){ // JsonArray 對應 List var jsonArray = new List<JsonValue>(JsonArrayInitCapacity); // skip '[' data.index++; do {  // 跳過空白  SkipWhiteSpace(ref data);  if (data.json[data.index] == ']')  {   // 空 "[]"   break;  }  // add JsonArray item   // 遞歸處理List每個元素  jsonArray.Add(ParseValue(ref data));  // 跳過空白  SkipWhiteSpace(ref data);  if (data.json[data.index] == ',')  {   // 解析下一個元素   data.index++;  }  else  {   // 跳過空白   SkipWhiteSpace(ref data);   DebugTool.Assert   (    data.json[data.index] == ']',     "Json ParseArray error, char '{0}' should be ']' ",     data.json[data.index]   );   break;  } } while (true); // skip ']' data.index++; return new JsonValue(JsonType.Array, jsonArray);}

JsonArray類型就簡單的對應C#的List,element是JsonValue類型。當解析完成后,element的類型就是確定的了。

JsonValue是遞歸的調用ParseValue來處理的,其類型可能是JsonType枚舉的任意類型。

解析string

private static JsonValue ParseString(ref Data data){ // skip '"' data.index++; var start = data.index; string str; // 處理字符串 while (true) {  switch (data.json[data.index++])  {   case '"': // 字符串結束    // check end '"'          if (data.sb.Length == 0)    {     // 沒有使用StringBuilder,直接摳出字符串     str = data.json.Substring(start, data.index - start - 1);    }    else    {     // 有特殊字符在StringBuilder     str = data.sb.Append(data.json, start, data.index - start - 1).ToString();     // clear for next string     // 清空字符,供下次使用     data.sb.Length = 0;    }    break;   case '//':    {     // check escaped char     var escapedIndex = data.index;     char c;     // 處理各種轉義字符     switch (data.json[data.index++])     {      case '"':       c = '"';       break;      case '/'':       c = '/'';       break;      case '//':       c = '//';       break;      case '/':       c = '/';       break;      case 'n':       c = '/n';       break;      case 'r':       c = '/r';       break;      case 't':       c = '/t';       break;      case 'u':       // 計算unicode字符的碼點       c = GetUnicodeCodePoint        (         data.json[data.index],          data.json[data.index + 1],          data.json[data.index + 2],          data.json[data.index + 3]        );       // skip code point       data.index += 4;       break;      default:       // not support just add in pre string       continue;     }     // add pre string and escaped char     // 特殊處理的字符和正常的字符,一起放入StringBuilder     data.sb.Append(data.json, start, escapedIndex - start - 1).Append(c);     // update pre string start index     start = data.index;     continue;    }   default:    continue;  }  // already skip the end '"'  break; } return new JsonValue(JsonType.String, str);}

處理字符串麻煩的地方在于,轉義字符需要特殊處理,都這轉義字符就會直接顯示而不能展示特殊的作用。好在StringBuilder功能非常強大,提供處理各種情況的接口。

解析Unicode字符

在JSON中,Unicode字符是以/u開頭跟隨4個碼點組成的轉義字符。碼點在StringBuilder的Append重載函數中是直接支持的。所以,我們只要把/u后面的4個字符,轉換成碼點傳遞給Append就可以了。

/// <summary>/// Get the unicode code point./// </summary>private static char GetUnicodeCodePoint(char c1, char c2, char c3, char c4){ // 把/u后面的4個char轉換成碼點,注意這里需要是char類型,才能被Append正確處理。 // 4個char轉換為int后,映射到16進制的高位到低位,然后相加得到碼點。 return (char)   (    UnicodeCharToInt(c1) * 0x1000 +    UnicodeCharToInt(c2) * 0x100 +    UnicodeCharToInt(c3) * 0x10 +    UnicodeCharToInt(c4)   );}/// <summary>/// Single unicode char convert to int./// </summary>private static int UnicodeCharToInt(char c){ // 使用switch case 減少 if else 的判斷 switch (c) {  case '0':  case '1':  case '2':  case '3':  case '4':  case '5':  case '6':  case '7':  case '8':  case '9':   return c - '0';  case 'a':  case 'b':  case 'c':  case 'd':  case 'e':  case 'f':   return c - 'a' + 10;  case 'A':  case 'B':  case 'C':  case 'D':  case 'E':  case 'F':   return c - 'A' + 10; } throw new Exception(string.Format("Json Unicode char '{0}' error", c));}

解析number

private static JsonValue ParseNumber(ref Data data){ var start = data.index; // 收集數值字符 while (true) {  switch (data.json[++data.index])  {   case '0':   case '1':   case '2':   case '3':   case '4':   case '5':   case '6':   case '7':   case '8':   case '9':   case '-':   case '+':   case '.':   case 'e':   case 'E':    continue;  }  break; } // 摳出數值字符串 var strNum = data.json.Substring(start, data.index - start); float num; // 當成float處理,當然也可以用double if (float.TryParse(strNum, out num)) {  return new JsonValue(JsonType.Number, num); } else {  throw new Exception(string.Format("Json ParseNumber error, can not parse string [{0}]", strNum)); }}

如何使用

只有一句話,把Json字符串解析成JsonValue對象,然后JsonValue對象包含了所有的數值。

var jsonValue = MojoUnity.Json.Parse(jsonString);JsonValue的訪問API// JsonValue 當做 stringpublic string AsString();// JsonValue 當做 floatpublic float AsFloat();// JsonValue 當做 intpublic float AsInt();// JsonValue 當做 boolpublic float AsBool();// JsonValue 當做 nullpublic float IsNull();// JsonValue 當做 Dictionarypublic Dictionary<string, JsonValue> AsObject();// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做JsonValue public JsonValue AsObjectGet(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 Dictionarypublic Dictionary<string, JsonValue> AsObjectGetObject(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 Listpublic List<JsonValue> AsObjectGetArray(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 stringpublic string AsObjectGetString(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 floatpublic float AsObjectGetFloat(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 intpublic int AsObjectGetInt(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 boolpublic bool AsObjectGetBool(string key);// JsonValue 當做 Dictionary 并根據 key 獲取 value 當做 null public bool AsObjectGetIsNull(string key);// JsonValue 當做 Listpublic List<JsonValue> AsArray();// JsonValue 當做 List 并獲取 index 的 value 當做 JsonValuepublic JsonValue AsArrayGet(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 Dictionarypublic Dictionary<string, JsonValue> AsArrayGetObject(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 Listpublic List<JsonValue> AsArrayGetArray(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 stringpublic string AsArrayGetString(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 floatpublic float AsArrayGetFloat(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 intpublic int AsArrayGetInt(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 boolpublic bool AsArrayGetBool(int index);// JsonValue 當做 List 并獲取 index 的 value 當做 nullpublic bool AsArrayGetIsNull(int index);

最后

MojoUnityJson 目的就是完成簡單而單一的JSON字符串解析功能,能夠讀取JSON的數據就是最重要的功能。在網上也了解了一些開源的C#實現的JSON庫,不是功能太多太豐富,就是實現有些繁瑣了,于是就手動實現了MojoUnityJson。

總結

以上所述是小編給大家介紹的C#實現JSON解析器MojoUnityJson,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美电影在线观看完整版| 久久99精品久久久久久噜噜| 日韩在线欧美在线国产在线| 色妞在线综合亚洲欧美| 欧美高清视频免费观看| 国产精品福利在线观看| 久久久精品国产网站| 成人在线免费观看视视频| 亚洲视频在线观看免费| 91国产美女在线观看| 日韩中文字幕亚洲| 热久久这里只有| 久久久久99精品久久久久| 亚洲自拍偷拍网址| 精品国产999| 日韩高清电影免费观看完整版| 日韩欧美国产一区二区| 欧美黑人国产人伦爽爽爽| 久久久精品久久| 日韩av一区在线观看| 亚洲欧洲自拍偷拍| 亚洲影院色在线观看免费| 亚洲男人第一av网站| 欧美午夜xxx| 国产精品国产三级国产专播精品人| 国产欧美精品日韩精品| 国产一区视频在线| 一区二区三区精品99久久| 日韩在线一区二区三区免费视频| 亚洲福利影片在线| 久久久噜噜噜久久中文字免| 成人黄色av免费在线观看| 国产97在线|亚洲| 69国产精品成人在线播放| 九九热这里只有在线精品视| 亚洲国产第一页| 亚洲夜晚福利在线观看| 欧美激情精品久久久久久变态| 久久精品国产91精品亚洲| 亚洲成人a级网| 国产日韩欧美夫妻视频在线观看| 成人高清视频观看www| 国产不卡一区二区在线播放| 成人福利在线视频| 最近2019年好看中文字幕视频| 国产精品大陆在线观看| 国产日韩精品在线观看| 亚洲欧美三级在线| 亚洲精品白浆高清久久久久久| 午夜精品在线观看| 91在线无精精品一区二区| 久久久久久久av| 精品偷拍一区二区三区在线看| 久久精品人人做人人爽| 中文字幕亚洲综合| 久久久精品欧美| 欧美肥臀大乳一区二区免费视频| 久久亚洲影音av资源网| 亚洲xxxx妇黄裸体| xxxx性欧美| 成人av番号网| 国产精品主播视频| 亚洲国产精品人人爽夜夜爽| 色偷偷偷亚洲综合网另类| 欧美美女15p| 国产va免费精品高清在线观看| 日韩国产精品亚洲а∨天堂免| 久久久91精品国产一区不卡| 亚洲男人天堂2024| 国产日韩av高清| 日韩中文字幕第一页| 欧美多人爱爱视频网站| 欧美精品在线免费播放| 日韩在线观看成人| 欧美成人精品xxx| 亚洲精品综合久久中文字幕| 国产日韩一区在线| 在线视频欧美日韩| 久久久久久97| 国产69久久精品成人| 久久久久这里只有精品| 欧美日韩免费网站| 久久精品中文字幕免费mv| 久久躁狠狠躁夜夜爽| 国产婷婷色综合av蜜臀av| 国产精品一区二区三区久久久| 岛国视频午夜一区免费在线观看| 亚洲国产欧美久久| 欧美亚州一区二区三区| 国产精品香蕉在线观看| 国产日韩亚洲欧美| 国产欧美日韩精品丝袜高跟鞋| 欧美在线观看一区二区三区| 国产精品视频大全| 欧美大片在线看| 欧美一区二区色| 国产视频久久久久| 欧美高清激情视频| 97色伦亚洲国产| 成人国产精品久久久久久亚洲| 国产精品久久一区| 美女av一区二区三区| 在线观看欧美视频| 欧美日韩国产精品一区二区三区四区| 亚洲wwwav| 久久精品在线播放| 亚洲一二三在线| 日韩在线精品一区| 欧美国产日韩一区二区| 欧美极品少妇xxxxⅹ裸体艺术| 亚洲国产一区二区三区四区| 精品人伦一区二区三区蜜桃免费| 欧美精品久久久久| 亚洲欧洲在线观看| 国产精品wwww| 亚洲国产美女精品久久久久∴| 亚洲人成自拍网站| 亚洲最大福利网| 国产日韩精品视频| 国产91精品黑色丝袜高跟鞋| 亚洲精品一区中文字幕乱码| 亚洲午夜精品久久久久久久久久久久| 国产日韩欧美黄色| 福利一区视频在线观看| 粉嫩av一区二区三区免费野| 2019精品视频| 51精品国产黑色丝袜高跟鞋| 国产精品久久久久久av福利| 国产有码在线一区二区视频| 久久精品中文字幕一区| 伊人青青综合网站| 在线日韩第一页| 精品国产欧美一区二区三区成人| 精品久久久一区二区| 久久精品中文字幕电影| 国产97在线观看| 国产91精品久久久久久| 欧美成人午夜免费视在线看片| 欧美日韩性生活视频| 国产精品吴梦梦| 亚洲视频自拍偷拍| 亚洲视频在线视频| 成人黄色片网站| 欧美久久精品一级黑人c片| 欧美野外wwwxxx| 国产精品高潮呻吟久久av野狼| 国产日产欧美a一级在线| 亚洲自拍偷拍色片视频| 日本精品免费观看| 色偷偷偷综合中文字幕;dd| 在线成人中文字幕| 国产精品久久久久久一区二区| 4438全国亚洲精品在线观看视频| 亚洲一区中文字幕在线观看| 97在线精品国自产拍中文| 日韩精品免费看| 国产成人精品在线播放| 亚洲精品久久久久中文字幕二区| 国产999精品视频| 国产一区玩具在线观看| 久久免费成人精品视频| 亚洲美女自拍视频| 高清日韩电视剧大全免费播放在线观看| 欧美成人免费在线视频|