Simple regex failing test to determine a 3 digit number - c#

I have had a difficult time wrapping my head around regular expressions. In the following code, I used a Regex to determine if the data passed was a 1 to 3 digit number. The expression worked if the data started with a number (ex. "200"), but also passed if the data had a letter not in the first digit (ex. "3A5"). I managed to handle the error with the INT32.TryParse() method, but it seems there should be an easier way.
if (LSK == MainWindow.LSK6R)
{
int ci;
int length = SP_Command.Length;
if (length > 3) return MainWindow.ENTRY_OUT_OF_RANGE; //Cannot be greater than 999
String pattern = #"[0-9]{1,3}"; //RegEx pattern for 1 to 3 digit number
if (Regex.IsMatch(SP_Command, pattern)) //Does not check for ^A-Z. See below.
{
bool test = Int32.TryParse(SP_Command, out ci); //Trying to parse A-Z. Only if
if (test) //it no letter will it succeed
{
FlightPlan.CostIndex = ci; //Update the flightplan CI
CI.Text = ci.ToString(); //Update the Init page
}
else return MainWindow.FORMAT_ERROR; //It contained a letter
}
else return MainWindow.FORMAT_ERROR; //It didn't fit the RegEx
}

Regex.IsMatch searches the input string for the pattern (and thus returns true for 3A5 because it finds 3).
You should also include start (^) and end ($) of string:
String pattern = #"^[0-9]{1,3}$";

Adding line begin/end should help.
^[0-9]{1,3}$

Related

C#: Remove Excess Text From String

