2017-06-22 4 views
2

j'ai données venant à travers dans une requête HTTP en-tête (Autoriser) qui est similaire à ce qui suit:Parse virgule délimitée paires de valeurs clés

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

Je souhaite obtenir dans un KeyValuePair

Parsing ces données se révèle difficile en raison de

  • clés et des valeurs ne sont indiquées si elles contiennent des caractères non alphanumériques
  • Key Les s et les valeurs peuvent contenir des virgules, des guillemets (échappés) et des symboles égaux

De quelles options ai-je besoin pour traiter cela? J'ai essayé des bibliothèques CSV, mais je me retrouve avec des résultats incorrects.

+0

Le serveur à partir duquel vous obtenez des données peut-il être modifié? Si oui, la meilleure solution sera de normaliser la réponse du serveur. –

+0

@ S.Petrosov Il est déjà normalisé. Toutes les valeurs de texte sont entre guillemets, les guillemets dans les champs sont échappés. Les valeurs de clé avec des caractères spéciaux sont également citées. – John

Répondre

1

J'ai entendu beaucoup de gens dire: Si vous résolvez un problème avec une expression régulière que vous avez deux problèmes. Eh bien ... Si vous n'avez pas envie d'écrire votre propre analyseur ... Ce petit monstre fonctionne bien:

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

C'est super merci. Je ne vais même pas essayer de donner un sens au Regex! – John

+0

Je veux que vous pouvez disséquer cette chose pour vous et expliquer les différentes parties. En outre, je suis sûr que quelqu'un avec de meilleures compétences regex pourrait réécrire cela d'une manière plus courte ... – dnickless

0

Ce code doit faire le travail:

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(); 
    } 
}