C# split string.format string with regex - c#

I want to be able to split a formatting string on the variables' position indicators. It will chop out the curly braces and the position indicating numbers in between them.
So, the string:
string format = "{0} field needs to be set to '{1}' when {2}, Fixit. NOW!";
Should resolve to 3 strings.
" field needs to be set to '"
"' when "
", Fixit. NOW!"
We use string like the above 'format' to build error messages. My goal is to add generic unit tests that can take in the format and verify that an error message was generated that matches the expected format. Since both the error generation code and the unit test reference the same formatting, the unit tests won't need to be updated when minor changes are made to the message.
In the above example, i'll be able to test for the expected results, via a call to a new method called SplitFormatString.
string fieldName = "UserName";
string expectedValue = "Bob";
string condition = "excellence is a must";
string errorMessage = TestFieldValueErrorCase( );
AssertStringContainsAllThese(errorMessage, SplitFormatString(format), fieldName, expectedValue,condition);
With validation
public static void AssertStringContainsAllThese(string msg, string[] formatChunks, params string[] thingsToFind)
{
foreach (var txt in formatChunks.Concat(thingsToFind))
{
Assert.IsTrue(msg.Contains(txt), "Could not find <<" + txt + ">> in msg >>> " + msg);
}
}
I'd rather use regex than an inelegant approach using substrings.

