views:

599

answers:

3

Really simple problem:

I want to split a connection string into its keyword / value pairs, so for example the following connection string:

Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=vm-jp-dev2;Data Source=scsql\sql2005;Auto Translate=False

Would become:

Provider=SQLOLEDB.1
Integrated Security=SSPI
Persist Security Info=False
Initial Catalog=vm-jp-dev2
Data Source=scsql\sql2005
Auto Translate=False

The trouble is that the MSDN documentation states that connection string values are allowed to contain semicolons if the value is enclosed in single or double quote characters, (so if I understand it the following would be valid):

Provider="Some;Provider";Initial Catalog='Some;Catalog';...

Whats the best way of splitting this string (in C#)?

A: 

You should implement some sort of simple string parsing respecing quotes. Something like that:

public static IEnumerable<string> SplitString(string str)
{
    int StartIndex = 0;
    bool IsQuoted = false;
    for (int I = 0; I < str.Length; I++)
    {
        if (str[I] == '"')
            IsQuoted = !IsQuoted;
        if ((str[I] == ';') && !IsQuoted)
        {
            yield return str.Substring(StartIndex, I - StartIndex);        
            StartIndex = I + 1;
        }
    }

    if (StartIndex < str.Length)
        yield return str.Substring(StartIndex);
}
arbiter
A: 

You can write a mini-parser. Moves through the string keeping track of the quoting state. Likely more reliable in general.

The other option is to use a regular expression, and match the whole content, which can be captured in a regex.Split rather than skipping the output:

var re = new Regex(@"([\w\s]+=\s*?(?:['""][\w\s]+['""]|[\w\s]+));");
var parts = re.Split(connectionString)

This assumes:

  • No ability to quote quotes inside quotes (or otherwise)
  • Content on names is limited to white space and alpha-numerics (replace [\s\w] with group that covers valid characters).

Personally if I couldn't workout the regex quite quickly I'd go with the parser.

EDIT: There is an easier way. DbConnectionStringBuilder implements IEnumerable, so get it to do the work:

using System;
using System.Collections.Generic;
using System.Data.Common;

class Program {
    static void Main(string[] args) {
        string conStr = @"Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=vm-jp-dev2;Data Source='scsql\sql;2005';Auto Translate=False";

        var cb = new DbConnectionStringBuilder();
        cb.ConnectionString = conStr;
        int n = 0;
        foreach (KeyValuePair<string, object> c in cb) {
            Console.WriteLine("#{0}: {1}={2}", ++n, c.Key, c.Value);
        }
    }
}
Richard
+6  A: 

There is a DBConnectionStringBuilder class that will do what you want...

        System.Data.Common.DbConnectionStringBuilder builder = new System.Data.Common.DbConnectionStringBuilder();

        builder.ConnectionString = "Provider=\"Some;Provider\";Initial Catalog='Some;Catalog';";

        foreach (string key in builder.Keys)
        {
            Response.Write(String.Format("{0}: {1}<br>", key , builder[key]));
        }
Robin Day
Thanks, I thought there might be something like this but I couldn't find it!
Kragen