2017-06-22 47 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(); 
    } 
}