1. 程式人生 > >用原始方法解析復雜字符串,json一定要用JsonMapper麽?

用原始方法解析復雜字符串,json一定要用JsonMapper麽?

之間 正則表達式 isn ces plain cli shu 如何解決 clist

轉自數據之巔原文用原始方法解析復雜字符串,json一定要用JsonMapper麽?

閱讀目錄

  • 1.不規則非json字符串
  • 2.鍵值對字符串分割函數
  • 3.復雜Json格式的字符串
  • 4.標準的json格式
  • 5.總結

經常采集數據,肯定會碰到解析字符串,包括整個頁面的html,或者json以及一些不標準的json格式。。。

以前用json序列化,有時候需要實體類,有的時候沒有,比較麻煩,聽說可以用JsonMapper,解析為字典格式。不過沒用過,習慣了用最原始的方法來解析字符串,所以這裏分享幾個解析的案例。也許會有點作用。

解析字符串最常用的應該是Splite和Replace了。分割,然後替換一些引號之類的。最後組合。特別是采集的時候,經常會把html頁面中某一段要提取出來,可能很多人用正則表達式,可是不會啊,也不願意去學。那只好用這些原始的方法了,時間久了,也積累一些經驗或者函數。看看幾個例子。

回到目錄

1.不規則非json字符串

先看看這個例子,字符串是連在一起,沒有換行的,為了方便觀察,換行了,程序是原始在一起的:

1 2 3 [11101630,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,05,48‘,‘4‘,1,2,0,0], [11101631,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,09,48‘,‘0‘,,,0,0], [11101632,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,03,10‘,‘1‘,2,2,0,0]

先來分析一下這個字符串的特點,才能找到思路哦:

1.每一組數據都是在[]括號對中,每一組數據用,號分割,所以最終要形成一個數組來訪問哦。

2.每一組的數據基本都是用 , 號分割,字符串類型還有單引號 ;

3.第7個數組是一個整體,也使用,號分割,整體是字符串有引號;

4.第2組數據有空值,直接用,號分割,所以splite的時候不能去掉空值,否則數組長度不一樣,定位就亂了。

既然分析都完了,那思路呢?

1.組直接分割使用 ], 標記,然後每一組要Repalce掉 [ 和 ] 。主要是最前和最後;

2.組內分割,使用 ,號標記分割,出來之前要把單引號給 替換掉 ;不然也是作為字符串,引號也包括進去了;

3.至於那個 數組 的處理,不能過於想復雜,分割之後,直接在最後增加1個元素,將固定位置7-12的組合起來;這樣也許方便點;

4.由於空值有占位,所以每一組的長度是固定的。所以處理的時候直接根據自己想要的位置來組合。

下面看看代碼了,C#版本,相對與一行代碼,仔細看,Linq很是一個神器,真的是神奇。。。說多了都是淚,為啥就沒早點學呢:

1 2 3 4 5 6 7 8 9 10 11 String str = @"[11101630,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,05,48‘,‘4‘,1,2,0,0],[11101631,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,09,48‘,‘0‘,,,0,0],[11101632,1532,14,‘0‘,‘0‘,3,‘2015,4,23,16,03,10‘,‘1‘,2,2,0,0]"; var result = str.Split(new string[] { "]," }, StringSplitOptions.None) //先整體分割組 .Select(n => n.Replace("[", "") //以下是組內分割,並去掉其他幹擾字符 .Replace("]", "") .Replace("\‘", "") .Split(‘,‘).ToList()) .Select(n => //對中間一個整體單獨提取,進行組合,單獨增加一個元素 { n.Add(String.Format("{0},{1},{2},{3},{4},{5}", n[6], n[7], n[8], n[9], n[10], n[11]));return n; }).ToList();

看看結果怎麽樣:

技術分享

回到目錄

