RegEx Model Validation: Whole Number or Decimal Multiples of .25 - c#

I am trying to compose a regular expression to match a numeric value expressed as a decimal multiple of .25 (ex. 1.25, 14.75).
// Must Match
1.0
1.25
1.250000
1.5
1.500
1.75
1.7500
// Must Not Match
1.2
1.46
1.501
1.99
So far I have the following expression: \d+(\.((0+)|(250*)|(50*)|(750*))). It works when I use online tooling like gskinner.com/regexr. When I use the expression in a validation attribute to seed my EntityFramework db, it produces validation errors:
[RegularExpression(#"^\d+(\.((0+)|(250*)|(50*)|(750*)))$", ErrorMessage = "Hours must be 15 minute increments expressed as decimals (ex. .0, .25, .5, .75)")]
public double Hours { get; set; }
Similar question (I am looking for a way to round the decimal portion of numbers up or down to the nearest .25, .5, .75, or whole number) but I need to use a regular expression to use the above data annotation.
Question:
Anyone see what's wrong with my expression?
Bonus points if you can extend it to support whole numbers (ex. 4 or 4.25 but not 4. or 4.62)

To match such number use regex pattern
(?!0\d)\d+(?:[.](?:25|5|75|0)0*)?(?!\d)
To validate input to be such number use regex pattern
^(?!0\d)\d+(?:[.](?:25|5|75|0)0*)?$
In both cases, the very first part (?!0\d) is optional to disallow match/validate numbers with invalid leading zeros, such as 000003.250, when match would trim them and take just 3.250; validation would fail if this optional part is present in the regex.

This matches whole numbers too:
^\d+(\.(25|5|75|0)0*)?$
I tested it with RegexHero. It has a .NET Regex engine in the backstage. If you're using all test cases together, make sure that you make Multiline option selected, so that ^ and $ symbols match each line individually, not the whole text.

Related

C# regex to match exact number (including integers and decimals)

Summary
I'm trying to use regex to match an exact number (i.e. the number as a human would understand it, not the digit itself) within a larger string. The number I'm trying to match will vary. It could be an integer or a decimal, and it could be a single digit or multiple digits.
Examples
If trying to match the number 2, I want it to find the 2 in x + 2 + 3 but not in 2.5, 2.52 or 5.2 (because that's the digit 2, not the actual number 2).
If trying to match the number 2.5, I want it to find the 2.5 in x + 2.5 + 3 and 2.5, but not 2.52 or 12.5.
Note that 2 and 2.5 are just examples, I want this to work for any arbitrary positive number (if it works for negative numbers that's not a problem, but it's also not a requirement).
Initial attempt
I started with (\bX\b)+ (where X will be the number I want to match), which works when X is 2.5 but not when X is 2. This is because it's using word breaks to identify the start and end of the number, but a decimal point counts as a word break. This means that if X is 2 (i.e. the regex is (\b2\b)+) it will match the number 2 (correct), but also 2.x (incorrect) and x.2 (also incorrect).
Current attempt
I've fixed the problem of 2.x by changing the expression to (\bX\b(?!\.))+. This excludes numbers where X is followed by a decimal point, so if X is 2 it will match 2 (correct), will not match 2.x (correct) but will still match x.2 (incorrect). If X is a decimal number, this works correctly (so if X is 2.5 it will correctly match 2.5 and exclude 12.5 or 2.51).
How can I avoid matching X when it's preceded by a decimal point?
Real use-case
If it helps, the end goal is to use this with the C# Regex.Replace function as follows:
private static string ReplaceNumberWithinFormula(string originalFormula, double numberToReplace, string textToReplaceNumberWith)
{
return Regex.Replace(originalFormula, $#"(\b{numberToReplace}\b(?!\.))+", textToReplaceNumberWith);
}
You may use
private static string ReplaceNumberWithinFormula(string originalFormula, double numberToReplace, string textToReplaceNumberWith)
{
return Regex.Replace(originalFormula, $#"(?<!\d\.?){Regex.Escape(numberToReplace.ToString())}(?!\.?\d)", textToReplaceNumberWith);
}
See the C# demo
The (?<!\d\.?){Regex.Escape(numberToReplace.ToString())}(?!\.?\d), given the variable inside is equal to 2.5, translates into (?<!\d\.?)2\.5(?!\.?\d) and matches 2.5 only if
(?<!\d\.?) - not preceded with a digit and an optional .
(?!\.?\d) - not followed with an optional . and then a digit.
See the regex demo.
A simpler regex that will work with the input like you have only can be a word boundary + lookarounds based pattern like
private static string ReplaceNumberWithinFormula(string originalFormula, double numberToReplace, string textToReplaceNumberWith)
{
return Regex.Replace(originalFormula, $#"\b(?<!\.){Regex.Escape(numberToReplace.ToString())}\b(?!\.)", textToReplaceNumberWith);
}
Here, the regex will look like \b(?<!\.)2\.5\b(?!\.) and will match a word boundary position first (with \b), then will make sure there is no . right before the location (with (?<!\.)), then will match 2.5, assure there is no word char (letter, digit, or _) right after the number and then will check that there is no . after the number. See this regex demo.
It is equal to $#"(?<![\w.]){Regex.Escape(numberToReplace.ToString())}(?![\w.])", and is more restrictive than the top solution that will let you match the exact float or integer number in any context.
Add also a negative lookbehind:
((?<!\.)\b2\b(?!\.))+
Check the demo.
I think this is what you are looking for
^\d+(\.\d+)?\b
This matches whole numbers like 2
Matches decimal numbers like 2.1
Does not match patterns like 2. or .3

Regex Pattern to Validate Text Input With Max Value and Max Decimal Place

I need to create a pattern for a "text" type input to only allow a number from 0 to a specific max value and at the same time and validate to a specific number of decimal places.
Quick example:
Max Value = 300.86
Max Decimal Places = 3
Valid inputs:
0
1
300
300.86
300.85
300.850
300.851
.2
0.3333
Invalid inputs:
-1
301
300.87
300.861
1,30.2
1,.0
,.1
Currently I only know how to validate number of decimal places using this pattern:
^[,0-9]*(.\d{1,{0}})?$
Note:
I can't use type=number because I can't use any pattern with that :(
please help
I think something like this, is what you're after:
^(300(?:\.(?:[0-7]\d{0,2}|8(?:[0-5]\d?|60?)?))?|[0-2]?\d{0,2}(?:\.\d{0,3})?)$
See it here at REGEX STORM.
(Had to tweak it there, to end in \r, because REGEX STORM wouldn't match $ with end of line even though multi-line was selected???)
Explanation
It has two parts. The latter [0-2]?\d{0,2}(?:\.\d{0,3})? test for numbers below 300. It optionally starts with 0, 1 or 2 ([0-2]?). Then any two digits can follow (\d{0,2}). Then, optionally, it's followed by a . which, if present, can be followed by up to three digits (decimals) ((?:\.\d{0,3})?).
The first part - 300(?:\.(?:[0-7]\d{0,2}|8(?:[0-5]\d?|60?)?))? - test for when the integer part is exactly 300. It may then optionally be followed by a decimal point, and one out of three cases:
[0-7]\d{0,2} a digit in the range 0 to 7, followed by up to two digits
8(?:[0-5]\d*|60*)? an 8 followed by a digit in the range 0 to 5, optionally followed by a digit (The [0-5]\d? alternation).
or the number 86 and an optionall 0 (the 60? alternation)
These parts are in a capturing group separated by an alternation - |. The whole expression must be at the start of the string (^) (or line with multi-line flag) and at the end of the same ($).
Edit
Done some tweaking 'cause some numbers wrongly failed.
Edit 2
Completely missed "the maximum number of decimals" part. Fixed. (Fooled by the "valid" example 0.3333)
I don't know anything about C# so I'll just have to assume that what I can do in Python, you can find some way to do in C#. I'll give you my suggestion in pseudocode (this is not meant to mirror Python).
maxValue = some number
nDecimals = some number
givenValue = text with some number to be tested
#split number on decimal; remove non-digit characters from each side
leftSideOfDecimal = Replace(pattern = '^(\d{1,3}(,\d{3})*)(\.\d*)$', replacement = '\1', givenValue)
leftSideOfDecimal = Replace(',', '', leftSideOfDecimal)
rightSideOfDecimal = Replace('^(\d{1,3}(,\d{3})*)(\.\d*)$', '\3', givenValue)
rightSideOfDecimal = Replace('\.','',rightSideOfDecimal)
leftSideOfDecimal = pass leftSideOfDecimal to function to change type from text to integer
if leftSideOfDecimal <= maxValue and numberOfCharacters(rightSideOfDecimal) == nDecimals:
do whatever you want
Alternatively, if you have a function by which you can split strings on a given character (like a decimal or comma), then you just split the input on the decimal, clean up the first side as in the code, and then proceed with the last three lines of the code above. That way would save you from having to use a mildly complicated regex.

Find matching sequences that have exactly one deviation

I'm trying to implement a feature which takes a sequence of digits (U.S. Social Security Numbers) as an argument and returns a collection of SSNs which match the input except for exactly one deviation.
So, the input 123456789 would return:
123356789
193456789
123450789
But would not return 123546789, etc.
I have a system in ASP.NET which does pattern matches on inputs with wildcards, like 123**6789. So I could adapt that, using a loop, to this. But if there was a single regex for this, I would just implement it in SQL and be done with it.
So, is there a regex that will do this without having to call it in a for loop?
Unfortunately I'm not specialist in regular expressions but I think that you can use simple regular expression to check absolute value of subtraction between testing value and your input value. Acceptable result should be exactly 1 digit and 0 or more trailing zeroes. For your example values:
Testing value Input value ABS(Subtraction)
--------------+--------------+------------------
123356789 123456789 100000
193456789 123456789 70000000
123450789 123456789 6000
123456786 123456789 3

Specific decimal number regular expression

I have regular expression validator with expression like:
^\d{1,4}(\,\d{1,3})?$
I wan`t to validate next formats:
Decimal numbers with max 3 decimal places like 0,125 1,15, 0,5 but not(1,1234) that is ok but, user can write 5 digits like (12345, 54321 ... )
Exclude 0, so if user just write 0, there will be an error but user can write 0,5 or 0,125... I don`t know how to manage that
So everything is working fine except scenario 2. I don`t know how to exclude only 0... can I do that with regular expression validator, or should I try with custom validator in function(check if value is 0)
You could prohibit the number from containing all zeros with a negative lookbehind. That would also invalidate all entries that consist of zeros and dots, but that's probably a good thing: it is very likely that since you do not want a standalone zero, you do not want 00, 000, or 0.000 as well:
^(\d{1,4}(\.\d{1,3})?)(?<!^[0\.]+)$
// ^^^^^^^^^^^^
// |||
// The lookbehind part
The part that I added to your expression checks that the string does not consist entirely of zeros and dots. Here is a demo on ideone.

Regular expression to detect whether input is a formatted number

Regular Expressions have always seemed like black magic to me and I have never been able to get my head around building them.
I am now in need of a Reg Exp (for validation putsposes) that checks that the user enters a number according to the following rules.
no alpha characters
can have decimal
can have commas for the thousands, but the commas must be correctly placed
Some examples of VALID values:
1.23
100
1,234
1234
1,234.56
0.56
1,234,567.89
INVALID values:
1.ab
1,2345.67
0,123.45
1.24,687
You can try the following expression
^([1-9]\d{0,2}(,\d{3})+|[1-9]\d*|0)(\.\d+)?$
Explanation:
The part before the point consists of
either 1-3 digits followed by (one or more) comma plus three digits
or just digits (at least one)
If then follows a dot also some digits must follow.
^(((([1-9][0-9]{0,2})(,[0-9]{3})*)|([0-9]+)))?(\.[0-9]+)?$
This works for all of your examples of valid data, and will also accept decimals that start with a decimal point. (I.e. .61, .07, etc.)
I noticed that all of your examples of valid decimals (1.23, 1,234.56, and 1,234,567.89) had exactly two digits after the decimal point. I'm not sure if this is coincidence, or if you actually require exactly two digits after the decimal point. (I.e. maybe you're working with money values.) The regular expression as I've written it works for any number of digits after the decimal point. (I.e. 1.2345 and 1,234.56789 would be considered valid.) If you need there to be exactly two digits after the decimal point, change the end of the regular expression from +)?$ to {2})?$.
try to use this regex
^(\d{1,3}[,](\d{3}[,])*\d{3}(\.\d{1,3})?|\d{1,3}(\.\d+)?)$
I know you asked for a regex but I think it's much saner to just call double.TryParse() and consider your input acceptable if that method returns true.
double dummy;
var isValid=double.TryParse(text, out dummy);
It won't match your testcases exactly; the major difference being that it is very lenient with commas (so it will accept two of your INVALID inputs).
I'm not sure why you care, but if you really do want comma strictness you could do a preprocessing step where you only check the validity of comma placement and then call double.TryParse() only if the string passes the comma placement test. (If you want to be truly careful, you'll have to honor the CultureInfo so you can know what character is used for separators, and how many digits there are between separators, in the environment your program finds itself in)
Either approach results in code that is more "obviously right" than a regex. For example, you won't have to live with the fear that your regex left out some important case, like scientific notation.

Categories