2017-06-22 44 views
2

我有數據在HTTP請求(授權)報頭,其類似於以下未來通過:解析逗號分隔的關鍵值對

name="Dave O'Connel", "e-mail"="[email protected]", epoch=1498158305, "other value"="some arbitrary\" text, with comma = and equals symbol" 

我想獲得它變成一個KeyValuePair

解析這個數據被證明是困難的,因爲

  • 項和值,如果它們包含只引用非字母數字字符
  • 關鍵s和值可能包含逗號,(轉義)雙引號和等於符號

我需要哪些選項來處理?我試過CSV庫,但最終得到不正確的結果。

+0

從中獲取數據的服務器可以修改嗎?如果是的話,最好的解決方案是標準化來自服務器的響應。 –

+0

@ S.Petrosov它已經正常化了。所有文本值都被引用,字段中的引號被轉義。帶有特殊字符的鍵值也被引用。 – John

回答

1

我聽到很多人說:如果解決一個問題,你有兩個問題正則表達式。哦,好吧......如果你不想寫自己的語法分析器......這個小怪物效果很好:

public class Program 
    { 
     static void Main(string[] args) 
     { 
      Regex regex = new Regex("^(?:(?:[, ]+)?(?\'q\'\")?(?\'key\'[^=\"]*?)(?:\\k\'q\'(?\'-q\'))?=(?\'q\'\")?(?\'value\'(?:[^\"]|(?<=\\\\)\")*)(?:\\k\'q\'(?\'-q\'))?)*(?(q)(?!))$", RegexOptions.Compiled); 

      string s = "name=\"Dave O\'Connel\", \"e-mail\"=\"[email protected]\", epoch=1498158305, \"other value\"=\"some arbitrary\\\" text, with comma = and equals symbol\""; 

      Match match = regex.Match(s); 

      if (match.Success) 
      { 
       var keys = match.Groups["key"].Captures; 
       var values = match.Groups["value"].Captures; 

       for (int i = 0; i < keys.Count; i++) 
       { 
        Console.WriteLine(keys[i] + " = " + values[i]); 
        // this prints: 
        // name = Dave O'Connel 
        // e-mail = [email protected] 
        // epoch = 1498158305, 
        // other value = some arbitrary\" text, with comma = and equals symbol 
       } 
      } 

      Console.ReadLine(); 
     } 
    } 
+0

非常感謝。我甚至不會嘗試理解正則表達式! – John

+0

我希望我可以爲你剖析這個東西,並解釋個別部分。另外,我相信有更好的正則表達式技能的人可以用更短的方式重寫這個... – dnickless

0

此代碼應該做的工作:

class Program 
{ 
    static string Preprocess(string s) 
    { 
     bool esc = false, quoted = false; 
     StringBuilder sb = new StringBuilder(); 
     foreach (var c in s) 
     { 
      if (c == '\\' && !esc) 
       esc = true; 
      else 
      { 
       if (c == '\"' && !esc) 
        quoted = !quoted; 
       else 
       { 
        if (c == '=' && quoted) 
         sb.Append('~'); 
        else if (c == ',' && quoted) 
         sb.Append(';'); 
        else 
         sb.Append(c); 
       } 
       esc = false; 
      } 
     } 
     return sb.ToString(); 
    } 

    static string Postprocess(string s) 
    { 
     return s.Replace('~', '=').Replace(';', ','); 
    } 

    static Dictionary<string, string> MakeKeyValueList(string str) 
    { 
     var dict = new Dictionary<string, string>(); 
     foreach (var kvp in Preprocess(str).Split(',')) 
     { 
      string[] kv = kvp.Split(new char[] { '=' }, 2); 
      if (kv.Length == 2) 
       dict[Postprocess(kv[0]).Trim()] = Postprocess(kv[1]).Trim(); 
     } 
     return dict; 
    } 

    static void Main(string[] args) 
    { 
     var dict = MakeKeyValueList("name=\"Dave O'Connel\", \"e-mail\"=\"[email protected]\", epoch=1498158305, \"other value\"=\"some arbitrary\\\" text, with comma = and equals symbol\""); 
     foreach (var kvp in dict) 
      Console.WriteLine(kvp.ToString()); 
     Console.ReadKey(); 
    } 
}