2.鍵值對字符串分割函數

  由於json數據格式都是鍵值對字符串,所以這裏特意分享一個經常用到的分割函數,不用Json組件,那就用簡單的方法做一個。這個函數來源於Newlife.Core,是X組件的重要部分。源碼部分不過多解釋,就是按規則將鍵值對直接分割保持在字典中,使用方法大家可以自己實驗一下,或者參考下面的案例,都有用到這個方法。代碼如下,為了方便使用,寫成了擴展方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static class StringHelper { /// <summary>拆分字符串成為名值字典</summary> /// <param name="str">要分割字符串的</param> /// <param name="nameValueSeparator">鍵值對的分隔符</param> /// <param name="separators">分割字符</param> /// <returns>鍵值對字典</returns> public static IDictionary<String, String> SplitAsDictionary(this String str, String nameValueSeparator = "=", params String[] separators) { var dic = new Dictionary<String, String>(); if (String.IsNullOrWhiteSpace(str)) return dic; if (String.IsNullOrEmpty(nameValueSeparator)) nameValueSeparator = "="; if (separators == null || separators.Length < 1) separators = new String[] { ",", ";" }; String[] ss = str.Split(separators, StringSplitOptions.RemoveEmptyEntries); if (ss == null || ss.Length < 1) return null; foreach (var item in ss) { Int32 p = item.IndexOf(nameValueSeparator); // 在前後都不行 if (p <= 0 || p >= item.Length - 1) continue; String key = item.Substring(0, p).Trim(); dic[key] = item.Substring(p + nameValueSeparator.Length).Trim(); } return dic; } }

上面默認的鍵值對分割符號為 = 號,根據實際情況進行修改,json格式裏面一般是:冒號比較多。

回到目錄

3.復雜Json格式的字符串

上面的例子比較簡單,這次看一個稍微復雜點的,雖然可能用JsonMapper可以很輕易做到,但試一下最原始的方法吧。還是按照上面的思路,先分析字符串的特點:字符串是連在一起,沒有換行的,為了方便觀察,換行了,程序是原始在一起的:

1 2 3 4 5 6 7 {1074:[‘墨聯‘,‘墨聯‘,‘MEX D1‘,‘#098000‘,‘98‘], 2100:[‘美乙‘,‘美乙‘,‘USL D2‘,‘#E89B10‘,‘98‘], 1024:[‘阿甲‘,‘阿甲‘,‘ARG‘,‘#00CCFF‘,‘98‘], 1052:[‘哥倫甲‘,‘哥倫甲‘,‘COLCMA‘,‘#888500‘,‘98‘], 1028:[‘K聯賽‘,‘K聯賽‘,‘KORL‘,‘#F75000‘,‘98‘], 1297:[‘球會友誼‘,‘球會友誼‘,‘CF‘,‘#5691D8‘,‘98‘], 2085:[‘奧女甲‘,‘奧女甲‘,‘AFB‘,‘#D86220‘,‘97‘]}

還是先分析特點,這個格式應該是json類似的了,比較規則:

  1. 組與之間是使用 , 號分割;前後有{}括號對;觀察前後可以使用 ], 字符串將組分開;

  2. 鍵 是整數,鍵值是通過 : 號分割;

  3. 值是一個數組,有5個元素,通過 , 號分割

  4. 都有單引號,需要過濾掉;其他沒有特殊情況;

代碼解決過程:

1 2 3 4 5 6 7 string text = @"{1074:[‘墨聯‘,‘墨聯‘,‘MEX D1‘,‘#098000‘,‘98‘],2100:[‘美乙‘,‘美乙‘,‘USL D2‘,‘#E89B10‘,‘98‘],1024:[‘阿甲‘,‘阿甲‘,‘ARG‘,‘#00CCFF‘,‘98‘],1052:[‘哥倫甲‘,‘哥倫甲‘,‘COLCMA‘,‘#888500‘,‘98‘],1028:[‘K聯賽‘,‘K聯賽‘,‘KORL‘,‘#F75000‘,‘98‘],1297:[‘球會友誼‘,‘球會友誼‘,‘CF‘,‘#5691D8‘,‘98‘],2085:[‘奧女甲‘,‘奧女甲‘,‘AFB‘,‘#D86220‘,‘97‘]}"; var dic = text.Replace("\‘", "").Split(new String[]{"],"}, StringSplitOptions.None) //先組分割 .Select(n => n.Replace("{", "").Replace("}", "") //將組裏面的幹擾字符過濾掉 .Replace("[", "").Replace("]", "") .SplitAsDictionary(":", "\"") //鍵值對處理,冒號分隔符 .ToDictionary(t => t.Key, t => t.Value.Split(‘,‘)//值再次進行分割,形成數組 )).ToArray();

看看結果如何:

技術分享

回到目錄

4.標準的json格式

在實際的采集過,可能會碰到直接url,返回的就是json格式,比較標準。這裏舉個例子,如下面這個頁面鏈接:

http://d.dacai.com/zhishu/CorrectCorp.html?matchId=1899040&matchStatusId=41

點擊開後,是這個樣子:

這個應該夠復雜了,我們分析一下,篇幅較大,源碼對照鏈接:

  1. 每一大組數據,是用,號分割;整體也是前後大括號對{},有4個大類,鍵分布是:IndBodans,IndEvenGoals,IndGoalss,IndHalfFulls。

  2. 每一組的子類中,包括的都是同一個類型的數據,每一個子數據組都有N多個小的鍵值對,如MatchId,CorpId等等,使用},可以分割

    分析完成之後如何解決,思路是類似的,先整體分割,使用},進行,然後每一個之類作為鍵,對值再次進行分割。。。形成字典列表。其中的引號也是需要過濾的,至於數值類型,實際用到那個的時候,都是根據key去找,再進行Convert轉換就可以了。看看源代碼:

1 2 3 4 5 6 7 var dicList = doc.Split("{\"IndBodans\":[", "],\"IndEvenGoals\":[", //大類分割 "],\"IndGoalss\":[", "],\"IndHalfFulls\":[", "]}") .Select(n => n.Replace("\"", "").Split("},{")//對每個大類處理,先過濾,再分割為子類 .Select(k => k.Replace("{", "").Replace("}", "")//對子類過濾 .SplitAsDictionary(":", ","))//提取子類的鍵值對 .ToArray() ).ToList();//列表

看看解析的結果如何:

技術分享

註意,有元素是空值的,可以不用管。至於那幾個鍵值對數組,最終屬於哪一個大類?雖然沒有直接標記出來,但是這個問題隨便加一個判斷就可以了,因為每一個類別的鍵名稱是不一樣的,看看是否包括對應的鍵就可以確定類別。

回到目錄

用原始方法解析復雜字符串,json一定要用JsonMapper麽?