I think you will want Regex.Split
Splits an input string into an array of substrings at the positions defined by a regular expression pattern.
Regex.Split("{0} field needs to be set to '{1}' when {2}, Fixit. NOW!", #"{\d+}");
Should output:
["","field needs to be set to '","' when ",", Fixit. NOW!"]

Related

Splitting up a log file line c#

Log file lines in question:
[2018-10-25 19:40:34] [Output] : (CHAT-Type) User: message
So the date and output can be split by number of characters right?
Then I can parse the date from within the [].
That would leave me with
(CHAT-Type) User: message
Now I want to split this into Chat Type, Username and message.
This is really hurting my head how I would do all this in c#.
Basically I need it to come out like this:
DateTime
ChatType
User
Message
all separate variables
This looks like RegEx kind of a problem :)
Here's a regular expression that matches a single line (with named capture groups)
^\[(?'dateTime'.+)\] \[(?'output'.+)\] : \((?'type'.+)\) (?'user'.+): (?'message'.+)$
Regexr link to try online: https://regexr.com/421p4
Since I used .+ for all areas, there are no character restrictions. It might break (e.g., if there is no space before and after :.) But it can be further improved to be more flexible. If you'd like, I can write one up.
Also, if you're using a method like file.ReadAllText(), you need to use the multiline flag to match all lines. (Regex.Match(input, pattern, RegexOptions.Multiline))
Otherwise (if you're iterating through the lines, for example,) it doesn't matter because there are no \ns in the string.
The C# code
using System.Text.RegularExpressions;
// ...
string pattern = #"^\[(?<dateTime>.+)\] \[(?<output>.+)\] : \((?<type>.+)\) (?<user>.+): (?<message>.+)$";
string message = "[2018-10-25 19:40:34] [Output] : (CHAT-Type) User: message";
var match = Regex.Match(message, pattern);
You can access the matches through the match variable like this:
match.Groups["dateTime"].Value; // "2018-10-25 19:40:34"
match.Groups["user"].Value; // "User"
match.Groups["message"].Value; // "message"
This is how you split all the values:
string inputValue = "(CHAT-Type) User: message";
int braceCloseIndex = inputValue.IndexOf(')');
int colonIndex = inputValue.IndexOf(':');
string chatType = inputValue.Substring(1, braceCloseIndex - 1).Trim();
string userName = inputValue.Substring(braceCloseIndex + 1, colonIndex - braceCloseIndex - 1).Trim();
string message = inputValue.Substring(colonIndex + 1).Trim();
Console.WriteLine($"chatType: {chatType}, userName: {userName}, msg: {message}");

In C#, How to ignore characters in variable while doing string.format

I have a string variable called reason for failure which contains user added text for instance the following:
({0}) on arm ({1}} (82) Kits
Now this variable is part of a method where I am using string.format. I need the string.format to not confuse with {0} {1} in the text of the above variable because I am getting the the exception, Input string was not in correct format
The reason you're getting the exception, The input string is not in the correct format is due to the way you're constructing the string. In your variable you have two closing braces where string.Format expects only one: on arm ({1}}. If you add this variable as a parameter to String.Format as shown in the first example below, it should resolve this issue.
Otherwise, if you are saying that the variable serviceEntry.ReasonForFailure contains the characters {0} and {1}, and that when you place this variable inside a String.Format, those characters are being replaced by the String.Format arguments, then this is by design, at least the way you're constructing your string.
Instead of inserting your variable in the string using the + operator, include it as another parameter to the String.Format call. This way, the {0} in your variable will be preserved.
message.Body = string.Format(
"<html><body>Request is complete<br/>" +
"Service Request initiated by you is Complete<br/>" +
"Please use the following link to access " +
"{0}{1}<br/>" +
"Reason For Failure: {2}<br/></body></html>",
RunLogURL, runLogID, serviceEntry.ReasonForFailure);
Now, if you want to replace the {0} and {1} in serviceEntry.ReasonForFailure with some other values, you can nest a String.Format inside another:
serviceEntry.ReasonForFailure = "10003 Insufficient Liquid Level detected at " +
"pipettor channel ({0}) on arm ({1}) (82)";
var channelId = 87;
var armId = 42;
message.Body = string.Format(
"<html><body>Request is complete<br/>" +
"Service Request initiated by you is Complete<br/>" +
"Please use the following link to access " +
"{0}{1}<br/>" +
"Reason For Failure: {2}<br/></body></html>",
RunLogURL, runLogID,
String.Format(serviceEntry.ReasonForFailure, channelId, armId));
Or you can do it in two operations:
serviceEntry.ReasonForFailure = "10003 Insufficient Liquid Level detected at " +
"pipettor channel ({0}) on arm ({1}) (82)";
var channelId = 87;
var armId = 42;
var reasonForFailure = String.Format(serviceEntry.ReasonForFailure, channelId, armId);
message.Body = string.Format(
"<html><body>Request is complete<br/>" +
"Service Request initiated by you is Complete<br/>" +
"Please use the following link to access " +
"{0}{1}<br/>" +
"Reason For Failure: {2}<br/></body></html>",
RunLogURL, runLogID, reasonForFailure);
The problem is that your variable serviceEntry.ReasonForFailure contains a format item. If don't want them to be treated as format items you'll have to escape them with an extra set of braces. For instance: {0} becomes {{0}} as explained here.
The quick and dirty solution to your problem would be to replace all opening and closing braces by a double brace:
"Reason For Failure:" + serviceEntry.ReasonForFailure.Replace("{","{{").Replace("}","}}") + "<br/>"
A better solution would be to do the replacement using a regular expression:
public string EscapeCurlyBraces(string value)
{
string strRegex = #"(\{\d+\})";
Regex myRegex = new Regex(strRegex, RegexOptions.None);
string strReplace = #"{$1}";
return myRegex.Replace(value, strReplace);
}
And then use it like this:
"Reason For Failure:" + EscapeCurlyBraces(serviceEntry.ReasonForFailure) + "<br/>"
Update
I suggest you ditch the current solution and rewrite it using a StringBuilder:
var emailBody = new StringBuilder();
emailBody.Append("<html><body>RSLMS - Service Request is complete<br/>");
emailBody.Append("Service Request initiated by you is Complete <br/>");
emailBody.AppendFormat("Please use the following link to access Run Log Entry {0}{1}<br/>", RunLogURL, runLogID);
// ommited some lines
emailBody.AppendFormat("Service ID: {0}<br/><br/>", serviceEntry.ID.ToString());
// ommited some lines
emailBody.AppendFormat("Reason For Failure: {0}<br/><br/>", serviceEntry.ReasonForFailure);
emailBody.Append("Thank you <br/> RSLMS Administrator <br/></body></html>");
message.Body = emailBody.ToString();
Since you have two String.Format, you didnt provide parameter for the external , lets say you have x and y for the external Format, this is what you need to do. You need to do double curly braces for those you want to escape from the inner format as in :
var reasonForFailure = "({{0}}) on arm ({{1}}) (82) Kits should still have 50 tests left after run, but it seems like the instrument is not able to pipette anymore from the kits.";
var message = string.Format(string.Format(
"<html><body>Request is complete<br/>" +
"Service Request initiated by you is Complete" + " <br/> " +
"Please use the following link to access {0}{1} <br/>" +
"Reason For Failure: " + reasonForFailure+"<br/>" +
"</body></html>", RunLogURL, runLogID),x,y);

How to split string variable by multiple characters

I need to split string variable by multiple characters, in my case by " ";
Here is my code:
string s_var = "New String variable";
string[] s_mas = s_var.Split(" ");
The Split() method isn't working for me, it says that the argument " " is invalid.
Hoping you guys know how to solve this issue.
You're not specifying the correct arguments.
If you want to split by a string, you need to specify an array.
You also need to specify whether or not to discard empty strings.
Try this:
var s_mas = s_var.Split(new[] { " " }, StringSplitOptions.None);

How can I insert a blank space (" "), when I concatenate a string?

This question is for C Sharp (and Java maybe :).
When I want to display a message to the console, I want to insert after each "+" a blank space. How can I do this, without inserting manually that blank space?
try this
var text = string.Join(" ", new[] {foo, bar, other });
You can't, really - just put it in explicitly:
Console.WriteLine(foo + " " + bar);
or
System.out.println(foo + " " + bar);
I mean you could write a method with a parameter array / varargs parameter, e.g. (C#)
public void WriteToConsole(params object[] values)
{
string separator = "";
foreach (object value in values)
{
Console.Write(separator);
separator = " ";
Console.Write(value);
}
}
... but personally I wouldn't.
if you're looking for a way to tidy your printing routine try String.Format e.g.
Console.WriteLine(String.Format("{0} {1}", string1, string2));
In C#:
string.Join(" ", "Foo", "Bar", "Baz");
In Java:
String.join(" ", "Foo", "Bar", "Baz");
Each of these methods permits a variable number of strings to join, and each has various overloads to pass in collections of strings too.
You can replace "+" with "+ ". Something like this:
new String("Foo+Bar").replace("+", "+ ");
Do you mean a concatenation of strings or just a '+' character? In Java, if there are lot of parameters to show within an output string you can use String.format method like this: String.format("First: %s, second: %s, third: %s etc", param1, param2, param3). In my opinion it's more readable than chained concatenation with '+' operator.
In C# you can use String Interpolation as well using the $ special character, which identifies a string literal as an interpolated string
string text1 = "Hello";
string text2 = "World!";
Console.WriteLine($"{text1}, {text2}");
Output
Hello, World!
From Docs
String interpolation provides a more readable and convenient syntax to create formatted strings than a string composite formatting feature.
// Composite formatting:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");
Both calls produce the same output that is similar to:
Hello, Mark! Today is Wednesday, it's 19:40 now.
Or in Java you can use the printf variant of System.out:
System.out.printf("%s %s", foo, bar);
Remember to put in a "\n" [line feed] at the end, if there are multiple lines to print.

How to insert newline in string literal?

In .NET I can provide both \r or \n string literals, but there is a way to insert
something like "new line" special character like Environment.NewLine static property?
Well, simple options are:
string.Format:
string x = string.Format("first line{0}second line", Environment.NewLine);
String concatenation:
string x = "first line" + Environment.NewLine + "second line";
String interpolation (in C#6 and above):
string x = $"first line{Environment.NewLine}second line";
You could also use \n everywhere, and replace:
string x = "first line\nsecond line\nthird line".Replace("\n",
Environment.NewLine);
Note that you can't make this a string constant, because the value of Environment.NewLine will only be available at execution time.
If you want a const string that contains Environment.NewLine in it you can do something like this:
const string stringWithNewLine =
#"first line
second line
third line";
EDIT
Since this is in a const string it is done in compile time therefore it is the compiler's interpretation of a newline. I can't seem to find a reference explaining this behavior but, I can prove it works as intended. I compiled this code on both Windows and Ubuntu (with Mono) then disassembled and these are the results:
As you can see, in Windows newlines are interpreted as \r\n and on Ubuntu as \n
var sb = new StringBuilder();
sb.Append(first);
sb.AppendLine(); // which is equal to Append(Environment.NewLine);
sb.Append(second);
return sb.ToString();
One more way of convenient placement of Environment.NewLine in format string.
The idea is to create string extension method that formats string as usual but also replaces {nl} in text with Environment.NewLine
Usage
" X={0} {nl} Y={1}{nl} X+Y={2}".FormatIt(1, 2, 1+2);
gives:
X=1
Y=2
X+Y=3
Code
///<summary>
/// Use "string".FormatIt(...) instead of string.Format("string, ...)
/// Use {nl} in text to insert Environment.NewLine
///</summary>
///<exception cref="ArgumentNullException">If format is null</exception>
[StringFormatMethod("format")]
public static string FormatIt(this string format, params object[] args)
{
if (format == null) throw new ArgumentNullException("format");
return string.Format(format.Replace("{nl}", Environment.NewLine), args);
}
Note
If you want ReSharper to highlight your parameters, add attribute to the method above
[StringFormatMethod("format")]
This implementation is obviously less efficient than just String.Format
Maybe one, who interested in this question would be interested in the next question too:
Named string formatting in C#
string myText =
#"<div class=""firstLine""></div>
<div class=""secondLine""></div>
<div class=""thirdLine""></div>";
that's not it:
string myText =
#"<div class=\"firstLine\"></div>
<div class=\"secondLine\"></div>
<div class=\"thirdLine\"></div>";
If you really want the New Line string as a constant, then you can do this:
public readonly string myVar = Environment.NewLine;
The user of the readonly keyword in C# means that this variable can only be assigned to once. You can find the documentation on it here. It allows the declaration of a constant variable whose value isn't known until execution time.
static class MyClass
{
public const string NewLine="\n";
}
string x = "first line" + MyClass.NewLine + "second line"
newer .net versions allow you to use $ in front of the literal which allows you to use variables inside like follows:
var x = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3";
If you are working with Web application you can try this.
StringBuilder sb = new StringBuilder();
sb.AppendLine("Some text with line one");
sb.AppendLine("Some mpre text with line two");
MyLabel.Text = sb.ToString().Replace(Environment.NewLine, "<br />")
If I understand the question: Couple "\r\n" to get that new line below in a textbox. My example worked -
string s1 = comboBox1.Text; // s1 is the variable assigned to box 1, etc.
string s2 = comboBox2.Text;
string both = s1 + "\r\n" + s2;
textBox1.Text = both;
A typical answer could be s1
s2 in the text box using defined type style.
I like more the "pythonic way"
List<string> lines = new List<string> {
"line1",
"line2",
String.Format("{0} - {1} | {2}",
someVar,
othervar,
thirdVar
)
};
if(foo)
lines.Add("line3");
return String.Join(Environment.NewLine, lines);
Here, Environment.NewLine doesn't worked.
I put a "<br/>" in a string and worked.
Ex:
ltrYourLiteral.Text = "First line.<br/>Second Line.";

Categories