I could use a little help with proper regular expressions to parse the following string into 3 variables. The part with comments saying // TODO: is where I need help with the regular expressions. For now I have just assigned a static value, but need to replace that with real regular expressions that parse the sample text. Thanks!
// This is what a sample text will look like.
var text = "Cashpay #username 55 This is a sample message";
// We need to parse the text into 3 variables.
// 1) username - the user the payment will go to.
// 2) amount - the amount the payment is for.
// 3) message - an optional message for the payment.
var username = "username"; // TODO: Get the username value from the text.
var amount = 55.00; // TODO: Get the amount from the text.
var message = "This is a sample message"; // TODO: Get the message from the text.
// now write out the variables
Console.WriteLine("username: " + username);
Console.WriteLine("amount: " + amount);
Console.WriteLine("message: " + message);
You can use capturing groups:
var regex = new Regex(#"^Cashpay\s+#([A-Za-z0-9_-]+)\s+(\d+)\s+(.+)$");
var text = "Cashpay #username 55 This is a sample message";
var match = regex.Match(text);
if (!match.Success)
//Bad string! Waaaah!
string username = match.Groups[1].Value;
int amount = int.Parse(match.Groups[2].Value);
string message = match.Groups[3].Value;
This method does not do input validation; in some cases this might be ok (e.g. the input is coming from a source which has already been validated). If you are getting this from user input you should probably use a method that is more robust. If it is coming from a trusted source but has multiple formats (e.g. "Cashpay" is one of many choices) you could use a switch or if statement for flow control after the split:
// make sure you validate input (coming from trusted source?)
// before you parse like this.
string list[] = text.Split(new char [] {' '});
if (list[0] == "Cashpay")
{
var username = list[1].SubString(1);
var amount = list[2];
var message = string.Join(' ',list.Skip(3));
}
or
// make sure you validate input (coming from trusted source?)
// before you parse like this.
string list[] = text.Split(new char [] {' '},4);
if (list[0] == "Cashpay")
{
var username = list[1].SubString(1);
var amount = list[2];
var message = list[3];
}
Related
a user specifies a file name that can be either in the form "<name>_<fileNum>of<fileNumTotal>" or simply "<name>". I need to somehow extract the "<name>" part from the full file name.
Basically, I am looking for a solution to the method "ExtractName()" in the following example:
string fileName = "example_File"; \\ This var is specified by user
string extractedName = ExtractName(fileName); // Must return "example_File"
fileName = "example_File2_1of5";
extractedName = ExtractName(fileName); // Must return "example_File2"
fileName = "examp_File_3of15";
extractedName = ExtractName(fileName); // Must return "examp_File"
fileName = "example_12of15";
extractedName = ExtractName(fileName); // Must return "example"
Edit: Here's what I've tried so far:
ExtractName(string fullName)
{
return fullName.SubString(0, fullName.LastIndexOf('_'));
}
But this clearly does not work for the case where the full name is just "<name>".
Thanks
This would be easier to parse using Regex, because you don't know how many digits either number will have.
var inputs = new[]
{
"example_File",
"example_File2_1of5",
"examp_File_3of15",
"example_12of15"
};
var pattern = new Regex(#"^(.+)(_\d+of\d+)$");
foreach (var input in inputs)
{
var match = pattern.Match(input);
if (!match.Success)
{
// file doesn't end with "#of#", so use the whole input
Console.WriteLine(input);
}
else
{
// it does end with "#of#", so use the first capture group
Console.WriteLine(match.Groups[1].Value);
}
}
This code returns:
example_File
example_File2
examp_File
example
The Regex pattern has three parts:
^ and $ are anchors to ensure you capture the entire string, not just a subset of characters.
(.+) - match everything, be as greedy as possible.
(_\d+of\d+) - match "_#of#", where "#" can be any number of consecutive digits.
I have an application that loops through a group of documents and if a value is detected, then the user receives a prompt to replace this value. My current code looks like the following;
if (alllines[i].Contains("$"))
{
// prompt
int dollarIndex = alllines[i].IndexOf("%");
string nextTenChars = alllines[i].Substring(dollarIndex + 1, 18);
string PromtText = nextTenChars.Replace("%", "").Replace("/*", "").Replace("*/", "");
string promptValue = CreateInput.ShowDialog(PromtText, fi.FullName);
if (promptValue.Equals(""))
{
}
else
{
alllines[i] = alllines[i].Replace("$", promptValue);
File.WriteAllLines(fi.FullName, alllines.ToArray());
}
}
As you can see the prompt box displays 18 characters after the index which in this case is % however, if there are not 18 characters then the application crashes. What I want to do is use regex but I am unsure of how to apply this in the codes current state.
If I use the below I get the error Cannot convert from int to string any help would be appreciated.
Regex regex = new Regex(#"(\$.{1,10})");
var chars = regex.Matches(dollarIndex);
This should work
Regex regex = new Regex(#"(/*%.{1,50})");
var chars = regex.Match(alllines[i]).ToString();
string promptValue = CreateInput.ShowDialog(PromtText, fi.FullName);
Is there any smart and neat way to I guess escape characters in a string to make it compatible with the specific format the SendKeys uses?
At first I thought this would work:
line = Regex.Replace(line, #"\{{0}", "{{}");
line = Regex.Replace(line, #"\}{0}", "{}}");
But this won't work work because it's doing two checks and messes up the syntax entirely.
How can I handle this?
You can use some place holder instead of { and } and create the formatted result using those place holders. Then at last replace those place holders by { and }. For example:
string PrepareForSendKeys(string input)
{
var specialChars = "+^%~(){}";
var c1 = "[BRACEOPEN]";
var c2 = "[BRACECLOSE]";
specialChars.ToList().ForEach(x =>
{
input = input.Replace(x.ToString(),
string.Format("{0}{1}{2}", c1, x.ToString(), c2));
});
input = input.Replace(c1, "{");
input = input.Replace(c2, "}");
return input;
}
And you can use it this way:
var input = "some string containing + ^ % ~ ( ) { }";
MessageBox.Show(PrepareForSendKeys(input));
And the result would be:
some string containing {+} {^} {%} {~} {(} {)} {{} {}}
I need to locate a specific part of a string value like the one below, I need to alter the "Meeting ID" to a specific number.
This number comes from a dropdownlist of multiple numbers, so I cant simply use find & replace. As the text could change to one of multiple numbers before the user is happy.
The "0783," part of the string never changes, and "Meeting ID" is always followed by a ",".
So i need to get to "0783, INSERT TEXT ," and then insert the new number on the Index Changed event.
Here is an example :-
Business Invitation, start time, M Problem, 518-06-xxx, 9999 999
0783, Meeting ID, xxx ??
What is the best way of locating this string and replacing the test each time?
I hope this makes sense guys?
Okay, so there are several ways of doing this, however this seems to be a string you have control over so I'm going to say here's what you want to do.
var myString = string.Format("Business Invitation, start time, M Problem, 518-06-xxx, 9999 999 0783, {0}, xxx ??", yourMeetingId);
If you don't have control over it then you're going to have to be a bit more clever:
var startingIndex = myString.IndexOf("0783, ");
var endingIndex = myString.IndexOf(",", startingIndex + 6);
var pattern = myString.Substring(startingIndex + 6, endingIndex - (startingIndex + 6));
myString = myString.Replace(pattern, yourMeetingId);
You should store your "current" Meeting ID in a variable, changing it along with your user's actions, and then use that same global variable whenever you need the string.
This way, you don't have to worry about what's inside the string and don't need to mess with array indexes. You will also be safe from magic numbers / strings, which are bound to blow up in your face at some point in the future.
You can try with Regex.Replace method
string pattern = #"\d{3},";
Regex regex = new Regex(pattern);
var inputStr = "518-06-xxx, 9999 999 0783";
var replace = "..."
var outputStr = regex.Replace(inputStr, replace);
use Regex.Split by token "0783," then in the second string in the array return split by token "," the first element in the string array would be where you would insert new text. Then use string.Join to join the first split with "0783," and the join the second with ",".
string temp = "Business Invitation, start time, M Problem, 518-06-xxx, 9999 999 0783, Meeting ID, xxx ??";
string newID = "1234";
string[] firstSplits = Regex.Split(temp, "0783,");
string[] secondSplits = Regex.Split(firstSplits[1], ",");
secondSplits[0] = newID;
string #join = string.Join(",", secondSplits);
firstSplits[1] = #join;
string newString = string.Join("0783,", firstSplits);
I have multiple words I want to replace with values, whats the best way to do this?
Example:
This is what I have done but it feels and looks so wrong
string s ="Dear <Name>, your booking is confirmed for the <EventDate>";
string s1 = s.Replace("<Name>", client.FullName);
string s2 =s1.Replace("<EventDate>", event.EventDate.ToString());
txtMessage.Text = s2;
There has to be a better way?
thanks
You could use String.Format.
string.Format("Dear {0}, your booking is confirmed for the {1}",
client.FullName, event.EventDate.ToString());
If you're planning on having a dynamic number of replacements, which could change at any time, and you want to make it a bit cleaner, you could always do something like this:
// Define name/value pairs to be replaced.
var replacements = new Dictionary<string,string>();
replacements.Add("<Name>", client.FullName);
replacements.Add("<EventDate>", event.EventDate.ToString());
// Replace
string s = "Dear <Name>, your booking is confirmed for the <EventDate>";
foreach (var replacement in replacements)
{
s = s.Replace(replacement.Key, replacement.Value);
}
To build on George's answer, you could parse the message into tokens then build the message from the tokens.
If the template string was much larger and there are more tokens, this would be a tad more efficient as you are not rebuilding the entire message for each token replacement. Also, the generation of the tokens could be moved out into a Singleton so it is only done once.
// Define name/value pairs to be replaced.
var replacements = new Dictionary<string, string>();
replacements.Add("<Name>", client.FullName);
replacements.Add("<EventDate>", event.EventDate.ToString());
string s = "Dear <Name>, your booking is confirmed for the <EventDate>";
// Parse the message into an array of tokens
Regex regex = new Regex("(<[^>]+>)");
string[] tokens = regex.Split(s);
// Re-build the new message from the tokens
var sb = new StringBuilder();
foreach (string token in tokens)
sb.Append(replacements.ContainsKey(token) ? replacements[token] : token);
s = sb.ToString();
You can chain the Replace operations together:
s = s.Replace(...).Replace(...);
Note that you don't need to create other strings to do this.
Using String.Format is the appropriate way, but only if you can change the original string to suit the brace formatting.
When you do multiple replaces it's much more efficient to use StringBuilder instead of string. Otherwise replace function is making a copy of the string every time you run it, wasting time and memory.
Try this code:
string MyString ="This is the First Post to Stack overflow";
MyString = MyString.Replace("the", "My").Replace("to", "to the");
Result: MyString ="This is My First Post to the Stack overflow";
Use String.Format:
const string message = "Dear {0}, Please call {1} to get your {2} from {3}";
string name = "Bob";
string callName = "Alice";
string thingy = "Book";
string thingyKeeper = "Library";
string customMessage = string.Format(message, name, callName, thingy, thingyKeeper);
Improving on what #Evan said...
string s ="Dear <Name>, your booking is confirmed for the <EventDate>";
string s1 = client.FullName;
string s2 = event.EventDate.ToString();
txtMessage.Text = s.Replace("<Name>", s1).Replace("EventDate", s2);