Parse String with Regex c# - c#

I am trying to customise a DevExpress grid filter.
Currently I return the data from my api, and so I need to parse the built in string which is returned from the grid.
An example of the filter string is;
StartsWith([name], 'test') And StartsWith([quantity], '12') And
StartsWith([id], '1') And StartsWith([date], '01/10/2015')
I would like to convert this to a Dictionary in the most efficient way?

You could use Regex for filtering the key/value pair outta your string and a simple foreach to prepare the dictionary.
This could be a solution:
public static Dictionary<string, object> FilterAPIData(string data)
{
var r = new Regex(#"\[\w+\], \'[\w/]+\'");
var result = r.Matches(data);
var dict = new Dictionary<string, object>();
foreach (Match item in result)
{
var val = item.Value.Split(',');
dict.Add(val[0], val[1]);
}
return dict;
}

Regex might be the best option for this, but I'll show you how to do it without Regex as it can be a bit difficult to understand.
Assuming your string will always be in this format you can do this:
string str = "StartsWith([name], 'test') And StartsWith([quantity], '12') And StartsWith([id], '1') And StartsWith([date], '01/10/2015')";
var strArray = str.Split(new string[]{"And "}, StringSplitOptions.None);
var dict = new Dictionary<string, string>();
foreach(var value in strArray)
{
dict.Add(GetStringBetween(value, "[", "]"), GetStringBetween(value, "'", "'"));
}
private string GetStringBetween(string value, string startDelim, string endDelim)
{
int first = value.IndexOf(startDelim) + startDelim.Length;
int last = value.LastIndexOf(endDelim);
return value.Substring(first, last - first);
}
//Output :
//name test
//quantity 12
//id 1
// date 01/10/2015
If there other formats the string can be in you can adjust as needed. I would also consider adding in more validation/error handling, but I will let you figure that out ;)

Related

How to URL encode a dictionary in C# with bracket notation

