String data to be converted to Dictionary - c#

I have a String
string data = "[City, Delhi]&[State, DL]&[Country, IN]";
from which I want a dictionary.
The approach I thought was
Split on "&"
In the resulting Array, parse each element
2.1 Replace "[" and "]"
2.2 Insert into the Dictionary
I hate this approach because my string already has "[" and "]" and I should be able to add it directly to Dictionary.

This is a good use case for regular expressions.
var d = Regex.Matches(data, #"\[(?<k>[^,]+), (?<v>[^]]+)\]")
.OfType<Match>()
.ToDictionary(m => m.Groups["k"].Value, m => m.Groups["v"].Value);

The approach you describe is probably as good as it's going to get.
A naive implementation (without error handling) would be:
var pairs = data.Split('&');
var dict = new Dictionary<string, string>();
foreach (var pair in pairs)
{
var parts = pair.Split(',');
dict.Add(
parts[0].TrimStart('['),
parts[1].TrimStart().TrimEnd(']'));
}
Or, using a regular expression to obtain the keys and values:
string data = "[City, Delhi]&[State, DL]&[Country, IN]";
var pairs = data.Split('&');
var dict = new Dictionary<string, string>();
var regex = new System.Text.RegularExpressions.Regex(#"\[(?<key>.*), (?<value>.*)\]");
foreach (var pair in pairs)
{
var match = regex.Match(pair);
// TODO: Error if match.Success == false ?
dict.Add(match.Groups["key"].Value, match.Groups["value"].Value);
}

You can try this using linq
string data = "[City, Delhi]&[State, DL]&[Country, IN]";
string[] arr = data.Replace("[", "").Replace("]", "").Split('&');
var dict = arr.ToList().ToDictionary(x => x.Split(',')[0], x => x.Split(',')[1]);

Try this...
private static void Splitter()
{
string data = "[City, Delhi]&[State, DL]&[Country, IN]";
Dictionary<string,string> dOutput = new Dictionary<string,string>();
string[] sArr = data.Split('&');
var v = from p in sArr
select p.Replace("[", "").Replace("]", "").Split(',');
var v2 = (from p in v
select p).ToDictionary(item => item[0], item => item[1]);
Console.WriteLine(v2.Count());
}
v2 is a dictionary object...

Related

converting a dictionary of dictionary to string

i have a dictionary of dictionaries:
Dictionary<string, Dictionary<char, string>> myDict;
i'm trying to output its contents by overriding the to string method but i cant figure out how to convert it to string.
i tried:
StringBuilder str = new StringBuilder();
foreach (Dictionary<string, Dictionary<char, string>> s in str)
{
myDict.Append(s.Keys).Append(",").Append(s.Values);
}
this did not work
Your version tries printing s.Keys and s.Values, which are both collections. You can print them using a loop, but you could use string.Join twice instead:
public override string ToString() {
return string.Join(
",",
myDict.Select(
p => string.Format(
"{0}:{1}",
p.Key,
string.Join(",", p.Value.Select(x => string.Format("{0}={1}", x.Key, x.Value)))
)
);
}
Note 1: the above syntax uses string.Format, rather than string interpolation, in both calls. If you are using a newer version of C#, you could rewrite it for a somewhat shorter code, for example
string.Join(",", p.Value.Select(x => $"{x.Key}={x.Value}"))
Note 2: For older versions of .NET add ToArray() after both selects:
return string.Join(
",",
myDict.Select(
p => string.Format(
"{0}:{1}",
p.Key,
string.Join(",", p.Value.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray())
).ToArray()
));
Consider using Newtonsoft.Json, which supports serializing dictionaries to string.
var values = new Dictionary<string, IDictionary<char, string>>
{
{
"test", new Dictionary<char, string>
{
['a'] = "apple",
['b'] = "banana",
['c'] = "cat"
}
},
{
"lights", new Dictionary<char, string>
{
['c'] = "compact fluorescent",
['l'] = "light emitting diode",
['i'] = "incandescent"
}
}
};
Console.WriteLine(JsonConvert.SerializeObject(values));
Output:
{"test":{"a":"apple","b":"banana","c":"cat"},"lights":{"c":"compact fluorescent","l":"light emitting diode","i":"incandescent"}}
Try this one:
StringBuilder str = new StringBuilder();
foreach (var s in myDict)
{
foreach (var i in s.Value)
{
//Key is char, Value is string
str.Append("(")
.Append(s.Key)
.Append(",")
.Append(i.Key)
.Append(",")
.Append(i.Value)
.Append("),");
}
}
//remove trailing ","
var s = str.ToString().Trim(",");

C# .net regex extracting a string from within a string

I have a string output that looks like this:
ID = GC5c.U.feab4bc5-8-92e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31
How can I iterate through the ID(s) of this list and obtain the values within the string?
Open the file, iterate through each line, and put it into a Dictionary<string, string>
Dictionary<string, string> data = new Dictionary<string, string>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(line[0].TrimEnd(), line[1].TrimStart());
}
}
UPDATE: Note that this solution is using Dictionary, and so it does not allow duplicate keys. If you need to duplicate keys, I would suggest changing this solution for a List<KeyValuePair<string, string>>. The code will get a little dirtier by the way:
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(new KeyValuePair(line[0].TrimEnd(), line[1].TrimStart()));
}
}
I am not sure Regex is the best suited for this scenario, however, please find below a solution using it with a named group "id".
var regex = new Regex(#"id.*=\s*(?<id>.+)", RegexOptions.IgnoreCase);
var input = #"ID = Gs3c.H.feab4bc5-6c00-4ee8-9e2e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31";
var ids = regex.Matches(input).Cast<Match>().Select(m => m.Groups["id"]);
Here is the Regex test: Regex test
NicoRiff's suggestion of using regular parsing into a Dictionary is the way to go. Here's the obligatory LINQ-based approach:
var data = File.ReadLines("C:/your/file/path.txt")
.Select(l => l.Split('='))
.ToDictionary(k => k[0], v => v[1]);
EDIT: As Nico pointed out, when the dictionary is going to contain duplicate keys, then a dictionary won't work. However, you can still use LINQ to automatically arrange the dictionary so that the ID field of your source text is the key instead of the field names. For example, you can use the following:
var data = File.ReadLines("C:/your/file/path.txt")
.Where(l => !String.IsNullOrEmpty(l))
.Select((l, i) => new { ID = i / 4, Value = l.Split('=') })
.GroupBy(x => x.ID)
.Select(g => new { ID = g.First().Value[1].Trim(), Values = g.ToDictionary(k => k.Value[0].Trim(), v => v.Value[1].Trim()) })
.ToDictionary(k => k.ID, v => v.Values);
Afterwards, you can iterate through data to get your fields:
foreach (var d in data.Values)
{
string id = d["ID"];
string aesKey1 = d["AESKEY1"];
string aesKey2 = d["AESKEY2"];
string desKey1 = d["DESKEY1"];
}
If you like to put the data into a dictionary like: Dicationary<string, Dictionary<string,string>>
Where the key of the main dictionary is the value of ID, and the internal dictionaries are the values that follows, then the following would do it:
string[] lines = input.Split('\n');
var myDict = new Dictionary<string, Dictionary<string,string>>();
var currentKey = "";
foreach (string[] keyVal in lines.Where(line=>!string.IsNullOrWhiteSpace(line))
.Select(line => line.Split('=')))
{
if (keyVal[0].StartsWith("ID"))
{
currentKey = keyVal[1].Trim();
myDict.Add(currentKey, new Dictionary<string, string>());
}
else
{
myDict[currentKey].Add(keyVal[0].Trim(), keyVal[1].Trim());
}
}
The Regex would look like so:
#"^ID\s+=\s+(.+)$"
You can test it on Regex101 and Rextester

How to Sort NameValue Collection and Store it in a string

Here I am storing two set of querystring parameters into two different namevalue collection. The querystring parameter order may vary so I just want to sort the order and then I need to store namevalue collection to a string.
Updated Code :
string url1 = #"http://www.somewebsitesampletest.com/dcs7o?data=142248494&dcp=smre&nparam=4567P&email=xxx.com";
string url2 = #"http://www.somewebsitesampletest.com/dcs7o?dcp=smre&data=142248494&email=xxx.com&nparam=4567P";
var NameValueCollection1 = HttpUtility.ParseQueryString(url1);
var NameValueCollection2 = HttpUtility.ParseQueryString(url2);
ExpectedResult:
After Sorting and converting to string the result should look like the below one
string query1 = "data=142248494&dcp=smre&email=xxx.com&nparam=4567P";
string query2 = "data=142248494&dcp=smre&email=xxx.com&nparam=4567P";
Here's a solution using Linq.
Basically it changes the NameValueCollection to an IEnumerable of the keys using Cast<T>, then the rest is fairly self explanatory.
public string GetSortedQueryString(string url)
{
var queryString = HttpUtility.ParseQueryString(url);
// Ignore null keys (caused by your ?& at the start of the query string
var orderedKeys = queryString.Cast<string>().Where(k => k != null).OrderBy(k => k);
return string.Join("&", orderedKeys.Select(k => string.Format("{0}={1}", k, queryString[k])));
}
Results for your URLs would be:
data=142248494&dcp=smre&email=xxx.com&nparam=4567P
data=142248494&dcp=smre&email=xxx.com&nparam=4567P
Email comes before nparam, unlike your expected solution (I'm assuming that was a mistake).
use LINQ with a Dictionary and a list of KeyValuePair :
string url1 = #"http://www.somewebsitesampletest.com/dcs7o?&data=142248494&dcp=smre&nparam=4567P&email=xxx.com";
string query1 ="";
Dictionary<String, String> paramDict = new Dictionary<string, string>();
var query = from match in urlString.Split('?').Where(m => m.Contains('='))
.SelectMany(pr => pr.Split('&'))
where match.Contains('=')
select new KeyValuePair<string, String>(
match.Split('=')[0],
match.Split('=')[1]);
query.ToList().ForEach(kvp => paramDict.Add(kvp.Key, kvp.Value));
var List<KeyValuePair<string, string>> paramList = paramDict.ToList();
paramList.Sort();
foreach (KeyValuePair<string, int> pair in list)
{
query1+=pair.Key+"="+pair.Value+"&";
}
query1=query1.TrimEnd('&');
I made this fiddle because I needed to sort querystring values in order to properly compare URIs: (H/T to Jacob's answer)
https://dotnetfiddle.net/eEhkNk
This preserves duplicate keys:
public static string[] QueryStringOmissions = new string[] { "b" };
public static NameValueCollection SortAndRemove(NameValueCollection collection)
{
var orderedKeys = collection.Cast<string>().Where(k => k != null).OrderBy(k => k);
var newCollection = HttpUtility.ParseQueryString(String.Empty);
foreach(var key in orderedKeys)
{
if (!QueryStringOmissions.Contains(key))
{
foreach(var val in collection.GetValues(key).Select(x => x).OrderBy(x => x).ToArray())
{
newCollection.Add(key, val);
}
}
}
return newCollection;
}

C# regex to extract key value

Is there an easy and elegant way to extract key value pairs from a string of below format?
"key1='value1' key2='value 2' key3='value3' key4='value4' key5='5555' key6='xxx666'"
My attempt resulted in this but I'm not too happy with it
var regex = new Regex(#"\'\s", RegexOptions.None);
var someString = #"key1='value1' key2='value 2' key3='value3' key4='value4' key5='5555' key6='xxx666'" + " ";
var splitArray = regex.Split(someString);
IDictionary<string, string> keyValuePairs = new Dictionary<string, string>();
foreach (var split in splitArray)
{
regex = new Regex(#"\=\'", RegexOptions.None);
var keyValuArray = regex.Split(split);
if (keyValuArray.Length > 1)
{
keyValuePairs.Add(keyValuArray[0], keyValuArray[1]);
}
}
You should be able to do it without a split, using a MatchCollection instead:
var rx = new Regex("([^=\\s]+)='([^']*)'");
var str = "key1='value1' key2='value 2' key3='value3' key4='value4' key5='5555' key6='xxx666'";
foreach (Match m in rx.Matches(str)) {
Console.WriteLine("{0} {1}", m.Groups[1], m.Groups[2]);
}
Demo.
The heart of this solution is this regular expression: ([^=\\s]+)='([^']*)' It defines the structure of your key-value pair: a sequence of non-space characters defines the key, then there's an equal sign, followed by the value enclosed in single quotes. This solution goes through the matches in sequence, extracting keys and values, which are assigned to matching groups Group[1] and Group[2], in this order.
Another way to do it:
var someString = #"key1='value1' key2='value 2' key3='value3' key4='value4' key5='5555' key6='xxx666'" + " ";
Dictionary<string, string> dic = Regex.Matches(someString, #"(?<key>\w+)='(?<value>[^']*)'")
.OfType<Match>()
.ToDictionary(m => m.Groups["key"].Value, m => m.Groups["value"].Value);
You can do it like this
var str = "key1='value1' key2='value 2' key3='value3' key4='value4' key5='5555' key6='xxx666'";
var arr = Regex.Split(str, "(?<=')\\s(?=\\w)"); // split on whitespace to get key=value
foreach(var s in arr) {
var nArr = s.Split("="); // split on = to get key and value
keyValuePairs.Add(nArr[0], nArr[1]);
}
(?<=')\s(?=\w) will look for space which is after ' and before the start of the key

splitting string in dictionary

How do I split the following string
string s = "username=bill&password=mypassword";
Dictionary<string,string> stringd = SplitTheString(s);
such that I could capture it as follows:
string username = stringd.First().Key;
string password = stringd.First().Values;
Please let me know. Thanks
You can populate the dictionary list like so:
Dictionary<string, string> dictionary = new Dictionary<string, string>();
string s = "username=bill&password=mypassword";
foreach (string x in s.Split('&'))
{
string[] values = x.Split('=');
dictionary.Add(values[0], values[1]);
}
this would allow you to access them like so:
string username = dictionary["username"];
string password = dictionary["password"];
NOTE: keep in mind there is no validation in this function, it assumes your input string is correctly formatted
It looks like you are trying to parse a query string - this is already built in, you can use HttpUtility.ParseQueryString() for this:
string input = "username=bill&password=mypassword";
var col = HttpUtility.ParseQueryString(input);
string username = col["username"];
string password = col["password"];
I think something similar to this should work
public Dictionary<string, string> SplitTheStrings(s) {
var d = new Dictionary<string, string>();
var a = s.Split('&');
foreach(string x in a) {
var b = x.Split('=');
d.Add(b[0], b[1]);
}
return d;
}
var splitString = "username=bill&password=pass";
var splits = new char[2];
splits[0] = '=';
splits[1] = '&';
var items = splitString.Split(splits);
var list = new Dictionary<string, string> {{items[1], items[3]}};
var username = list.First().Key;
var password = list.First().Value;
this my also work
If Keys will not repeat
var dict = s.Split('&').Select( i=>
{
var t = i.Split('=');
return new {Key=t[0], Value=t[1]};}
).ToDictionary(i=>i.Key, i=>i.Value);
If Keys can repeat
string s = "username=bill&password=mypassword";
var dict = s.Split('&').Select( i=>
{
var t = i.Split('=');
return new {Key=t[0], Value=t[1]};}
).ToLookup(i=>i.Key, i=>i.Value);
The other answers are better, easier to read, simpler, less prone to bugs, etc, but an alternate solution is to use a regular expression like this to extract all the keys and values:
MatchCollection mc = Regex.Matches("username=bill&password=mypassword&","(.*?)=(.*?)&");
Each match in the match collection will have two groups, a group for the key text and a group for the value text.
I am not too good at regular expressions so I don't know how to get it to match without adding the trailing '&' to the input string...

Categories

Resources