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
Related
I have a list of json string like this
{}
{"RuleId":"20cf47c5-3674-4a39-8553-00348f860fe7"}
{}
{"RuleId":"3047c5-3674-4a39-7753-003477860fe7"}
{}
{"RuleId":"20cf47c5-3674-4a39-8553-00348f860fe7"}
{"RuleId":"55cf47c5-3674-4a39-8553-00366f860hh7"}
now I want to get the count of element that match a rule id. How to do that with linq
Do the following:
string pattern = #"<a regular expression pattern>";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
var num = jsonList.Count(x => rgx.Matches(JObject.Parse(x)["RuleId"]).Count > 0);
Or in a simple case:
string specifiedId = "<Id>";
var num = jsonList.Count(x => JObject.Parse(x)["RuleId"] == specifiedId);
This is what I understand from your question: count a given id in elements of a list.
var ruleId = "20cf47c5-3674-4a39-8553-00348f860fe7";
var list = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("RuleId", "20cf47c5-3674-4a39-8553-00348f860fe7"),
new KeyValuePair<string, string>("RuleId", "3047c5-3674-4a39-7753-003477860fe7"),
new KeyValuePair<string, string>("RuleId", "20cf47c5-3674-4a39-8553-00348f860fe7"),
new KeyValuePair<string, string>("RuleId", "55cf47c5-3674-4a39-8553-00366f860hh7")
};
var count = list.Count(x => x.Value == ruleId);
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...
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;
}
I have following file names in my files folder
1000_A.csv
1000_B.csv
1000_C.csv
1001_A.csv
1001_B.csv
files names starting with same ID needs to be added to a list and then the list needs to added to a dictionary with ID as key
For ex:
list x contains "1000_A.csv", "1000_B.csv", "1000_C.csv"
add this to a dictionary with ID 1000 as the key Please help.
You can use LINQ's GroupBy:
Dictionary<int, List<string>> idFilenames = fileList
.Select(fileName =>
{
string fnwoe = Path.GetFileNameWithoutExtension(fileName);
string idPart = fnwoe.Split('_').First();
int id;
int.TryParse(idPart, out id);
return new { fileName, id };
})
.GroupBy(x => x.id)
.ToDictionary(g => g.Key, g => g.Select(x => x.fileName).ToList());
var folder = GetFolder();
var files = new Dictionary<int, List<string>>();
foreach (var file in folders)
{
int id = Convert.ToInt32(file.Substring(0, file.IndexOf('_'));
if (files.Any(x => x.Key == id))
files[id].Add(file);
else
{
var newList = new List<string>();
newList.Add(file);
files.Add(id, newList);
}
}
var listOfFiles = ...; // assuming you can read the list of filenames
// into a string[] or IList<string>
var d = listOfFiles.GroupBy( f => f.Substring( 0, f.IndexOf( '_' ) ) )
.ToDictionary( g => g.Key, g => g );
e.g CSV the list of your csv files
Loop through you CSV list:
Dictionary<string, int> Dict = new Dictionary<string, int>();
List<string> files = new List<string>();
foreach (string path CSV)
{
if(!ContainsKey(path.Substring(0,3))
{
files.Add(path);
Dict.Add(path.Substring(0,3),files);
}
else
{
files.Add(path);
Dict[path.Substring(0,3)].Add(file);
}
}
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...