C# String "pattern" in variable - c#

how do I put string "pattern" to a variable.
To clearify what I want:
string word = "George";
string pattern1 = $"I met person {word}";
string pattern2 = $"I love {word}";
Console.WriteLine(pattern1);
Console.WriteLine(pattern2);
word = "Jimmy";
Console.WriteLine(pattern1);
Console.WriteLine(pattern2);
If the "pattern" system worked as I want, I would get this output:
I met person George.
I love George.
I met person Jimmy.
I love Jimmy.
You get what I want I don't want to execute the $"..." string I want to save it as "pattern" (I didn't find better word for it) and then execute it when I want (etc with changed variables).

Use the overload of Console.WriteLine that takes a composite formatting string and arguments for the string. (Note the lack of $ in front of the pattern strings - we are not performing the interpolation there, but deferring it to be done as part of the Console.WriteLine call.)
string word = "George";
string pattern1 = "I met person {0}";
string pattern2 = "I love {0}";
Console.WriteLine(pattern1, word);
Console.WriteLine(pattern2, word);
word = "Jimmy";
Console.WriteLine(pattern1, word);
Console.WriteLine(pattern2, word);
If you want to store the string after the substitution instead of writing directly to the console, use string.Format.

Just make it into a method:
private static string pattern1(string word) => $"I met person {word}";
Inside your original method, call the new method like this:
Console.WriteLine(pattern1(word));

Related

C# How to treat a string variable as interpolated string?