Let's say I have the following class:
public class TestClass
{
public Dictionary<string, string> Property1 { get; set; }
}
If I do the following:
var dictionary = new Dictionary<string, string>();
dictionary.add("key1", "value1");
dictionary.add("key2", "value2");
var newClass = new TestClass();
newClass.Property1 = dictionary;
I am trying to URL encode this dictionary to the following:
https://baseaddress.com/resource/?Property1[key1]=value1&Property1[key2]=value2
When attempting to URL encode the dictionary via HttpUtility it is returning the ToString() method of the Dictionary which comes out as:
System.Collections.Generic.Dictionary`2[System.String,System.String]
I am trying to pass this dictionary to a .netcore API that binds to a similar Dictionary<string, string>
Edit
I was able to get it working by using the following code:
var builder = new UriBuilder(uri);
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (var propInfo in obj.GetType().GetProperties())
{
var propName = propInfo.Name;
var propValue = propInfo.GetValue(obj);
if (propValue != null)
{
var dict = propValue as IDictionary;
if (dict != null)
{
foreach (var key in dict.Keys)
{
var keyName = key;
var keyValue = dict[key];
query.Add($"{propName}[{keyName}]", keyValue.ToString());
}
}
else
{
query.Add(propName, propValue.ToString());
}
}
}
builder.Query = query.ToString();
return builder.Uri;
I was hoping there was a more efficient way to make this work.
If you want to get the standard format and avoid any problem with your QueryString you can "leverage" .net core approach which indeed is a way larger than the old approach. With that said here is what you can do:
One thing....Notice that they are strings so you can add your brackets :)
Dictionary<String,StringValues>() queryString = QueryHelpers.ParseQuery("?param1=value");
StringValues secondValue=StringValues.Concat(queryString["param2"], "my other value");
parsedQueryString["yourkey"] = secondValue;
//At this point you can start concatenating as many time as needed.
QueryString.Create(parsedQueryString).ToString();
// creates the following string "?param1=value&param2=my%20other%20value"
A plus :)
// Getting a param value
var param2Value = queryString["param2"];
param2Value.ToString(); // Get the values concatenated together
param2Value.ToArray(); // Gets an array of strings
// Modifying a parameter
queryString["param1"] = "another value";
// NOTE, if there were two values, this overwrites both and leaves a single value

Format string with dictionary in C#

Suppose I had the following code in Python (yes, this question is about c# this is just an example)
string = "{entry1} {entry2} this is a string"
dictionary = {"entry1": "foo", "entry2": "bar"}
print(string.format(**dictionary))
# output is "foo bar this is just a string"
In this string, it would replace the {entry1} and {entry2} from the string to foo and bar using the .format()
Is there anyway I can replicate this EXACT same thing in C# (and also remove the curly braces) like the following code:
string str1 = "{entry1} {entry2} this a string";
Dictionary<string, string> dict1 = new() {
{"entry1", "foo"},
{"entry2", "bar"}
};
// how would I format this string using the given dict and get the same output?
using string interpolation you could do the following
Dictionary<string, string> dict1 = new() {
{"entry1", "foo"},
{"entry2", "bar"}
};
string result = $"{dict1["entry1"]} {dict1["entry2"]} this is a string";
You can write an extension method for a dictionary and in it manipulate your string as per your need Like
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public static class DictionaryExtensions
{
public static string ReplaceKeyInString(this Dictionary<string, string> dictionary, string inputString)
{
var regex = new Regex("{(.*?)}");
var matches = regex.Matches(inputString);
foreach (Match match in matches)
{
var valueWithoutBrackets = match.Groups[1].Value;
var valueWithBrackets = match.Value;
if(dictionary.ContainsKey(valueWithoutBrackets))
inputString = inputString.Replace(valueWithBrackets, dictionary[valueWithoutBrackets]);
}
return inputString;
}
}
Now use this extension method to convert given string to the expected string,
string input = "{entry1} {entry2} this is a string";
Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{ "entry1", "foo" },
{ "entry2", "bar" }
};
var result = dictionary.ReplaceKeyInString(input);
Console.WriteLine(result);
RegEx logic credit goes to #Fabian Bigler. Here is Fabian's answer:
Get values between curly braces c#
Try online
You can replace values within {...} with a help of regular expressions:
using System.Text.RegularExpressions;
...
string str1 = "{entry1} {entry2} this a string";
Dictionary<string, string> dict1 = new() {
{ "entry1", "foo" },
{ "entry2", "bar" }
};
string result = Regex.Replace(str1, #"{([^}]+)}",
m => dict1.TryGetValue(m.Groups[1].Value, out var v) ? v : "???");
// Let's have a look:
Console.Write(result);
Outcome:
foo bar this a string
try this
foreach (var d in dict) str1=str1.Replace("{"+d.Key+"}",d.Value);
or if you like the extensions
Console.WriteLine(str1.FormatFromDictionary(dict));
public static string FormatFromDictionary(this string str, Dictionary<string, string> dict)
{
foreach (var d in dict) str = str.Replace("{" + d.Key + "}", d.Value);
return str;
}
You can use a string builder if there are may items to replace in one string
public static string FormatFromDictionary(this string str, Dictionary<string, string> dict)
{
StringBuilder sb = new StringBuilder(str, 100);
foreach (var d in dict) sb.Replace("{" + d.Key + "}", d.Value);
return sb.ToString();
}

find the date y ( probably we have 1000 files 999 have date x and 1 have y date ) and the corresponding file?

Please suggest the simplest way to do the below logic.
we can use data-tables and query from the table?
string[] filePath = Directory.GetFiles(directory, "*.txt",SearchOption.AllDirectories);
Dictionary<string, DateTime> dic = new Dictionary<string, DateTime>();
foreach (string CurrentPath in filePath)
{
string Content = System.IO.File.ReadAllText(#CurrentPath);
string loadedDate = DateTime.ParseExact(Content.Substring(9,8), "yyyyMMdd",
CultureInfo.InvariantCulture).ToString("yyyy/MM/dd");
DateTime Datevalue = DateTime.Parse(loadedDate);
String FileName = Path.GetFileName(CurrentPath);
dic.Add(Path.GetFileName(CurrentPath), Datevalue);
}
Description:
filepath contains the list of .txt file path
Inside the foreach loop reading all the file content and found the date present in the content.
Added all the date valueand the FileName in a Dictionary.
Now i need to find the date which is different and the corresponding filename.
For EG: we have 3 files File1.txt, File2.txt,File3.txt. first 2 files having the date value 25/9/2019
and the 3rd file having the date value 24/9/2019.
here we need to find the date which is different from the other i.e 24/9/2019 and the corresponding
file name File3.txt.
From the dictionary value how can i find the date(date which is different from the other date) and the corresponding file name?.
please suggest the simplest or any-other way to do this logic.
You can use the Dictionary to have a key-value pairs of text files and the extracted dates from them.
string directory = #"C:\";
string[] filePath = Directory.GetFiles(directory, "*.txt", SearchOption.AllDirectories);
Dictionary<string, DateTime> dic = new Dictionary<string, DateTime>();
foreach (string CurrentPath in filePath)
{
string Content = File.ReadAllText(#CurrentPath);
string loadedDate = DateTime.ParseExact(Content.Substring(9, 8), "yyyyMMdd",
CultureInfo.InvariantCulture).ToString("yyyy/MM/dd");
DateTime Datevalue = DateTime.Parse(loadedDate);
dic.Add(Path.GetFileName(CurrentPath), Datevalue);
}
Edit
For example, you could add to the dictionary only the distinct dates with their text files. Please refactor the code and try:
string directory = #"C:\";
string[] filePath = Directory.GetFiles(directory, "*.txt", SearchOption.AllDirectories);
Dictionary<DateTime, string> dic = new Dictionary<DateTime, string>();
foreach (string CurrentPath in filePath)
{
string Content = File.ReadAllText(#CurrentPath);
string loadedDate = DateTime.ParseExact(Content.Substring(9, 8), "yyyyMMdd",
CultureInfo.InvariantCulture).ToString("yyyy/MM/dd");
DateTime Datevalue = DateTime.Parse(loadedDate);
if(!dic.ContainsKey(Datevalue))
dic.Add(Datevalue, Path.GetFileName(CurrentPath));
}
Then you can check if the dictionary contains more than one entry which means that you have two or more different dates that you can do whatever you want accordingly.
if (dic.Count > 1)
{ /* You have different dates connected to their files. */ }
Hope it helps.
You can use a helper dictionary with number of occurrences for each date. The method that returns you the fileName, would be like:
public string GetFileName()
{
Dictionary<DateTime, int> dts = new Dictionary<DateTime, int>();
foreach (KeyValuePair<string, DateTime> item in dic)
{
if (dts.ContainsKey(item.Value))
{
dts[item.Value]++;
}
else
{
dts.Add(item.Value, 1);
}
}
var value = dts.Where(x => x.Value == 1).Select(x => x.Key).FirstOrDefault();
foreach (KeyValuePair<string, DateTime> item in dic)
{
if (item.Value == value)
{
return item.Key;
}
}
return "";
}
Your requirement is ambiguous as there is no way to tell which is the right date. However if you want to find a list of dates and the files associated with those dates you can improve your code by making the date as the key.
So your dictionary declaration can change to -
Dictionary<DateTime, List<string>> dic = new Dictionary<DateTime, List<string>>();
Then we can perform lookup on the keys in the dictionary. So you can change this dic.Add(Path.GetFileName(CurrentPath), Datevalue); by a method call like
AddFileName(dic,Path.GetFileName(CurrentPath), Datevalue);
void AddFileName(Dictionary<DateTime, List<string>> fileInfo, DateTime dt, string fileName)
{
if (fileInfo.ContainsKey(dt))
{
var fileList = fileInfo[dt];
fileList.Add(fileName);
}
else
{
fileInfo.Add(dt, new List<string> { fileName });
}
}
And now you have the unique dates and the associated file list to perform the next steps...

Querying key value in List<string>

I have the following code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
I have a predefined object where I need to use a list of strings.
I decided to use a Tuple but I am not sure how I can cast the str value back to a Tuple.
How can I store a key value in a List so that I can use lambda to query it e.g. by the key?
All this code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Could be replaced by a dictionary:
Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("MyKey", "MyValue");
Then you can use linq to query the dictionary if you'd like to do so:
value = values.Where(x => x.ContainsKey("MyKey"));
You can get a list with all the keys as follows:
List<string> keys = values.Keys;
So no need to have a separate list for that.
If you want a list of string with two values separated by a coma, the dictionary will do too:
List<string> keysValues = (from item in values
select item.Key + "," + item.Value).ToList();
Use Dictionary.
var dictionary = new Dictionary<string, string>();
dictionary.Add("myKey", "myVal");
if (dictionary.ContainsKey("myKey"))
dictionary["myKey"] = "myVal1";
I suggest you use a Dictionary. But if you really need to do it this way:
To transform from the string back to Tuple (assuming that the Key itself will never contain a commma+space):
var tuple = Tuple.Create("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Console.WriteLine(str);
int comma = str.IndexOf(", ");
string key = str.Substring(1,comma-1);
string valuee = str.Substring(comma+2,str.Length-key.Length-4);
var tuple2 = Tuple.Create(key, valuee);
// 'tuple2' is now equal to the orignal 'tuple'

C# Convert List<object> to list<hashtable>

This is my first question here, so sorry for any wrong information or about my English.
I need to convert a List<Object> to List<Hashtable>
string IdsLista = string.Empty;
foreach (DataRow rows in ListaItensTransferencia.Rows)
{
IdsLista += Convert.ToString(rows["Id Bem"]) + ",";
}
string[] idsSelecionadosListaTransferencia = IdsLista.Split(',');
List<object> listaIdsSelecionadosListTransferencia = new List<object>(idsSelecionadosListaTransferencia.Length);
listaIdsSelecionadosListTransferencia.AddRange(idsSelecionadosListaTransferencia);
wuc_itensTransferencia.checkBoxGrid = listaIdsSelecionadosListTransferencia;
//v this is the list<hashtable> v this is the list<object>
wuc_itensTransferencia.ItensSelecionados = listaIdsSelecionadosListTransferencia;
How do I do this ?
Instead of putting data into list of object, put directly into list of hashtable. Why you want to create the comma separated string. Try this
List<HashTable> hashTable = new List<HashTable>();
foreach (DataRow rows in ListaItensTransferencia.Rows)
{
hashTable.Add(new HashTable("Id Bem", Convert.ToString(rows["Id Bem"])));
}

Categories