How to get value in dictionary from 2 different string [duplicate] - c#

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.

Related

Replace few variable names in the string for c# [duplicate]

This question already has answers here:
fastest way to replace string in a template
(9 answers)
Closed 4 months ago.
I have a question, my template content does not have a fixed value, this template content value is random and comes from what the user input and stores in the table, but the variable of the content is set.
For example few template content values (For schedule.TemplateContent) :
1. My name is {name}.
2. My name is {name}. My last name is {lastName}
3. Her name is {name}. She is a {sex}. She like play {activity}
Below is my code, I just only know how to replace 1 word in the template content, not sure how to replace if loop the template content has multiple variables need to replace:
foreach (SAASQueuePatList pat in patList)
{
pat.PatName = "{name}";
pat.PatLastName = "{lastName}";
pat.PatSex= "{sex}";
pat.PatActivity = "{activity}";
string fullContent = schedule.TemplateContent.Replace("{name}", pat.PatName);
}
Hope someone can guide me on how to solve this problem. Thanks.
string fullContent = schedule.TemplateContent
.Replace("{name}", pat.PatName)
.Replace("{lastName}", pat.PatLastName)
.Replace("{sex}", pat.PatSex)
.Replace("{activity}", pat.PatActivity);
You need a map that links a field name to a property.
var map = new Dictionary<string,Func<SAASQueuePat,string>>
{
"name", x => x.PatName,
"sex", x => x.Gender
};
Then you can generate string like this:
foreach (var item in map)
{
template = template.Replace("{" + item.Key + "}", item.Value(pat));
}

convert jsonstring to objects c# [duplicate]

This question already has answers here:
How to Convert JSON object to Custom C# object?
(13 answers)
Closed 5 years ago.
i want to get the data from my returning api jsonstring.
my result string looks like this
[
{"Id":12,"name":"testname","type":"testtype"}
{"Id":12,"name":"testname","type":"testtype"}
{"Id":12,"name":"testname","type":"testtype"}
]
how can i extract this data to c# objects
i can only do it ones
var obj = JObject.Parse(result);
var ID = (int)obj["Id"];
var Name = (String)obj["name"];
var type = (String)obj["type"];
User u = new User(ID,Name,Type);
Your string is not valid JSON, so making it valid JSON is the first step to process it quickly. The easiest thing to do is to make it a JSON array:
string jsonArray = "["
+ string.Join(", ", json.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
+ "]";
From then on it is straightforward (see my related answer: Easiest way to parse JSON response):
var result = JsonConvert.DeserializeObject<User[]>(jsonArray);
Another option is to split the lines yourself, and parse and add the items to a list manually.
Result is an array of JSON.. so loop and parse
list<User> userList = new list<User>();
for(int i=0 ; i <result.length; i++)
{
var obj = JObject.Parse(result[i]);
var ID = (int)obj["Id"];
var Name = (String)obj["name"];
var type = (String)obj["type"];
User u = new User(ID,Name,Type); //create User
userList.add(u); //Add to list
}

How to do a multiple case insensitive replace using a StringBuilder

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.

c# - regex to find a string that comes after = [duplicate]

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...

See if items in a string list contain a certain string

Basically i have a string list as such:
/forum/
/phpld/
/php/
Now i want to check if any of the url:
http://www.url.com/forum/
contains any values from the string list.
In the above case it should match because /forum/ is in the url.
I was thinking something like this:
foreach (string filter in _filterList)
{
if (PAGEURL.Trim().Contains(filter.Trim()))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
break;
}
}
But i cannot get the above to be accurate
How would i do this? :)
Try this:
_filterList.Any(filter => PAGEURL.Trim().Contains(filter.Trim()));
You may do PAGEURL = PAGEURL.Trim() before this expression to not run it each time.
String.Contains() is case-sensitive and culture-insensitive, so if there are any case differences that could be the cause of the 'inaccuracy' that you are experiencing.
If you suspect this may be the problem (or even as a viable alternative) you can try this as the 'if' clause:
if (PAGEURL.Trim().IndexOf(filter.Trim(), StringComparison.OrdinalIgnoreCase) >= 0)
I'm not abundantly clear on what you want to do here, it seems as though if a URL contains any of the filters then you want to add the URL to the list.
List<string> parseResultsFinal = new List<string>();
if (_filterList.Any(x => PAGEURL.Contains(x))
{
parseResultsFinal.Add(PAGEURL);
}
Try to use that.
I would try the following:
var trimmedUrl = PageURL.Replace("http://", "");
var parts = trimmedUrl.Split("/");
var filterList = new List<string> { "forum", "phpld", "php" }
var anyContains = parts.Any(o => filterList.contains(o));
I'd change segments filters to simple words (without slashes, trimmed before adding to filter list):
var _filterList = new List<string>()
{
"forum", "phpld", "php"
};
And used regex to search for segments in url (ignore case, optional slash at the end of url)
bool IsSegmentInUrl(string url, string segment)
{
string pattern = String.Format(".*/{0}(/|$)", segment);
return Regex.IsMatch(url, pattern, RegexOptions.IgnoreCase);
}
Usage:
if (_filterList.Any(filter => IsSegmentInUrl(PAGEURL, filter))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
}
More readable solution - create extensions method
public static bool ContainsSegment(this string url, string segment)
{
string pattern = String.Format("http://.*/{0}(/|$)", segment);
return Regex.IsMatch(url, pattern, RegexOptions.IgnoreCase);
}
Now code looks very self-describing:
if (_filterList.Any(filter => PAGEURL.ContainsSegment(filter))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
}

Categories