Parse namevalue collection with quotation marks handling

Parsing of namevalue collections is a common pattern. .NET have build in parsing of Query Strings, and other bloggers have solutions on how to do this.

This is Yet Another NameValueCollection parser. It will parse not only query strings, but also other collections. This query string can be parsed:

  • id=2&title=hello&subtitle=world
    • id = 2
    • title = hello
    • subtitle = world

But also more complex strings, where your seperators are inside quotation marks can be parsed. For example:

  • id=2|title=’hello=world‘|subtitle=’sub|title
    • id = 2
    • title = hello=world
    • subtitle = sub|title

Ignoring seperators inside quotes (” and “”) requires more complex code than just calling the Split() function on a string, but the code is not that complex.
This class parses any name/value collection string, ignoring seperators inside quotes (” and “”):

using System;
using System.Collections;
using System.Collections.Generic;

namespace PT.MyCode
{
  internal class NameValueCollectionParser
  {
    public NameValueCollectionParser(char innerSeperator, char outerSeperator)
    {
      InnerSeperator = innerSeperator;
      OuterSeperator = outerSeperator;
    }

    public char InnerSeperator { get; private set; }
    public char OuterSeperator { get; private set; }

    public void GetNameValueSet(string nameValueColection, ref Dictionary<string, string> output)
    {
      foreach (string nameValueSet in Split(nameValueColection, OuterSeperator))
      {
        string[] nameValueSetSplitted = Split(nameValueSet, InnerSeperator);
        if (nameValueSetSplitted.Length != 2)
          return;
        output.Add(nameValueSetSplitted[0], nameValueSetSplitted[1]);
      }
    }

    private string[] Split(string values, char seperator)
    {
      var list = new ArrayList();
      bool insidePlings = false;
      int ac = 0;
      int begin = 0;
      CharEnumerator en = values.GetEnumerator();
      while (en.MoveNext())
      {
        if (en.Current == '\'' || en.Current == '\"')
        {
          if (insidePlings)
            insidePlings = false;
          else
            insidePlings = true;
        }
        else if (en.Current == seperator && !insidePlings)
        {
          string s = Trim(values.Substring(begin, ac - begin));
          list.Add(s);
          begin = ac + 1;
        }
        ac++;
      }
      list.Add(Trim(values.Substring(begin, values.Length - begin)));

      return list.ToArray(typeof (string)) as string[];
    }

    private string Trim(string s)
    {
      s = s.TrimStart(',');
      s = s.TrimStart('\'', '\"');
      s = s.TrimEnd('\'', '\"');
      s = s.Trim();
      return s;
    }
  }
}

The class is prepared to be used in an Extension method on the Dictionary class:

using System.Collections.Generic;

namespace PT.MyCode
{
  internal static class DictionaryExtension
  {
    public static void AddNameValueCollection(this Dictionary<string, string> dictionary, char outerSeperator, char innerSeperator, string value)
    {
      NameValueCollectionParser parser = new NameValueCollectionParser(innerSeperator, outerSeperator);
      parser.GetNameValueSet(value, ref dictionary);
    }

  }
}

The extension method is now ready to be used:

Dictionary<string, string> attributes = new Dictionary<string, string>();
attributes.AddNameValueCollection('|', '=', "id=2|title=\"hello=world\"|text=\"tell me how|you are doing\"");

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in .net, c#, General .NET and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s