How do I make regex properly validate the information? - c#

I've been given the task to make a textbox where you enter your personal code (something we in Latvia use). I need it to be validated before saving the information. For validation I've been using Regex but so far got no result.
Our personal code is like this : XXYYZZ-ABCDE, where
XXYYZZ is date format as in DAYMONTHYEAR and ABCDE are random numbers.
if (per_kods.Text.Trim() != string.Empty)
{
mRegxExpression = new Regex("${day}-${month}-${year}-#####$");
if (!mRegxExpression.IsMatch(per_kods.Text.Trim()))
{
label7.Text = "";
}
else
{
label7.ForeColor = Color.Red;
label7.Text = "Personas kods ievadīts nepareizi!";
pareizi = false;
}
}
this currently is my code. It basically enables a label above the textbox pointing out that the information entered is wrong. If the information is right, the label continues to be disabled. But right now the new Regex part is a problem. I know it might seem totally wrong, but I've just started learning Regex and don't know what's wrong and what's right.

If you don't care about date validation (so for example 31st of February will be accepted, you can do
new Regex(#"^(0[1-9]|[1-2]\d|3[0-1])(0[1-9]|1[0-2])(\d{2})-(\d{5})$");
If you want to understand what this string means, take a look at the MSDN reference.
Now for date validation, so filtering out dates like 310298 that don't exist, I'd recommend you do it manually afterwards - regex is not the best tool for such logic-validation.
EDIT:
You can accomplish that using DateTime.TryParse.
DateTime resultDateTime;
var isValid = DateTime.TryParse(string.Format("{0}-{1}-{2}", 2010, 2, 31), out resultDateTime);
// isValid is false, because 31st of February 2010 does not exist.
var isValid = DateTime.TryParse(string.Format("{0}-{1}-{2}", 2010, 2, 27), out resultDateTime);
// isValid is true, and resultDateTime has been set to 27-2-2010.
Note that DateTime.TryParse is culture sensitive. Depending on the target culture you might need to change the input string. See MSDN reference for TryParse.
EDIT2:
So to connect this with your existing code:
mRegxExpression = new Regex(#"^(0[1-9]|[1-2]\d|3[0-1])(0[1-9]|1[0-2])(\d{2})-(\d{5})$");
var match = mRegxExpression.Match(per_kods.Text.Trim()));
if(!Validate(match))
{
// Handle invalid.
}
else
{
// Handle valid.
}
Where Validate would be:
private static bool Validate(Match match)
{
if(!match.Success)
{
return false;
}
var day = match.Groups[1].ToString();
var month = match.Groups[2].ToString();
var year = match.Groups[3].ToString();
return DateTime.TryParse($"{day}-{month}-{year}", out _);
}
Because our regex begins with ^ and ends with $, there will be always at most one match. The Success property tells us whether there was any match at all, and later the Groups property gives us the capture groups. Groups[0] will be the entire matched string, and then every next one will be the substring that matches one of the parentheses enclosed groups from regex - so the first one is (0[1-9]|[1-2]\d|3[0-1]) which represents days, the second will be months, and so on. Then we just check if the date is valid (again, culture sensitive!). Also, we can neatly use the C#7 discard syntax (_) for the out parameter, as we don't need it.

You can get help from the code below to check validation.
public bool CheckValidation(string input)
{
input = input.Trim();
if (input == string.Empty) return false;
var mRegxExpression = new Regex("^([0-2][0-9]|(3)[0-1])(((0)[0-9])|((1)[0-2]))\\d{2}(\\-)\\d{5}$");
return mRegxExpression.IsMatch(input);
}

Related

C# strip out not needed data using REGEX or something different

So i'm trying to strip data from a string because I have in WPF a "preset" input which looks like __,___, now a user must input something like 30,589, but when a user just gives in 5 or 50, it needs to strip the rest (keeping the ,) to propperly make a float of the input value. The code that I have right now looks like this;
if (inp_km.Text == "__,___")
{
team_results.results[inp_tour_part.SelectedIndex].km =
float.Parse("00,000",
NumberStyles.AllowDecimalPoint,
CultureInfo.GetCultureInfo("nl-NL")); // Give the new value
}
else
{
team_results.results[inp_tour_part.SelectedIndex].km =
float.Parse(inp_km.Text,
NumberStyles.AllowDecimalPoint,
CultureInfo.GetCultureInfo("nl-NL")); // Give the new value
}
But this code just check wether the input is left blank or not... Could someone help me out?
Edit
So I've included a screen, this is the input lay-out a user gets;
Os you can see, the inputs are 'pre-filled', the content of such an input is a "string", so, let's say, I type into the first input just 5;
Then the value (retreived in C# by input_name.Text) is 5_:__, but that's a "wrong" value and you can't fill in such things, how could I check if there still is a : or _ in the input.
Also, the bottom input is the same, but then it needs to be filled in completely.
So you want to check either the input is in one of the two forms: 12,345 or 12:34.
This can be done using Regex very easily.
static void Main(string[] args)
{
var inputComma = "12,345";
var inputColon = "98:76";
Regex regexComma = new Regex(#"^\d{2},\d{3}$");
Regex regexColon = new Regex(#"^\d{2}:\d{2}$");
var matchComma = regexComma.Match(inputComma);
if (matchComma.Success)
{
Console.WriteLine(inputComma);
}
Console.WriteLine();
var matchColon = regexColon.Match(inputColon);
if (matchColon.Success)
{
Console.WriteLine(inputColon);
}
Console.ReadLine();
}
NOTE:
You haven't quite clarified the valid formats for your input. The above will evaluate to true strictly for 12,345 format if commas are present (i.e., two digits followed by a comma followed by three digits), and for colon, only numbers of the format 12:34 (two digits before and after the colon) only.
You might want to modify your Regex based on your exact criteria.

check for valid string format

i am trying to make a validaing system where it checks a string is in the correct format.
the required format can only contain numbers and dashes - and be ordered like so ***-**-*****-**-* 3-2-5-2-1.
For example, 978-14-08855-65-2
can i use Regex like i have for a email checking system by change the format key #"^([\w]+)#([\w])\.([\w]+)$"
the email checking code is
public static bool ValidEmail(string email, out string error)
{
error = "";
string regexEmailCOM = #"^([\w]+)#([\w])\.([\w]+)$"; // allows for .com emails
string regexEmailCoUK = #"^([\w]+)#([\w])\.([\w]+)\.([\w]+)$"; // this allows fo .co.uk emails
var validEmail = new Regex(email);
return validEmail.IsMatch(regexEmailCOM) || validEmail.IsMatch(regexEmailCoUK) && error == "") // if the new instance matches with the string, and there is no error
}
Regex is indeed a good fit for this situation.
One possible expression would be:
^\d{3}-\d\d-\d{5}-\d\d-\d$
This matches exactly 5 groups of only digits (\d) separated by -. Use curly brackets to set a fixed number of repeats.

C# validate input syntax and replace values

I am trying to make a function that validates an input string format and then replaces some values. The string should contain data in the following format:
string data = "'({today} - ({date1} + {date2}))', 'user', 'info'";
I want to make sure that the string is typed in the above format format(validate it), and if it is to replace the values of today, date1 and date2 with some values.
I am thinking of something like that, but I don't know if that is the best way:
if (data.Contains("{today}") && data.Contains("{date1}") && data.Contains("{date2}"))
{ }
Anybody can suggest something?
Here is what you asked, if I understood your comment correctly.
string data = "'({today} - ({date1} + {date2}))', 'user', 'info'"; // your string
string pattern = #"\{.*?\}"; // pattern that will match everything in format {anything}
Regex regEx = new Regex(pattern); //create regex using pattern
MatchCollection matches; // create collection of matches
matches = regEx.Matches(data); // get all matches from your string using regex
for (int i = 0; i < matches.Count; i++) // use this cycle to check if it s what you need
{
Console.WriteLine("{0}", matches[i].Value);
}
To validate your string, what you have suggested is fine. You could make it easier by checking for the negative:
if(!myString.Contains("{today}")
// handle error
if(!myString.Contains("{date1}")
// handle error
In order to replace the values, you can use String.Replace(...).
var myReplacedValue = myString.Replace("{today}", valueToRepalceWith);

How to make DateTime.TryParse() fail if no year is specified?

Consider the following code to parse a date. (Note that I'm in the EN-gb locale):
const DateTimeStyles DATE_TIME_STYLES = DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces;
DateTime dt;
// Current culture for this example is "EN-gb".
if (DateTime.TryParse("31/12", CultureInfo.CurrentUICulture, DATE_TIME_STYLES, out dt))
Console.WriteLine("Parsed correctly"); // Do not want!
else
Console.WriteLine("Did not parse correctly.");
I'm deliberately omitting the year. However, TryParse() will parse this without any errors, and will substitute the current year.
I'd like to be able to force the user to enter ALL the components of the date (using their local format), so I'd like the above parsing to fail - or to be able to detect that the user didn't enter a year.
I don't really want to use DateTime.TryParseExact() because then I would have to add code to specify all the different valid formats for all the different supported locales, which is non-trivial and likely error-prone. I suspect this may well be my only sane option, though.
Anyone got any ideas? (Someone here at work has already implemented a "solution" which involves not allowing the current year, which is clearly not a good solution...)
You could query for the culture's patterns, filter out those without a year and then use TryParseExact on the remaining patterns.
var allPatterns = culture.DateTimeFormat.GetAllDateTimePatterns();
var patternsWithYear = allPatterns.Where(s => s.Contains("y")).ToArray();
bool success = TryParseExact(input, patternsWithYear, culture, styles, out dateTime);
Known bug: This doesn't take escaping into account, you'll need to replace the Contains("y") call with proper parsing to fix this.
Alternatively you could go with just LongDatePattern and ShortDatePattern if you're fine with stricter format constraints.
You can use parse exact like this and catch the exception.
CurrentUICulture.DateTimeFormat.ShortDatePattern will give you the cultures short date pattern.
There is also DateTime.TryParseExact
DateTime.ParseExact(value.ToString(), cultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern.ToString, cultureInfo.CurrentUICulture)
The more I think about this the more I think it's a bad solution but given you're getting no other answers I'll post it anyway.
DateTime temp;
DateTime.TryParse(input, CultureInfo.CurrentUICulture, DATE_TIME_STYLES, out temp);
if (temp.Year == DateTime.Now.Year)
{
if (!input.Contains(DateTime.Now.Year))
{
if (temp.Days != int.Parse(DateTime.Now.Year.ToString().SubString(2)))
{
// my god that's gross but it tells you if the day is equal to the last two
// digits of the current year, if that's the case make sure that value occurs
// twice, if it doesn't then we know that no year was specified
}
}
}
Also, as others have suggested in comments now, checking the number of tokens or the strings length could also be useful like;
char[] delims = new char[] { '/', '\', '-', ' '); //are there really any others?
bool yearFound = false;
foreach (char delim in delims)
{
if (input.Split(delim).Count == 3)
{
yearFound = true;
break;
}
}
if (yearFound)
//parse
else
// error
These are just a couple of ideas, neither is truly sound. They're obviously both hacks, only you can know if they'll suffice. At least they beat your co-workers if (dt.Year == 2014) //discard input "solution".

Allow user to only input text?

how do I make a boolean statement to only allow text? I have this code for only allowing the user to input numbers but ca'nt figure out how to do text.
bool Dest = double.TryParse(this.xTripDestinationTextBox.Text, out Miles);
bool MilesGal = double.TryParse(this.xTripMpgTextBox.Text, out Mpg);
bool PriceGal = double.TryParse(this.xTripPricepgTextBox.Text, out Price);
Update: looking at your comment I would advise you to read this article:
User Input Validation in Windows Forms
Original answer: The simplest way, at least if you are using .NET 3.5, is to use LINQ:
bool isAllLetters = s.All(c => char.IsLetter(c));
In older .NET versions you can create a method to do this for you:
bool isAllLetters(string s)
{
foreach (char c in s)
{
if (!char.IsLetter(c))
{
return false;
}
}
return true;
}
You can also use a regular expression. If you want to allow any letter as defined in Unicode then you can use this regular expression:
bool isOnlyLetters = Regex.IsMatch(s, #"^\p{L}+$");
If you want to restrict to A-Z then you can use this:
bool isOnlyLetters = Regex.IsMatch(s, #"^[a-zA-Z]+$");
You can use following code in the KeyPress event:
if (!char.IsLetter(e.KeyChar)) {
e.Handled = true;
}
You can use regular expression, browse here: http://regexlib.com/
You can do one of a few things.
User Regular Expression to check that the string matches your concept of 'Text' only
Write some code that checks each character against a list of valid characters. Or even use char.IsLetter()
Use the MaskedTextBox and set a custom mask to limit input to text only characters
I found hooking up into the text changed event of a textbox and accepting/rejecting the changes an acceptable solution. To "only allow text" is a rather vague definition, but you may as well check if your newly added text (the next char) is a number or not and simply reject all numbers/disallowed characters. This will make users feel they can only enter characters and special characters (like dots, question marks etc.).
private void UTextBox_TextChanged(object sender, EventArgs e)
{
string lastCharacter = this.Text[this.Text.Length-1].ToString();
MatchCollection matches = Regex.Matches(lastCharacter, "[0-9]", RegexOptions.None);
if (matches.Count > 0) //character is a number, reject it.
{
this.Text = Text.Substring(0, Text.Length-1);
}
}

Categories