I am looking to create a regular expression in Delphi XE that will match a number followed by one decimal point, followed by (essentially) an unlimited number of digits.
Valid examples:
2.334
150.2
0.23
3
Invalid examples:
3..42
4-2.3
e5.64
3 145
The decimal point may be optional and integers are also okay.
How would one go about doing this in Delphi using TRegEx?
Edit:
This is what I have thus far:
enter function CheckCoefficientBoxesValidInput(InputtedTerm : TEdit) : boolean;
var
RegularExpression : TRegEx;
Match : TMatch;
begin
RegularExpression.Create('[-+]?[0-9]*\.?[0-9]+');
Match := RegularExpression.Match(InputtedTerm.Text);
if Match.Success then
begin
ShowMessage('Success.');
end;
end;
Edit 2:
Trying @DavidHeffernan's code:
Function CheckCoefficientBoxesValidInput(InputtedTerm : TEdit) : boolean;
var
RegularExpression : TRegEx;
Match : TMatch;
begin
CheckCoefficientBoxesValidInput := true;
if not RegularExpression.IsMatch(InputtedTerm.Text, '[-+]?[0-9]*\.?[0-9]+') then
CheckCoefficientBoxesValidInput := false;
end;
Unfortunately this doesn't seem to be working.
You probably want to cater for a sign too, to allow for negative numbers. This should do.
[-+]?[0-9]*\.?[0-9]+
This won't recognise scientific notation but then you did not ask for that. This returns True
if the pattern can be found anywhere inside the input text. I don't know your full requirements, but I guess you want to match against the entire input string. Use the ^
and $
start and end of line anchors for that. And perhaps you want to allow whitespace around the value too:
^\s*[-+]?[0-9]*\.?[0-9]+\s*$
Test for a match like this:
TRegEx.IsMatch(Input, '^\s*[-+]?[0-9]*\.?[0-9]+\s*$')
A demonstration:
{$APPTYPE CONSOLE}
uses
System.RegularExpressions;
procedure Check(const Input: string);
begin
Writeln(Input, ' ', TRegEx.IsMatch(Input, '^\s*[-+]?[0-9]*\.?[0-9]+\s*$'));
end;
begin
Check('2.334');
Check('150.2');
Check('0.23');
Check('3');
Check('3..42');
Check('4-2.3');
Check('e5.64');
Check('3 145');
end.
Output
2.334 TRUE 150.2 TRUE 0.23 TRUE 3 TRUE 3..42 FALSE 4-2.3 FALSE e5.64 FALSE 3 145 FALSE
The reference for Delphi regular expressions is here: http://www.regular-expressions.info/
And the documentation for the Delphi regular expression class: http://docwiki.embarcadero.com/Libraries/en/System.RegularExpressions.TRegEx
It would be far easier just to call TryStrToFloat
.
I know all the cool kids love RegEx, but imho it is overkill for this sort of problem when a very simple validation routine will do the job (and is far more likely to be comprehensible in months/years to come).
Something along the lines of:
function IsValidNumber(s: String): Boolean;
var
parts: TStringDynArray;
begin
parts := SplitString(s, '.');
case Length(parts) of
1: result := StrToIntDef(s, -1) <> -1;
2: result := (StrToIntDef(parts[0], -1) <> -1)
and (StrToIntDef(parts[1], -1) <> -1);
else
result := FALSE;
end;
end;
Having said that, a more general solution may be desirable and as an aside I would mention that in my own code if I had the same requirement I would use my own string template class.
This is essentially a "regex for mere mortals", allowing a simpler process of pattern matching based on variable elements within a string - optionally of an enforced type (int, guid etc) - separated by well-known literal parts.
In this case my class would have solved the problem thus:
if TStringTemplate.Match(['[:int]', '[:int].[:int]'], s) then
You supply an array of templates and a candidate string to match against those templates. The first match 'wins' and TRUE is returned. If there are no matches then FALSE is returned. Where a string matches a template you can optionally capture the variable parts into a name/value pair list (a TStringList which you must supply). So, given these calls:
TStringTemplate.Match(['[whole:int]', '[whole:int].[decimal:int]'], '42', list);
TStringTemplate.Match(['[whole:int]', '[whole:int].[decimal:int]'], '3.14159', list);
Then list will contain, in each case:
[0] whole=42
and
[0] whole=3
[1] decimal=14159
If the variable parts aren't named then the corresponding variables are simply added to the list as values in the order in which they occur in the matched value:
TStringTemplate.Match(['[whole:int]', '[:int].[:int]'], '3.14159', list);
Will yield the list:
[0] 3
[1] 14159
Unfortunately I cannot currently publish this class as it is in turn dependent upon my own string library which is currently undergoing a major overhaul, prior to release in my github repo. But if you are interested I will let you know when it's ready (v. soon) or you can just "watch" my repo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With