This question already has answers here:
C#6.0 string interpolation localization
(9 answers)
Closed 3 years ago.
I'm working on a system that gets templates from a database, then fills in values programmatically:
//using System.Runtime.CompilerServices;
var template = "Hello {0}"; // this string comes from the database
var name = "Joe";
var message = FormattableStringFactory.Create(template, new object[] { name });
Console.WriteLine(message);
This code sample works, but I can only use the numeric notation. I'd like to store the templates in the database in the interpolated string format, like this:
var template = "Hello {name}";
This throws a Run-time exception (line __): Input string was not in a correct format.
Is it possible to create an interpolated string from a string?
I do something similar in a (probably) weird way.... but it works so i try to share with you my conclusion:
public static string ExtendedStringFormat(this string source, List<Tuple<string, string>> values)
{
string returnvalue = source;
foreach(Tuple<string, string> my_touple in values)
{
returnvalue = returnvalue.Replace(string.Concat('{', my_touple.Item1, '}'), my_touple.Item2);
}
return returnvalue;
}
And you can call it like below:
List<Tuple<string, string>> lst = new List<Tuple<string,string>>();
lst.Add(new Tuple<string, string>("test","YAYYYYYY"));
lst.Add(new Tuple<string, string>("test2","YAYYYYYY22222222"));
string ret = "hem... hi? {test}, {test2}";
ret = ret.ExtendedStringFormat(lst);
Related
This question already has answers here:
How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?
(22 answers)
Closed 2 years ago.
I have a scnerio where i donot know the names of the keys so properties can;t be created beforehand.
The JSON needs to be parsed and loaded into Dictionary that is present in a class.
The format of JSON is like
"SearchCriteria":{
"firstname":"user1",
"surname":"User2"
},
"RequiredGroups":{
"UserGroup":"g1",
"TeacherGroup":"g2"
}
The problem is that the Parameters count and name are not known and can be anything.
The JSON also contains other sections as well such as RequiredGroups which have known key names and are mapped with Objects.
Need to convert into Dictionary. Any leads....
Example using Newtonsoft.Json.Linq:
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string json = #"{'SearchCriteria':{'firstname':'user1','surname':'User2'},'RequiredGroups':{'UserGroup':'g1','TeacherGroup':'g2'}}";
JObject o = JObject.Parse(json);
var dict = o.ToObject<Dictionary<string, object>>();
}
}
string str1 = "{\"SearchCriteria\":{ \"firstname\":\"user1\", \"surname\":\"User2\" }, \"RequiredGroups\":{ \"UserGroup\":\"g1\",\"TeacherGroup\":\"g2\" }}";
var jObject1 = JObject.Parse(str1);
Dictionary<string, string> dictObj = new Dictionary<string, string>();
IList<string> keys = jObject1.Properties().Select(p => p.Name).ToList();
foreach(var k in keys)
{
var s = jObject1[k].ToString();
dictObj.Add(k, s);
}
This question already has answers here:
How can I parse HTTP urls in C#?
(3 answers)
Closed 3 years ago.
I have 2 string
string str="nl/vacature/admin/Employee/home/details/"
and other one
string template ="nl/vacature/{model}/{controller}/{Action}/{Method}/"
I am looking for
model=admin,controller=Employee,Action=home,Method=details
in an object or in dictionary in key-value format.Their URL and template key may be at different order it may be
string template ="vacature/jobcount/{controller}/{Action}/{model}/{Method}/"
string str ="vacature/jobcount/Employee/home/admin/details/"
Try this:
string url = "nl/vacature/admin/Employee/home/details/";
string template = "nl/vacature/{model}/{controller}/{Action}/{Method}/";
// remove unnecessary parts
template = template.Replace("nl/vacature/", "").Replace("{", "").Replace("}", "");
url = url.Replace("nl/vacature/", "");
// dictionary, that will hold pairs, that you want
var dict = new Dictionary<string,string>();
var urlList = url.Split('/');
var templateList = template.Split('/');
for(int i = 0; i < urlList.Length; i++)
{
dict.Add(templateList[i], urlList[i]);
}
I leave to you exception handling in case, that URLs won't consist of the same number of parts.
Here's a Regex solution, but you need to change the template a little bit.
string url = "nl/vacature/admin/Employee/home/details/";
string template = "nl/vacature/(?<Model>.*?)/(?<Controller>.*?)/(?<Action>.*?)/(?<Method>.*?)/";
var matches = Regex.Match(url, template).Groups.Cast<Group>().Where(g => !int.TryParse(g.Name, out _)).ToDictionary(m => m.Name, m => m.Value);
// Dictionary<string, string>(4) { { "Model", "admin" }, { "Controller", "Employee" }, { "Action", "home" }, { "Method", "details" } }
However, external parsing library might be a better fit. You can find some URL parser instead of using regex.
I have a (large) template and want to replace multiple values. The replacement needs to be done case insensitive. It must also be possible to have keys that does not exist in the template.
For example:
[TestMethod]
public void ReplaceMultipleWithIgnoreCaseText()
{
const string template = "My name is #Name# and I like to read about #SUBJECT# on #website#, tag #subject#";
const string expected = "My name is Alex and I like to read about C# on stackoverflow.com, tag C#";
var replaceParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("#name#","Alex"),
new KeyValuePair<string, string>("#subject#","C#"),
new KeyValuePair<string, string>("#website#","stackoverflow.com"),
// Note: The next key does not exist in template
new KeyValuePair<string, string>("#country#","The Netherlands"),
};
var actual = ReplaceMultiple(template, replaceParameters);
Assert.AreEqual(expected, actual);
}
public string ReplaceMultiple(
string template,
IEnumerable<KeyValuePair<string, string>> replaceParameters)
{
throw new NotImplementedException(
"Implementation needed for many parameters and long text.");
}
Note that if I have a list of 30 parameters and a large template, I do not want 30 large strings in memory. Using a StringBuilder seems to be an option, but other solutions are also welcome.
Solution I tried but did not work
Solution found here (C# String replace with dictionary) throws an exception when a key is not in the colletion, but our users makes mistakes and in that case I want to just leave the wromg key in the text. Example:
static readonly Regex re = new Regex(#"\$(\w+)\$", RegexOptions.Compiled);
static void Main2()
{
// "Name" is accidentally typed by a user as "nam".
string input = #"Dear $nam$, as of $date$ your balance is $amount$";
var args = new Dictionary<string, string>(
StringComparer.OrdinalIgnoreCase) {
{"name", "Mr Smith"},
{"date", "05 Aug 2009"},
{"amount", "GBP200"}};
// Works, but not case insensitive and
// uses a lot of memory when using a large template
// ReplaceWithDictionary many args
string output1 = input;
foreach (var arg in args)
{
output1 = output1.Replace("$" + arg.Key +"$", arg.Value);
}
// Throws a KeyNotFoundException + Only works when data is tokenized
string output2 = re.Replace(input, match => args[match.Groups[1].Value]);
}
Using a StringBuilder seems to be an option, but other solutions are also welcome.
Since you want case insensitive, I'd suggest (non StringBuilder):
public static string ReplaceMultiple(
string template,
IEnumerable<KeyValuePair<string, string>> replaceParameters)
{
var result = template;
foreach(var replace in replaceParameters)
{
var templateSplit = Regex.Split(result,
replace.Key,
RegexOptions.IgnoreCase);
result = string.Join(replace.Value, templateSplit);
}
return result;
}
DotNetFiddle Example
This is based off of Marc's answer the only real change is the check during the replacement and the boundary regex rule:
static readonly Regex re = new Regex(#"\b(\w+)\b", RegexOptions.Compiled);
static void Main(string[] args)
{
string input = #"Dear Name, as of dAte your balance is amounT!";
var replacements = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"name", "Mr Smith"},
{"date", "05 Aug 2009"},
{"amount", "GBP200"}
};
string output = re.Replace(input, match => replacements.ContainsKey(match.Groups[1].Value) ? replacements[match.Groups[1].Value] : match.Groups[1].Value);
}
And here is a 5000 iterations test benchmark, have not looked at memory or anything else.
Replacement function is the one you have checked as the accepted answer.
I think I might have something you could try. I used something similar to it for email templates
public string replace()
{
string appPath = Request.PhysicalApplicationPath;
StreamReader sr = new StreamReader(appPath + "EmailTemplates/NewMember.txt");
string template = sr.ReadToEnd();
template = template.Replace("<%Client_Name%>",
first_name.Text + " " + middle_initial.Text + " " + last_name.Text);
//Add Customer data
template = template.Replace("<%Client_First_Name%>", first_name.Text);
template = template.Replace("<%Client_MI%>", middle_initial.Text);
template = template.Replace("<%Client_Last_Name%>", last_name.Text);
template = template.Replace("<%Client_DOB%>", dob.Text);
return template;
}
Inside of your template you can have tags such as <% %> as place holders for the values you want
Hope this helps!
The answer of Marc Gravell: C# String replace with dictionary can be changed an little bit so it does not throws an exception when the match can not be found. In this case it simply does not replace the match.
In case the string to be replace is tokenized, this is the solution:
static readonly Regex RegExInstance = new Regex(#"\$(\w+)\$", RegexOptions.Compiled);
public string ReplaceWithRegEx(string template, Dictionary<string, string> parameters)
{
return RegExInstance.Replace(template, match => GetNewValue(parameters, match));
}
private string GetNewValue(Dictionary<string, string> parameters, Match match)
{
var oldValue = match.Groups[1].Value;
string newValue;
var found = parameters.TryGetValue(oldValue, out newValue);
if (found)
{
return newValue;
}
var originalValue = match.Groups[0].Value;
return originalValue;
}
I have tested the solution with a 100.000 bytes string, 7 keys and hundreds of replacements. It uses 7 times more memory then the lenght of the string. And it took only 0.002 seconds.
This question already has answers here:
regex to find a string that comes after =
(6 answers)
Closed 9 years ago.
So I asked this question before and said I wanted it in javascript but realized later on that it's unecessary data being sent. So it would be great if anybody could help me solve the same thing in C#
What I need is to get several properties out of a string.
The string will look something like:
str = "car[brand=saab][wheels=4]";
There can be more or fewer properties.
I need everything before the first [] in 1 variable.
Then I need each property and its value in a variable.
Easiest way to understand what I want is probably to check my previous question and the answer that solved it :)
I used the regex(slightly different) in your previous question.
string input = "car[brand=saab][wheels=4]";
string product = "";
Dictionary<string, string> props = new Dictionary<string, string>();
foreach (Match m in Regex.Matches(input, #"^(\w+)|\[(\w+)=(.+?)\]"))
{
if (String.IsNullOrEmpty(product))
product = m.Groups[1].Value;
else
props.Add(m.Groups[2].Value, m.Groups[3].Value);
}
try this regex:
(.+?)(\[.+?\])+
and a sample code:
var inputString = "car[brand=saab][wheels=4]";
var pattern = #"(?<v1>.+?)(?<v2>\[.+?\])+";
var v1 = Regex.Match(inputString, pattern).Groups["v1"].Value;
Dictionary<String, String> list = new Dictionary<String, String>();
foreach (Capture capture in Regex.Match(inputString, pattern).Groups["v2"].Captures)
{
var sp = capture.Value.Split('=');
list.Add(sp[0], sp[1]);
}
explain:
(?<name>subexpression)
Captures the matched subexpression into a named group.
You can do this
var lst=Regex.Matches(input,#"(\w+)((?:\[.*?\])+)")
.Cast<Match>()
.Select(x=>new
{
name=x.Groups[1].Value,
value=Regex.Matches(x.Groups[2].Value,#"(?<=\[).*?(?=\])")
.Cast<Match>()
.Select(x=>new
{
name=x.Groups[0].Value.Split('=')[0],
value=x.Groups[0].Value.Split('=')[1]
})
});
Now you can iterate over lst like this
foreach(var parent in lst)
{
parent.name;//car
foreach(var pairs in parent.value)
{
pairs.name;//brand,wheels
pairs.value;//ferrari,4
}
}
So,for input car[brand=a][wheels=4]cycle[brand=b][wheels=2]
Output would be like
car
brand,a
wheels,4
cycle
brand,b
wheels,2
Without regex:
string input = "car[brand=saab][wheels=4]";
var query = from s in input.Replace("]", "").Split('[')
let vars = s.Split('=')
let name = vars[0]
let value = vars.Length > 1 ? vars[1] : ""
select new {Name = name, Value = value};
string firstVar = query.First().Name;
Dictionary<string, string> otherVars = query
.Skip(1)
.ToDictionary(v => v.Name, v => v.Value);
You can access your variables in the dictionary like this string brand = otherVars["brand"]
Since you already have an answer using regex and your comments state it doesn't have to be with a regex, I'll offer an alternative:
The code is
string str = ("car[brand=saab][wheels=4]");
int i = str.IndexOf("[");
string[] details =str.Substring(i).Replace("]","").Split('[');
string name = str.Substring(0, i);
string brand = details[1].Split('=')[1];
string wheels = details[2].Split('=')[1];
This approach assumes the data is always going to be in the same format though; you may need some validation in there depending on your needs...
This question already has answers here:
Enum ToString with user friendly strings
(25 answers)
Closed 4 years ago.
How can I get a List of an Enum's values?
For example, I have the following:
public enum ContactSubjects
{
[Description("General Question")]
General,
[Description("Availability/Reservation")]
Reservation,
[Description("Other Issue")]
Other
}
What I need to be able to do is pass ContactSubject.General as an argument and it returns the List of the descriptions.
This method needs to work with any Enum, not just ContactSubject (in my example). The signature should be something like GetEnumDescriptions(Enum value).
Something like that may work:
private static IEnumerable<string> GetDescriptions(Type type)
{
var descs = new List<string>();
var names = Enum.GetNames(type);
foreach (var name in names)
{
var field = type.GetField(name);
var fds = field.GetCustomAttributes(typeof(DescriptionAttribute), true);
foreach (DescriptionAttribute fd in fds)
{
descs.Add(fd.Description);
}
}
return descs;
}
however you may review some logic there: such as is it ok to start of names? how are you going to handle multiple Description attributes? What if some of them are missing - do you want a name or just skip it like above? etc.
just reviewed your question. For the VALUE you would have something like that:
private static IEnumerable<string> GetDescriptions(Enum value)
{
var descs = new List<string>();
var type = value.GetType();
var name = Enum.GetName(type, value);
var field = type.GetField(name);
var fds = field.GetCustomAttributes(typeof(DescriptionAttribute), true);
foreach (DescriptionAttribute fd in fds)
{
descs.Add(fd.Description);
}
return descs;
}
however it is not possible to place two Description attributes on single field, so I guess it may return just string.