C# Replacing String in Foreach loop - c#

I'm trying to replace text. I'm using a dictionary for the task.
public static string cleanString(this String str) {
Dictionary<string, string> dict = new Dictionary<string,string>();
dict.Add("JR", "Junior");
dict.Add("SR", "Senior");
foreach (KeyValuePair<string,string> d in dict) {
if (str.BlindContains(p.Key)) {
str = str.BlindReplace(str, p.Value);
}
}
return str;
}
BlindContains and BlindReplace just ignore the case of the replacement (and BC ensures the string is not part of another word):
public static bool BlindContains(this String str, string toCheck)
{
if (Regex.IsMatch(str, #"\b" + toCheck + #"\b", RegexOptions.IgnoreCase))
return str.IndexOf(toCheck, StringComparison.OrdinalIgnoreCase) >= 0;
return false;
}
public static string BlindReplace(this String str, string oldStr, string newStr)
{
return Regex.Replace(str, oldStr, newStr, RegexOptions.IgnoreCase);
}
The problem
If I call my method on a a string, the following occurs:
string mystring = "The jr. is less than the sr."
mystring.cleanString()
returns "Junior"
However, when I print
Console.WriteLine(Regex.Replace(mystring, "jr.", "junior", Regex.IgnoreCase));
I get the output: "The junior is less than the sr."
Why does the loop compromise the task?

You should be passing the key in your dictionary (Which contains the text to search for), rather than the actual string you are searching in.
It should be:
str = str.BlindReplace(p.Key, p.Value);
As opposed to:
str = str.BlindReplace(str, p.Value);
You are currently replacing your string with the value "Junior" because you specified your string as the text to search for. (Which will make it replace the entire string instead of just the keyword)

In cleanString implementation, I think you made an error in your call to BlindReplace. Instead of:
str = str.BlindReplace(str, p.Value);
I believe you should have called:
str = str.BlindReplace(d.Key, d.Value);

Related

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();
}

C# remove empty url parameters regex

I am trying to remove empty url type parameters from a string using C#. My code sample is here.
public static string test ()
{
string parameters = "one=aa&two=&three=aaa&four=";
string pattern = "&[a-zA-Z][a-zA-Z]*=&";
string replacement = "";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(parameters, replacement);
return parameters;
}
public static void Main(string[] args)
{
Console.WriteLine(test());
}
I tried the code in rextester
output: one=aa&two=&three=aaa&four=
expected output: one=aa&three=aaa
You absolutely do not need to roll your own Regex for this, try using HttpUtility.ParseQueryString():
public static string RemoveEmptyUrlParameters(string input)
{
var results = HttpUtility.ParseQueryString(input);
Dictionary<string, string> nonEmpty = new Dictionary<string, string>();
foreach(var k in results.AllKeys)
{
if(!string.IsNullOrWhiteSpace(results[k]))
{
nonEmpty.Add(k, results[k]);
}
}
return string.Join("&", nonEmpty.Select(kvp => $"{kvp.Key}={kvp.Value}"));
}
Fiddle here
Regex:
(?:^|&)[a-zA-Z]+=(?=&|$)
This matches start of string or an ampersand ((?:^|&)) followed by at least one (english) letter ([a-zA-Z]+), an equal sign (=) and then nothing, made sure by the positive look-ahead ((?=&|$)) which matches end of string or a new parameter (started by &).
Code:
public static string test ()
{
string parameters = "one=aa&two=&three=aaa&four=";
string pattern = "(?:^|&)[a-zA-Z]+=(?=&|$)";
string replacement = "";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(parameters, replacement);
return result;
}
public static void Main(string[] args)
{
Console.WriteLine(test());
}
Note that this also returns the correct variable (as pointed out by Joel Anderson)
See it live here at ideone.
The results of the Regex replace is not returned by the function. The function returns the variable "parameters", which is never updated or changed.
string parameters = "one=aa&two=&three=aaa&four=";
...
string result = rgx.Replace(parameters, replacement);
return parameters;
....
Perhaps you meant
return results;

Regex to find a string between two special known characters

I'm trying to parse messages transmited over TCP for my own network protocol using regex without success.
My commands start with ! followed by COMMAND_NAME and a list of arguments in the format or ARGUMENT_NAME=ARGUMENT_VALUE enclosed in <>
for example:
!LOGIN?<USERNAME='user'><PASSWORD='password'>;
my code :
public class CommandParser
{
private Dictionary<string, string> arguments = new Dictionary<string, string>();
public CommandParser(string input)
{
Match commandMatch = Regex.Match(input, #"\!([^)]*)\&");
if (commandMatch.Success)
{
CommandName = commandMatch.Groups[1].Value;
}
// Here we call Regex.Match.
MatchCollection matches = Regex.Matches(input,"(?<!\\S)<([a-z0-9]+)=(\'[a-z0-9]+\')>(?!\\S)",
RegexOptions.IgnoreCase);
//
foreach (Match argumentMatch in matches)
{
arguments.Add(
argumentMatch.Groups[1].Value,
argumentMatch.Groups[2].Value);
}
}
public string CommandName { get; set; }
public Dictionary<string, string> Arguments
{
get { return arguments; }
}
/// <summary>
///
/// </summary>
public int ArgumentCount
{
get { return arguments.Count; }
}
}
To find the command name, finding the first word after the "!" should be enough:
/\!\w*/g
To match the key/value pairs in groups, you could try something like:
(\w+)='([a-zA-Z_]*)'
An example of the above regex can be found here.
You do not need regex here and avoid them unless that's a last option left. You could do this with simple C# logic.
string input = "!LOGIN?<USERNAME='user'><PASSWORD='password'>";
string command = input.Substring(1, input.IndexOf('?') - 1);
Console.WriteLine($"command: {command}");
var parameters = input
.Replace($"!{command}?", string.Empty)
.Replace("<", "")
.Split(">".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
string[] kvpair;
foreach(var kv in parameters) {
kvpair = kv.Split('=');
Console.WriteLine($"pname: {kvpair[0]}, pvalue: {kvpair[1]}");
}
Output:
command: LOGIN
pname: USERNAME, pvalue: 'user'
pname: PASSWORD, pvalue: 'password'

Parse String with Regex 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 ;)

How to refactor these functions which have one line difference

I have 3 functions where the only difference in is the values I point out with comment
//-- point of difference
The majority of the function is the same across all three. The "DRY" factor is haunting my sleep :). I was wondering; can these could be merged easily and readably?
I have had situations like this before and I am hoping to learn something here.
private string RenderRequestType(string render, NameValueCollection nvp, string prefix, string regexWild, string suffix)
{
string regex = prefix + regexWild + suffix;
MatchCollection matches = Regex.Matches(render, regex);
foreach (Match match in matches)
{
foreach (Capture capture in match.Captures)
{
string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);
//-- point of difference
string value = nvp[name];
render = render.Replace(capture.Value, value);
}
}
return render;
}
private string RenderSessionType(string render, HttpContext httpContext, string prefix, string regexWild, string suffix)
{
string regex = prefix + regexWild + suffix;
MatchCollection matches = Regex.Matches(render, regex);
foreach (Match match in matches)
{
foreach (Capture capture in match.Captures)
{
string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);
//-- point of difference
object session = httpContext.Session[name];
string value = (session != null ? session.ToString() : "");
render = render.Replace(capture.Value, value);
}
}
return render;
}
private string RenderCookieType(string render, HttpContext httpContext, string prefix, string regexWild, string suffix)
{
string regex = prefix + regexWild + suffix;
MatchCollection matches = Regex.Matches(render, regex);
foreach (Match match in matches)
{
foreach (Capture capture in match.Captures)
{
string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);
//-- point of difference
HttpCookie cookie = httpContext.Request.Cookies[name];
string value = (cookie != null ? cookie.Value : "");
render = render.Replace(capture.Value, value);
}
}
return render;
}
You could modify the function to take a Func<string, string> to do the lookup:
private string RenderType(string render, Func<string, string> lookupFunc, string prefix, string regexWild, string suffix)
{
string regex = prefix + regexWild + suffix;
MatchCollection matches = Regex.Matches(render, regex);
foreach (Match match in matches)
{
foreach (Capture capture in match.Captures)
{
string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);
//-- point of difference
string value = lookupFunc(name);
render = render.Replace(capture.Value, value);
}
}
return render;
}
Then write your functions in terms of this one, e.g.:
private string RenderRequestType(string render, NameValueCollection nvp, string prefix, string regexWild, string suffix)
{
return RenderType(render, name => nvp[name], prefix, regexWild, suffix);
}
Pass in a Func<string, string> to get the value associated with a given name. In the first case that would just use nvp's indexer; in the second it would use the session. You could either use separate methods to create the delegates, or lambda expressions. (I'd definitely use a lambda expression for the first one; I might use a separate method for the second.)
In my opinion the best solution is to use lambda expressions.
Instead of second argument to your functions, put there lambda which will transform string name to string value.

Categories