程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 淺談C#手動解析Json格式內容,

淺談C#手動解析Json格式內容,

編輯:C#入門知識

淺談C#手動解析Json格式內容,


這個應該算處女貼吧 - -

之前百度了許久基本沒有一個滿意的json結構的解析類庫 想了想還是自己做一個吧

現在我來說下大概的思路 首先我創建了一個 JsonTokener的類 用於處理json字符串的一些操作裡面有個枚舉

 1     public enum JsonCharType
 2     {
 3         BeginObject = 123, //{
 4         EndObject = 125, //}
 5         BeginArray = 91, //[
 6         EndArray = 93, //]
 7         DoubleQuote = 34, //"
 8         SingleQuote = 39, //'
 9         Comma = 44,//,
10         Split = 58, //:
11         Slash = 92, //\
12         BackSlash = 47, ///
13         Right = 13, //\r
14         Line = 10, //\n
15         None = -1 //結尾或異常
16     }

這些枚舉數值代表了循環到的char狀態 後面都有注釋說明每個值代表的字符

  1  public sealed class JsonTokener
  2     {
  3         private string jsonSource = string.Empty;
  4         private int currentIndex = -1;
  5 
  6         public int CurrentIndex
  7         {
  8             get { return currentIndex; }
  9             set { currentIndex = value; }
 10         }
 11         private int countIndex = 0;
 12 
 13         internal int lastIndex = 0;
 14 
 15         public JsonTokener(string jsonSource)
 16         {
 17             this.jsonSource = jsonSource;
 18             currentIndex = -1;
 19             countIndex = jsonSource != null ? jsonSource.Length : 0;
 20         }
 21 
 22         /// <summary>
 23         /// 向前推進一個字符
 24         /// </summary>
 25         /// <returns></returns>
 26         public JsonCharType next()
 27         {
 28             currentIndex++;
 29             return getCurrentIndex();
 30         }
 31 
 32         public JsonCharType next(params JsonCharType[] types)
 33         {
 34             JsonCharType currentType = next();
 35             while ((int)currentType != -1)
 36             {
 37                 if (checkType(currentType, types))
 38                 {
 39                     return currentType;
 40                 }
 41                 else
 42                 {
 43                     currentType = next();
 44                 }
 45             }
 46             return JsonCharType.None;
 47         }
 48 
 49         private bool checkType(JsonCharType currentType, JsonCharType[] types)
 50         {
 51             foreach (JsonCharType item in types)
 52             {
 53                 if (currentType == item)
 54                     return true;
 55             }
 56             return false;
 57         }
 58 
 59         /// <summary>
 60         /// 向後推後一個字符
 61         /// </summary>
 62         /// <returns></returns>
 63         public JsonCharType back()
 64         {
 65             currentIndex--;
 66             return getCurrentIndex();
 67         }
 68 
 69         /// <summary>
 70         /// 獲得當前位置字符
 71         /// </summary>
 72         /// <returns></returns>
 73         public JsonCharType current()
 74         {
 75             return getCurrentIndex();
 76         }
 77 
 78         /// <summary>
 79         /// 獲得當前位置的字符
 80         /// </summary>
 81         /// <returns></returns>
 82         private JsonCharType getCurrentIndex()
 83         {
 84             if (currentIndex >= 0 && currentIndex < countIndex)
 85             {
 86                 char c = jsonSource[currentIndex];
 87                 return (JsonCharType)Enum.ToObject(typeof(JsonCharType), c);
 88             }
 89             else
 90             {
 91                 currentIndex = countIndex;
 92             }
 93             //else 驗證當前索引是否小於0
 94             return JsonCharType.None;
 95         }
 96 
 97         /// <summary>
 98         /// 查找該位置到下一個type間隔的文本
 99         /// </summary>
100         /// <param name="type"></param>
101         /// <returns></returns>
102         public string nextToType(JsonCharType type)
103         {
104             StringBuilder builder = new StringBuilder();
105             JsonCharType currentType = next();
106             while ((int)currentType != -1)
107             {
108                 if (currentType == type)
109                 {
110                     return builder.ToString();
111                 }
112                 else
113                 {
114                     builder.Append((char)currentType);
115                     currentType = next();
116                 }
117             }
118             throw new Exception("已到字符串末尾 沒有找到相關匹配");
119         }
120     }

