Dividere una stringa da punto e virgola tenendo conto di caratteri di escape
-
21-08-2019 - |
Domanda
Davvero semplice problema:
Voglio dividere una stringa di connessione nelle sue coppie parola chiave / valore, così per esempio la seguente stringa di connessione:
Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=vm-jp-dev2;Data Source=scsql\sql2005;Auto Translate=False
diventerebbero:
Provider=SQLOLEDB.1
Integrated Security=SSPI
Persist Security Info=False
Initial Catalog=vm-jp-dev2
Data Source=scsql\sql2005
Auto Translate=False
Il problema è che la documentazione MSDN afferma che i valori stringa di connessione sono autorizzati a contenere punti e virgola se il valore è racchiuso in caratteri singoli o doppi citazione, (quindi se non ho capito male il seguente sarebbe valido):
Provider="Some;Provider";Initial Catalog='Some;Catalog';...
Che cosa è il modo migliore per spaccare questa stringa (in C #)?
Soluzione
C'è una classe DbConnectionStringBuilder che farà quello che vuoi ...
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]));
}
Altri suggerimenti
Si dovrebbe attuare una sorta di semplice stringa parsing citazioni respecing. Qualcosa del genere:
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);
}
È possibile scrivere un mini-parser. Si muove attraverso il tenere traccia di stringa dello Stato citando. Probabilmente più affidabile in generale.
L'altra opzione è quella di utilizzare un'espressione regolare, e abbinare l'intero contenuto, che può essere bloccata in una regex.Split
anziché saltare l'uscita:
var re = new Regex(@"([\w\s]+=\s*?(?:['""][\w\s]+['""]|[\w\s]+));");
var parts = re.Split(connectionString)
Ciò presuppone:
- Nessun capacità di citare le citazioni all'interno di citazioni (o meno)
- Il contenuto di nomi è limitata a uno spazio bianco e alfa-numerici (sostituire [\ s \ w] con il gruppo che copre caratteri validi).
Personalmente se potessi non allenamento la regex abbastanza rapidamente mi piacerebbe andare con il parser.
EDIT: C'è un modo più semplice. DbConnectionStringBuilder
attrezzi IEnumerable
, in modo da arrivare a fare il lavoro:
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);
}
}
}
In caso di SQL Server si può fare semplicemente:
SqlConnectionStringBuilder decoder = new SqlConnectionStringBuilder(connectionString);
string UserID = decoder.UserID;
string Password = decoder.Password;
ecc.