Okay, so after looking around here on SO, I have found a solution that meets about 95% of my requirement, although I believe it may need to be redone at this point.
ISSUE
Say I have a value range supplied as "1000 - 1009 ABC1 ABC SOMETHING ELSE" where I just need the 1000 - 1009 part. I need to be able to remove excess characters from the string supplied, even if they truly are accepted characters, but only if they are part of secondary strings with text. (Sorry if that description seems odd, my mind isn't full power today.)
CURRENT SOLUTION
I currently have a simple method utilizing Linq to return only accepted characters, however this will return "1000 - 10091" which is not the range I am needing. I've thought about looping through the strings individual characters and comparing to previous characters as I go using IsDigit and IsLetter to my advantage, but then comes the issue of replacing the unacceptable characters or removing them. I think if I gave it a day or two I could figure it out with a clear mind, but it needs to be done by the end of the day, and I am banging my head against the keyboard.
void RemoveExcessText(ref string val) {
string allowedChars = "0123456789-+>";
val = new string(val.Where(c => allowedChars.Contains(c)).ToArray());
}
// Alternatively?
char previousChar = ' ';
for (int i = 0; i < val.Length; i++) {
if (char.IsLetter(val[i])) {
previousChar = val[i];
val.Remove(i, 1);
} else if (char.IsDigit(val[i])) {
if (char.IsLetter(previousChar)) {
val.Remove(i, 1);
}
}
}
But how do I calculate white space and leave in the +, -, and > charactrers? I am losing my mind on this one today.
Why not use a regular expression?
Regex.Match("1000 - 1009 ABC1 ABC SOMETHING ELSE", #"^(\d+)([\s\-]+)(\d+)");
Should give you what you want
I made a fiddle
You use a regular expression with a capturing group:
Regex r = new Regex("^(?<v>[-0-9 ]+?)");
This means "from the start of the input string (^) match [0 to 9 or space or hyphen] and keep going for as many occurrences of these characters as are available (+?) and store it into variable v (?)"
We get it out like this:
r.Matches(input)[0].Groups["v"].Value
Note though that if the input string doesn't match, the match collection will be 0 long and a call to [0] will crash. To this end you might want to robust it up with some extra error checking:
MatchCollection mc = r.Matches(input);
if(mc.Length > 0)
MessageBox.Show(mc[0].Groups["v"].Value;
You could match this with a regular expression. \d{1,4} means match a decimal digit at least once up to 4 times. Followed by space, hyphen, space, and 1 to 4 digits again, then anything else. Only the part inside parenthesis is output in your results.
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var pattern = #"(^\d{1,4} - \d{1,4}).*";
string input = ("1000 - 1009 ABC1 ABC SOMETHING ELSE");
string replacement = "$1";
string result = Regex.Replace(input, pattern, replacement);
Console.WriteLine(result);
}
}
https://dotnetfiddle.net/cZGlX4

Regular expression for checking a number range (with decimals)

I am working on a window form which accepts certain range of value as input. So far, I could only find the range between 0 and 20000.
(20000|[0-9]|0[1-9]|[1-9]\d{0,3})$
Can somebody kindly help me with finding the range between 0.0 and 20479.0 (including decimals)?
As comments suggest, regex is far from ideal in these cases. It can be done though, but get quite complex.
^(?:(?:1?\d{1,4}|20[0-3]\d\d|204[0-6]\d|2047[0-8])(?:\.\d+)?|20479(?:\.0+)?)$
This does it using two outer alternations - one to match the maximum number and optionally any number of zeroes as decimals. The other (first) has several sub-alternations matching the maximum for the different digits, and allowing an optional decimal point and decimals.
1?\d{1,4} Matches 0-19999
20[0-3]\d\d Matches 20000-20399
204[0-6]\d Matches 20400-20469
2047[0-8] Matches 20470-20478
See it here at regex101.
Here is a suggestion that allows numbers between 0 and 20479 with decimals:
^(0?[0-9]{0,4}(?:\.\d+)?|1\d{4}(?:\.\d+)?|20[0-4][0-7][0-8](?:\.\d+)?|20479(?:\.[0-7])?)$
As you can see, it is a bit complex, you may not want to do it with a regex.
Demo on regex101
Explanation
(0?[0-9]{0,4}(?:\.\d+)? between 0.0 and 9999.99 (decimals are optional)
1\d{4}(?:\.\d+)? between 10000.0 and 19999.99 (decimals are optional)
20[0-4][0-7][0-8](?:\.\d+)? between 20000.0 and 2048.99 (decimals are optional)
20479(?:\.[0-7])? between 20479 and 20479.7
Update: Without decimals, you can use:
^(0?[0-9]{0,4}|1\d{4}|20[0-4][0-7][0-8]|20479$
If you expect only integers (.0 at the end) you could try this
Mask is
^((1?[0-9]{0,4})|((20(([0-3][0-9]{0,2})|(4[0-7][0-9])))))$
If you need .0 at the end add \.0 before $. If you need double/decimal than precision/range would be required.
Why would you use a regex that'll be hardly maintainable when you can use real code:
public bool IsValid(string input = "")
{
double inputParsed;
if (!double.TryParse(input, out inputParsed))
return false;
if(inputParsed < 0 || inputParsed > 20479)
return false;
return true;
}
Using regex get two numbers before and after the point.
Then check the numbers to hit the range.
var list = new List<string> { "VB0.0", "VB20479.0", "VB20479.7", "VB20480.0", "VB010000.0", "VB0.8", "VBx.y" };
string pattern = #"(\d+)\.(\d+)";
foreach (var input in list)
{
var m = Regex.Match(input, pattern);
if (m.Success)
{
string value1 = m.Groups[1].Value;
string value2 = m.Groups[2].Value;
bool result = value1.Length <= 5 && int.Parse(value1) <= 20479
&& value2.Length <= 1 && int.Parse(value2) <= 7;
Console.WriteLine(result);
}
else Console.WriteLine(false);
}

C# WPF using Regex validation. How to check numbers between a range?

I'm writing a program for Uni which requires some basic validation.
I have a textbox which allows the user to input their age. I have successfully written a Regex expression which checks if the value entered into the textbox contains numeric values only and is two characters long:
Regex agePattern = new Regex(#"^[0-9]{1,2}\z$"); // Age entered must be numeric characters only (0-9) and may only be two charaters long
if (agePattern.IsMatch(ageBox.Text) == false)
{
MessageBox.Show("Customer's age is not valid. Age must be in numeric format & can only be two characters long"); // If Regex pattern & entered string DO NOT match - user get's this message
return;
}
else
{
// do something
}
My question is, can I extend my Regex expression to constrain age values between 1 and 99?
I've not written any Regex before and I'm struggling.
Thanks!
How about parsing an integer instead?
bool IsValidAge(string ageString) {
int age;
return int.TryParse(ageString, out age) && age >= 1 && age <= 99;
}
Try this regex:
^[1-9]?[0-9]?\z
Or skip regex, parse the text as int and write a function which decide input is between 1 and 99.
Try this regex:
^[1-9]?[0-9]?\z
This matches an empty input (since both digits are optional) as well as 0. Fewer ? are better:
^[1-9][0-9]?$
Try it with A Better .NET Regular Expression Tester (most other online testers don't allow to specify an empty source).

Using RegEx to match Month-Day in C#

Let me preface this by saying I am new to Regex and C# so I am still trying to figure it out. I also realize that Regex is a deep subject that takes time to understand. I have done a little research to figure this out but I don't have the time needed to properly study the art of Regex syntax as I need this program finished tomorrow. (no this is not homework, it is for my job)
I am using c# to search through a text file line by line and I am trying to use a Regex expression to check whether any lines contain any dates of the current month in the format MM-DD. The Regex expression is used within a method that is passed each line of the file.
Here is the method I am currently using:
private bool CheckTransactionDates(string line)
{
// in the actual code this is dynamically set based on other variables
string month = "12";
Regex regExPattern = new Regex(#"\s" + month + #"-\d(0[1-9]|[1-2][0-9]|3[0-1])\s");
Match match = regExPattern.Match(line);
return match.Success;
}
Essentially I need it to match if it is preceded by a space and followed by a space. Only if it is the current month (in this case 12), an hyphen, and a day of the month ( " 12-01 " should match but not " 12-99 "). It should always be 2 digits on either side of the hyphen.
This Regex (The only thing I can make match) will work, but also picks up items outside the necessary range:
Regex regExPattern = new Regex(#"\s" + month + #"-\d{2}\s");
I have also tried this without sucess:
Regex regExPattern = new Regex(#"\s" + month + #"-\d[01-30]{2}\s");
Can anyone tell me what I need to change to get the results I need?
Thanks in advance.
If you just need to find out if the line contains any valid match, something like this will work:
private bool CheckTransactionDates(string line)
{
// in the actual code this is dynamically set based on other variables
int month = DateTime.Now.Month;
int daysInMonth = DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month);
Regex pattern = new Regex(string.Format(#"{0:00}-(?<DAY>[0123][0-9])", month));
int day = 0;
foreach (Match match in pattern.Matches(line))
{
if (int.TryParse(match.Groups["DAY"].Value, out day))
{
if (day <= daysInMonth)
{
return true;
}
}
}
return false;
}
Here's how it works:
You determine the month to search for (here, I use the current month), and the number of days in that month.
Next, the regex pattern is built using a string.Format function that puts the left-zero-padded month, followed by dash, followed by any two digit number 00 to 39 (the [0123] for the first digit, the [0-9] for the second digit). This narrows the regex matches, but not conclusively for a date. The (?<DAY>...) that surrounds it creates a regex group, which will make processing it later easier. Note that I didn't check for a whitespace, in case the line begins with a valid date. You could easily add a space to the pattern, or modify the pattern to your specific needs.
Next, we check all possible matches on that line (pattern.Matches) in a loop.
If a match is found, we then try to parse it as an integer (it should always work, based on the pattern we are matching). We use the DAY group of that match that we defined in the pattern.
After parsing that match into an integer day, we check to see if that day is a valid number for the month specified. If it is, we return true from the function, as we found a valid date.
Finally, if we found no matches, or if none of the matches is valid, we return false from the function (only if we hadn't returned true earlier).
One thing to note is that \s matches any white space character, not just a space:
\s match any white space character [\r\n\t\f ]
However, a Regex that literally looks for a space would not, one like this (12-\d{2}). However, I've got to go with the rest of the community a bit on what to do with the matches. You're going to need to go through every match and validate the date with a better approach:
var input = string.Format(
" 11-20 2690 E 28.76 12-02 2468 E* 387.85{0}11-15 3610 E 29.34 12-87 2534 E",
Environment.NewLine);
var pattern = string.Format(#" ({0}-\d{{2}}) ", DateTime.Now.ToString("MM"));
var lines = new List<string>();
foreach (var line in input.Split(new string[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries))
{
var m = Regex.Match(line, pattern);
if (!m.Success)
{
continue;
}
DateTime dt;
if (!DateTime.TryParseExact(m.Value.Trim(),
"MM-dd",
null,
DateTimeStyles.None,
out dt))
{
continue;
}
lines.Add(line);
}
The reason I went through the lines one at a time is because presumably you need to know what line is good and what line is bad. My logic may not exactly match what you need but you can easily modify it.

Is it possible to write a regular expression to check this:

Is it possible to write a regular expression to check whether all numbers of specific 10 digit number occured up to 3 times?
for example return value for Regex.IsMatch("xxxx", "4433425425") is false.
and for Regex.IsMatch("xxxx", "4463322545") is true. what is xxxx?
in the first one i have 4 occurrence of digit 4 and in second one non of digits occurred more than 3 times.
Will match any digit that has four or more instances
string found = Regex.Match(s,#"(\d).*\1.*\1.*\1").Groups[1].Value;
Just an example of how to use it
static void Main( string[] args )
{
string fail = "1234567890";
string s = "1231231222";
string mTxt = #"(\d).*\1.*\1.*\1";
Console.WriteLine( Regex.Match(s,mTxt).Success);
Console.WriteLine(Regex.Match(fail, mTxt).Success);
}
Baised on #Brads Comments below use
([0-9]).*\1.*\1.*\1
Find a number occurring three times in a row:
(?=(0{3}|1{3}|2{3}|3{3}|4{3}|5{3}|6{3}|7{3}|8{3}|9{3}).{3}
Find a number occurring three times anywhere in the string:
(.?0.?){3}|(.?1.?){3}|(.?2.?){3}|(.?3.?){3}|(.?4.?){3}|(.?5.?){3}|(.?6.?){3}|(.?7.?){3}|(.?8.?){3}|(.?9.?){3}
Using backreferences (C/O #rerun):
([0-9]).*\1.*\1.*
NOTE: this will check the entire string for multiple characters. There is no limitation to the first 10 characters in the string. Let me know if you need that.
I'm going to risk downvotes here and suggest that regexes are most likely not the best tool for this job.
They have their place but I usually find that, if you're getting into "horrendous" territory with multiple backtracking or negative lookahead and lots of or clauses, you're probably better off tossing away the whole regex idea and writing a simple string scanning function which simply count each digit and ensures the counts are correct at the end. Pseudo-code something like:
def isValid (str):
foreach ch in '0'..'9':
count[ch] = 0
foreach ch in str:
if ch not in '0'..'9':
return false
count[ch] = count[ch] + 1
foreach ch in '0'..'9':
if count[ch] > 3:
return false
return true
That's my advice, take it or leave it, I won't be offended :-)

Categories