其中的操作無疑就代表了位移字符等一些操作 返回基本都是以JsonCharType為准

然後我又寫了個類叫JsonSerialization 用於解析json結構

在此我就貼核心代碼了 剩下的大家自己研究 要是都給出來就沒意思了~

在這裡我只提供思路

在JsonSerialization裡有個FindObject的方法 還有個Deserializa用於解析json結構 方法內有兩個參數一個是JsonObject是我自己定義的 還有一個是 JsonTokener就是上面的類

public JsonObject Deserializa()
{
    JsonTokener tokener = new JsonTokener(jsonSource);
    JsonObject parentNode = new JsonObject();
    //解析object
    FindObject(parentNode, tokener);
    return parentNode;
}

這個FindObject 基本實現思路

JsonCharType type = tokener.next(
JsonCharType.BeginArray,
JsonCharType.BeginObject,
JsonCharType.EndArray,
JsonCharType.EndObject,
JsonCharType.SingleQuote,
JsonCharType.DoubleQuote,
JsonCharType.Split,
JsonCharType.Comma);

首先尋找這些字符

一般一個完整的json結構傳入都會以 { [ 開頭 以] }結束 為了做到完美適配各種json結構 我加入了單引號識別和雙引號識別

現在假設一個json結構 jsonp({"str_key":"value", "bool_test":true,"int_test":123,"double_test":12.7,"null_test":null,"array_test":["array1","array2",{"array_obj" : "array_obj"},["inner_array",1,12.2,true,null]]}) 當然上述的json結構是以jsonp跨域返回的串做的例子 我只是想證明 我做的這個解析會忽略掉jsonp頭也就是說從第一個{開始解析或者第一個[開始解析

好了扯遠了 既然找到了第一個列表包含的字符 那麼就要進行進一步搜尋 也就是說還需要遞歸調用FindObject

所以第一個if也就有了

if (type == JsonCharType.BeginObject)
{
    if (parentNode.IsArray)
    {
        JsonObject innerObj = new JsonObject();
        //innerObj._parent = parentNode;
        innerObj._isObject = true;
        innerObj._sourceObj = new Dictionary<string, JsonObject>();
        FindObject(innerObj, tokener);
        parentNode.add(innerObj);
        //繼續尋找
        FindObject(parentNode, tokener);
    }
    else
    {
        parentNode._isObject = true;
        parentNode._sourceObj = new Dictionary<string, JsonObject>();
        FindObject(parentNode, tokener);
    }
}

為什麼要有個parentNode.IsArray的判斷呢 是為了防止從上次遞歸過來的JsonObject為Array類型 然而遞歸到這裡發現是Object的開頭

所以只需要新構建個JsonObject然後在尋找更下層的層級嵌套 然後添加進去 在繼續尋找直到找完位置

那個else的意思是代表了如果這個是初始化的操作也就是說一個沒有經過任何設置的JsonObject進行一個初始化並開始遞歸尋找

else if (type == JsonCharType.BeginArray)
{
    tokener.lastIndex = tokener.CurrentIndex;
    if (parentNode.IsObject)
    {
        JsonObject innerObj = new JsonObject();
        //innerObj._parent = parentNode;
        FindObject(innerObj, tokener);
        parentNode.add(innerObj);
        //繼續尋找
        FindObject(parentNode, tokener);
    }
    else
    {
        if (parentNode.IsArray)
        {
            JsonObject innerObj = new JsonObject();
            //innerObj._parent = parentNode;
            innerObj._isArray = true;
            innerObj._sourceObj = new List<JsonObject>();
            FindObject(innerObj, tokener);
            parentNode.add(innerObj);
            //繼續尋找
            FindObject(parentNode, tokener);
        }
        else
        {
            parentNode._isArray = true;
            parentNode._sourceObj = new List<JsonObject>();
            FindObject(parentNode, tokener);
        }
    }
}

這段代碼是接上面的我一段一段的解釋

這段代碼意思是當發現起始json array結構時 判斷 上一個遞歸過來的節點是不是json object類型 如果是就構建一個新的JsonObject並添加

如果不是的話判斷上一個節點過來的是不是json array結構 如果是json array結構則又需要構建一個JsonObject 並添加 

否則進行初始化設定並繼續尋找

else if (type == JsonCharType.DoubleQuote || type == JsonCharType.SingleQuote)
{
    if (parentNode.IsObject)
    {
        //找尋key
        string _key = tokener.nextToType(type);
        JsonObject innerObj = new JsonObject();
        //innerObj._parent = parentNode;
        innerObj._key = _key;
        FindObject(innerObj, tokener);
        parentNode.add(innerObj);
        //繼續尋找
        FindObject(parentNode, tokener);
    }
    else if (parentNode.IsArray)
    {
        //找到value並添加value
        string _value = tokener.nextToType(type);
        JsonObject obj = new JsonObject();
        //obj._parent = parentNode;
        obj.convertToJsonObject(_value, false);
        parentNode.add(obj);
        tokener.lastIndex = tokener.CurrentIndex;
        //繼續尋找
        FindObject(parentNode, tokener);
    }
    else
    {
        //找到value並設置value
        string _value = tokener.nextToType(type);
        parentNode.convertToJsonObject(_value, false);
    }
    tokener.lastIndex = tokener.CurrentIndex;
}

重頭戲來了 關於單引號 以及雙引號的解析  首先判斷遞歸節點 這幾乎成為了每個判斷必經之路- -

如果來自json object結構 則 先尋找key就相當於 循環到了這裡 "str_key":"value" 當然後面內容是我自動腦補的

json 的標准key value結構 當然value可以是任意結構可能是json object可能是json array也可能是json int

所以既然key的結構固定了那我就從當前的單引號或者雙引號尋找下一個單引號或雙引號這取決於起始標記

也就是 string _key = tokener.nextToType(type); 這個type自然是搜索到的單或雙引號~

上面我也說了key的結構是固定的 但是value的結構不固定所以我還得調用FindObject並構建一個新的JsonObject結構

並且把key賦值過去 當找到value的時候繼續尋找- -

如果父節點是IsArray類型基本原理和上面差不多只不過省去了找尋key的過程因為json array類型不需要key~

當找到最後就只剩value的設置了當然這只是設置json string類型至於 json int 啊 json null json double都還得另作設定

else if (type == JsonCharType.Split) //遇到kv分隔符表明了parentNode是object類型
{
    tokener.lastIndex = tokener.CurrentIndex;
    //進一步驗證如果真的是object則繼續找尋
    FindObject(parentNode, tokener);
}

接著走到這裡 大家可能發現一行頻繁出現的代碼 tokener.lastIndex = tokener.CurrentIndex; 可別小看這一行接下來就會用到

else if (type == JsonCharType.Comma) //遇到逗號表明 parentNode有可能是任意類型
{
    tokener.CurrentIndex = tokener.lastIndex;
    string value = tokener.nextToType(type);
    value = value.Trim();
    tokener.lastIndex = tokener.CurrentIndex;
    if (value == string.Empty)
    {
        //進一步驗證
        FindObject(parentNode, tokener);
    }
    else
    {
        if (parentNode.IsArray)
        {
            JsonObject innerObj = new JsonObject();
            //innerObj._parent = parentNode;
            innerObj.convertToJsonObject(value, true);
            parentNode.add(innerObj);
            FindObject(parentNode, tokener);
        }
        else
        {
            parentNode.convertToJsonObject(value, true);
        }
    }
}

恩在這裡這個tokener.lastIndex就派上用場了 這個值的含義是在一些指定的操作記錄最後一次的字符索引 比如" ' { [ ] } : 等符號都會進行記錄這是為了解析json array或者非json string類型的數值

設置tokener的當前位置為上一次特殊操作的最後index

也就是tokener.CurrentIndex = tokener.lastIndex;這句

然後獲取value 也就是說比如tokener操作進行到了這一步], \r\n1, "asd", true ] 等