the interpolated string is easy, just a string lead with $ sign. But what if the string template is coming from outside of your code. For example assume you have a XML file containing following line:
<filePath from="C:\data\settle{date}.csv" to="D:\data\settle{date}.csv"/>
Then you can use LINQ to XML read the content of the attributes in.
//assume the ele is the node <filePath></filePath>
string pathFrom = ele.Attribute("from").value;
string pathTo = ele.Attibute("to").value;
string date = DateTime.Today.ToString("MMddyyyy");
Now how can I inject the date into the pathFrom variable and pathTo variable?
If I have the control of the string itself, things are easy. I can just do var xxx=$"C:\data\settle{date}.csv";But now, what I have is only the variable that I know contains the placeholder date
String interpolation is a compiler feature, so it cannot be used at runtime. This should be clear from the fact that the names of the variables in the scope will in general not be availabe at runtime.
So you will have to roll your own replacement mechanism. It depends on your exact requirements what is best here.
If you only have one (or very few replacements), just do
output = input.Replace("{date}", date);
If the possible replacements are a long list, it might be better to use
output = Regex.Replace(input, #"\{\w+?\}",
match => GetValue(match.Value));
with
string GetValue(string variable)
{
switch (variable)
{
case "{date}":
return DateTime.Today.ToString("MMddyyyy");
default:
return "";
}
}
If you can get an IDictionary<string, string> mapping variable names to values you may simplify this to
output = Regex.Replace(input, #"\{\w+?\}",
match => replacements[match.Value.Substring(1, match.Value.Length-2)]);
You can't directly; the compiler turns your:
string world = "world";
var hw = $"Hello {world}"
Into something like:
string world = "world";
var hw = string.Format("Hello {0}", world);
(It chooses concat, format or formattablestring depending on the situation)
You could engage in a similar process yourself, by replacing "{date" with "{0" and putting the date as the second argument to a string format, etc.
SOLUTION 1:
If you have the ability to change something on xml template change {date} to {0}.
<filePath from="C:\data\settle{0}.csv" to="D:\data\settle{0}.csv" />
Then you can set the value of that like this.
var elementString = string.Format(element.ToString(), DateTime.Now.ToString("MMddyyyy"));
Output: <filePath from="C:\data\settle08092020.csv" to="D:\data\settle08092020.csv" />
SOLUTION 2:
If you can't change the xml template, then this might be my personal course to go.
<filePath from="C:\data\settle{date}.csv" to="D:\data\settle{date}.csv" />
Set the placeholder like this.
element.Attribute("to").Value = element.Attribute("to").Value.Replace("{date}", DateTime.Now.ToString("MMddyyyy"));
element.Attribute("from").Value = element.Attribute("from").Value.Replace("{date}", DateTime.Now.ToString("MMddyyyy"));
Output: <filePath from="C:\data\settle08092020.csv" to="D:\data\settle08092020.csv" />
I hope it helps. Kind regards.
If you treat your original string as a user-input string (or anything that is not processed by the compiler to replace the placeholder, then the question is simple - just use String.Replace() to replace the placehoder {date}, with the value of the date as you wish. Now the followup question is: are you sure that the compiler is not substituting it during compile time, and leaving it untouched for handling at the runtime?
String interpolation allows the developer to combine variables and text to form a string.
Example
Two int variables are created: foo and bar.
int foo = 34;
int bar = 42;
string resultString = $"The foo is {foo}, and the bar is {bar}.";
Console.WriteLine(resultString);
Output:
The foo is 34, and the bar is 42.

Is it possible to store a regex match and use part of it as a list enumerator?

I have created a MadLibs style game where the user enters responses to prompts which in turn replace blanks, represented by %s0, %s1 etc., in a story. I have this working using a for loop but someone else suggested I could do it using regex. What I have so far is below, which replaces all instances of %s+number with "wibble". What I was wondering is if it is possible to store the number found by the regex in a temporary variable and in turn use that to return a value from the list Words? E.g. return Regex.Replace(story, pattern, Global.Words[x]); where x is the number returned by the regex pattern as it goes over the string.
static void Main(string[] args)
{
Globals.Words = new List<string>();
Globals.Words.Add("nathan");
Globals.Words.Add("bob");
var text = "Once upon a time there was a %s0 and it was %s1";
Console.WriteLine(FindEscapeCharacters(text));
}
public static string FindEscapeCharacters(string story)
{
var pattern = #"%s([0-9]+)";
return Regex.Replace(story, "%s([0-9]+)", "wibble");
}
Thanks in advance, Nathan.
Not a direct answer to your question about regexes, but if I understand you correctly, there is an easier way to do this:
string baseString = "I have a {0} {1} in my {0} {2}.";
List<string> words = new List<string>() { "red", "cat", "hat" };
string outputString = String.Format(baseString, words.ToArray());
outputString will be I have a red cat in my red hat..
Is that not what you want, or is there more to your question that I'm missing?
Minor elaboration
String.Format uses the following signature:
string Format(string format, params object[] values)
The neat thing about params is that you can either list values separately:
var a = String.Format("...", valueA, valueB, valueC);
but you can also pass in an array directly:
var a = String.Format("...", valueArray);
Note that you can't mix and match the two approaches.
Yes, you are very close in your attempt with Regex.Replace; the last step is to change constant "wibble" into lambda match => how_to_replace_the_match:
var text = "Once upon a time there was a %s0 and it was %s1";
// Once upon a time there was a nathan and it was bob
var result = Regex.Replace(
text,
"%s([0-9]+)",
match => Globals.Words[int.Parse(match.Groups[1].Value)]);
Edit: In case you don't want working with capturing groups by their numbers, you can name them explicitly:
// Once upon a time there was a nathan and it was bob
var result = Regex.Replace(
text,
"%s(?<number>[0-9]+)",
match => Globals.Words[int.Parse(match.Groups["number"].Value)]);
There is an overload of Regex.Replace that, rather than taking a string for the last argument, takes a MatchEvaluator delegate - a function that takes a Match object and returns a string.
You could make that function parse the integer from the Match's Groups[1].Value property and then use that to index into your list, returning the string you find.

Split string with plus sign as a delimiter

I have an issue with a string containing the plus sign (+).
I want to split that string (or if there is some other way to solve my problem)
string ColumnPlusLevel = "+-J10+-J10+-J10+-J10+-J10";
string strpluslevel = "";
strpluslevel = ColumnPlusLevel;
string[] strpluslevel_lines = Regex.Split(strpluslevel, "+");
foreach (string line in strpluslevel_lines)
{
MessageBox.Show(line);
strpluslevel_summa = strpluslevel_summa + line;
}
MessageBox.Show(strpluslevel_summa, "summa sumarum");
The MessageBox is for my testing purpose.
Now... The ColumnPlusLevel string can have very varied entry but it is always a repeated pattern starting with the plus sign.
i.e. "+MJ+MJ+MJ" or "+PPL14.1+PPL14.1+PPL14.1" as examples.
(It comes form Another software and I cant edit the output from that software)
How can I find out what that pattern is that is being repeated?
That in this exampels is the +-J10 or +MJ or +PPL14.1
In my case above I have tested it by using only a MessageBox to show the result but I want the repeated pattering stored in a string later on.
Maybe im doing it wrong by using Split, maybe there is another solution.
Maybe I use Split in the wrong way.
Hope you understand my problem and the result I want.
Thanks for any advice.
/Tomas
How can I find out what that pattern is that is being repeated?
Maybe i didn't understand the requirement fully, but isn't it easy as:
string[] tokens = ColumnPlusLevel.Split(new[]{'+'}, StringSplitOptions.RemoveEmptyEntries);
string first = tokens[0];
bool repeatingPattern = tokens.Skip(1).All(s => s == first);
If repeatingPattern is true you know that the pattern itself is first.
Can you maybe explain how the logic works
The line which contains tokens.Skip(1) is a LINQ query, so you need to add using System.Linq at the top of your code file. Since tokens is a string[] which implements IEnumerable<string> you can use any LINQ (extension-)method. Enumerable.Skip(1) will skip the first because i have already stored that in a variable and i want to know if all others are same. Therefore i use All which returns false as soon as one item doesn't match the condition(so one string is different to the first). If all are same you know that there is a repeating pattern which is already stored in the variable first.
You should use String.Split function :
string pattern = ColumnPlusLevel.Split("+")[0];
...but it is always a repeated pattern starting with the plus sign.
Why do you even need String.Split() here if the pattern always only repeats itself?
string input = #"+MJ+MJ+MJ";
int indexOfSecondPlus = input.IndexOf('+', 1);
string pattern = input.Remove(indexOfSecondPlus, input.Length - indexOfSecondPlus);
//pattern is now "+MJ"
No need of string split, no need to use LinQ
String has a method called Split which let's you split/divide the string based on a given character/character-set:
string givenString = "+-J10+-J10+-J10+-J10+-J10"'
string SplittedString = givenString.Split("+")[0] ///Here + is the character based on which the string would be splitted and 0 is the index number
string result = SplittedString.Replace("-","") //The mothod REPLACE replaces the given string with a targeted string,i added this so that you can get the numbers only from the string

Interpolated string in database

Following interpolated string formation works well:
string BG="7263-2323";
string PG="2983-2323";
string interpolatedString = $"{BG};{PG}";
Console.WriteLine(interpolatedString);
Result in variable interpolatedString:
7263-2323;2983-2323
But, the problem is that I store interpolatedString in database, then it does not display values for BG and PG... Instead it displays string as it is:
$\"{BG};{PG}\"
How can I solve this issue? Any idea?
You can't do that. Interpolated strings are effectively just syntactic sugar for using string.Format. Instead you would need to store your strings like this:
Hello {0}, welcome to my app
And then use string.Format:
var format = "Hello {0}, welcome to my app";
var output = string.format(format, "Bob");
Alternatively you could roll your own, for example:
var format = "Hello {name}, welcome to my app";
var output = format.Replace("{name}", "Bob");
Note that my example here isn't particularly efficient so you may want to use something like StringBuilder if you're doing a lot of this.

How to get the string data which is outside of parenthesis in C#

I need to get the data which is outside of parenthesis
string data = "English(Language)";
string result= "English";
The result should display the text "English".
I tried with Regex but not able to get the desired result.
Easiest solution that I can think of:
string data = "English(Language)";
string result = data.Substring(0, data.IndexOf('('));
That is of course, if you never need the data within the parenthesis.
Another way to do it is by using String.Split:
string data = "English(Language)";
string result = data.Split('(')[0];
This is marginally slower than the first example since it needs to allocate memory for an array.
The third way to do it is via regular-expressions:
string data = "English(Language)";
var pattern = new Regex("(\\w+\\s?)\\((\\w+)\\)", RegexOptions.Compiled);
string result = pattern.Match(data).Groups[1].Value;
This is the slowest of all the examples, but captures both "English" and "Language". It also allows for whitespace \s? between English and (Language).
A great tool for testing regular expressions is RegexPal, just remember to escape everything when you move it over to C#.
Here is a fiddle, testing the performance of all options.
Try:
string input = "English(Language)";
string regex = "(\\(.*\\))";
string output = Regex.Replace(input, regex, "");
You will need that:
using System.Text.RegularExpressions;
If you dont bother to use Regex, the below solution works fine.
string data = "English(Language)";
string result = Regex.Match(data, #"(.*)\(.*\)").Groups[1].Value;
Console.WriteLine(result); // English
Hi take a look at the Split methods:
string data = "English(Language)";
string result= "English";
var value = data.Split('(').First();
Console.WriteLine (value);
Result :
English
xd or just:
string data = "English(Language)";
string result = data.Replace("(Language)", "");

Categories