假設最後特殊操作在]然後我需要截取到,這裡就會獲取一個空值所以我做了個驗證如果為空則繼續FindObject

如果不為空 就會被解析為" \r\n1"所以我加了個Trim這樣可以過濾掉前後的空格\r\n等數據

然後進行進一步驗證如果父節點來自json array則創建個新的JsonObject並把這個value進行一個內部的convert 進行int 類型 double類型 string類型等特殊類型的識別這個大家可以想想怎麼做~

找尋到最後遞歸到最後的else  parentNode.convertToJsonObject(value, true); 將讀出的 非json string類型轉換為 JsonObject

else if (type == JsonCharType.EndArray || type == JsonCharType.EndObject)
{
    tokener.lastIndex = tokener.CurrentIndex;
}

這是最後一個else了可算完工了 如果為結束array 或者結束object 也就是]} 記錄最後一次特殊操作為了應對](ps:記錄這個位置然後下次遞歸尋找的時候就會為空然後繼續尋找真正的value), \r\n1, "asd", true ]

 

總的來說這就是一個近乎完整的json解析 自己實現的思路以及一些代碼 奧對了在內部轉換的過程中有的json 串是這種格式 \u2223這種unicode編碼的特殊字符串

我在這提供一個解析方法寫的可能效率不是很好如果有好的建議留言~

this._isString = true;
int idx = str.IndexOf("\\u");
while (idx != -1)
{
    string v = str.Substring(idx, 6);
    string hex1 = v.Substring(2, 2);
    string hex2 = v.Substring(4);
    byte[] bytes = new byte[2] {
        Convert.ToByte(hex2,16), //高低位轉換
        Convert.ToByte(hex1,16) //所以是反的~
    };
    str = str.Replace(v, Encoding.Unicode.GetString(bytes));
    idx = str.IndexOf("\\u");
}
_sourceObj = str;

當然上面的解析也只是小弟的拙計畢竟現在比較好的解析都不是很好用無奈只能自己寫~並提供下思路~

處女貼完結- -

 

原帖地址:http://www.cnblogs.com/anonymous5L/p/json_decode.html


c語言的變量定義

淺談C語言變量

王佰營 徐麗紅

任何一種編程語言都離不開變量,特別是數據處理型程序,變量的使用非常頻繁,沒有變量參與程序甚至無法編制,即使編制運行後的意義也不大。變量之所以重要,是因為變量是編程語言中數據的符號標識和載體。

C語言是一種應用廣泛的善於實現控制的語言,變量在C語言中的應用更是靈活多變。那麼變量究竟是什麼呢?變量是內存或寄存器中用一個標識符命名的存儲單元,可以用來存儲一個特定類型的數據,並且數據的值在程序運行過程中可以進行修改。可見,變量首先是一個標識符或者名稱,就像一個客房的編號一樣,有了這個編號我們在交流中就可方便言表,否則,我們只可意會,那多不方便。為了方便,我們在給變量命名時,最好能符合大多數人的習慣,基本可以望名知義,便於交流和維護;其次,變量是唯一確定的對應內存若干存儲單元或者某個寄存器。這些是編譯器來保證的,用戶一般不用費心。

程序員一旦定義了變量,那麼,變量就至少可為我們提供兩個信息:一是變量的地址,即就是,操作系統為變量在內存中分配的若干內存的首地址;二是變量的值,也就是,變量在內存中所分配的那些內存單元中所存放的數據。

由於程序的多樣需要,我們對變量也有各種各樣的要求,比如:變量的生命期,變量的初始狀態,變量的有效區域,變量的開辟地和變量的開辟區域的大小等等;為了滿足這些要求,C語言的發明者就設置了以下變量:

1、 不同數據類型的變量;如:char cHar, int iTimes, flaot faverage;

2、 全局變量或者叫全程變量;

3、 局部變量;

4、 靜態變量: 靜態全局變量和靜態局部變量;關鍵詞:static

5、 寄存器變量;關鍵詞:register;

6、 外部變量: 關鍵詞:extern;

C語言中,變量在內存中開辟地的大小由數據類型決定的,由於PC機中規定一個地址單元存一個字節,不同的數據類型的變量,為其分配的地址單元數是不一樣的。C語言中除幾種基本的數據類型外用戶還可以自己定義所需要的數據類型:

1、 bool型 sizeof(bool): 1

2、 char型: sizeof(char): 1

3、 short型: sizeof(short): 2

4、 int型: sizeof(int): 4

5、 long型: sizeof(long): 4

6、 float型: sizeof(float): 4

7、 double型: sizeof(double): 8

8、 自定義型:如:

typedef struct tagMyData

{

char cHar;

int iTimes;

float faverage;

}MyDatap;

sizeof(MyDatap): 12

char szBuf[]="HELLO C&C++!";

sizeof(szBuf): 13

局部變量和全局變量是相對而言的;如下:局部變量 int itmp;

int Get_Max( const int& x, const int& y, const int& z )

{

......余下全文>>
 

C語言與匯編語言的相互調用

鄙視復制粘貼的
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved