The following information was sent to me by Baz (he didn't send a last name, so for now I'm assuming he is an eccentric rock star looking to change careers and become a web developer). As you know, or may not know, CFMX7 added a cool new function called isValid(). isValid lets you do all kinds of nice checking on strings. For example:
<cfoutput>Enter a valid email address, you wanker!</cfoutput>
</cfif>
<cfif not isValid("ssn", form.ssn)>
<cfoutput>Yes, I know social security won't be around when
you retire, but you must still enter a valid SSN!</cfoutput>
</cfide>
The two examples above show logic that would have been possible only with complex regex checks in the past. As you can imagine, the style above is somewhat simpler.
One of the isValid checks is for integers. An integer is a positive or negative whole number. So 42 is an integer, but 3.14159. What Baz discovered, however, was that the integer check was a bit too loose. Consider these four checks:
isValid("Integer","500,000")
isValid("Integer","500,0")
isValid("Integer","$500,000")
isValid("Integer","$500,000$")
Looking at the code above, I'd assume they would all return false. However - all four evaluate to true! Now - as we all know, ColdFusion is a bit loose when it comes to variables. That's part of the whole RAD aspect, and frankly I don't want to start a thread on that being good or not. That being said, I think both Baz and I agree that the assumption is that isValid would be more strict. It is certainly strict when doing a numeric check.
So if you do want to verify that a value is a proper integer, what do you do? I suggested a regex check:
isValid("regex", "101", "^-{0,1}[1-9]+[\d]*")
while Baz suggested a two-thronged approach:
isNumeric(OrderID) AND isValid("Integer",OrderID)
Personally, I like mine better, but who doesn't like their own code. Certainly the second one is probably a bit easier to read.
p.s. I've already logged a bug on this.
Archived Comments
Im not sure I follow. I would look at those examples and say that all four should return false. A , is not a numeric symbol. IsNumeric("500,000") should return false as well. Of course the $ should work the same as well. These would be symbols to help to describe numeric values true, but are not part of the number themselves. But im not really sure what you were talking about with coldfusion being loose, in this case, it seems that coldfusion is being stricter than you would have expected. But I dont think isValid("integer","500,000") == false is a bug, I think thats right.
Mistyped. Edited. Fixed. :) Should make sense now.
Ah ha, Much more sense now. I definately concur then ;)
Your regex should be
isValid('regex', '101', '^-?[0-9]+$')
This says match a string that starts with either zero or one minus signs followed by one or more numbers until the end of the string. This does the same thing
isValid('regex', '101', '^-?\d+$')
In truth, the above is not a test for numeric but a test for integer as it does not take decimals into account.
If your going to include the use of decimal or commas (used in Europe as a decimal), then this will be used
isValid('regex', '101', '^-?[0-9]+[.,]?[0-9]*$')
This matches a string with zero or one minus at the start, 1 or more digits followed by zero or one decimal or comma followed by zero or more digits.
The CF-RegEx list exists just for such nitpicking. :)
I think your first regex is wrong. I would not consider -0 to be a valid integer. -1, yes. 0, yes. But not -1. Also, your first regex would allow for 01. Again - to me - not valid.
As for commas - no - that was part of the point. We do not want to allow "formatted" numbers. Just numbers. Period. (I do not consider the - sign to be a format.)
True. It was that -{0,1} that really grabbed my attention rather than -?.
So Ray, it seems like you won - RegEx is the better way to go.
Another problem I've run into with isValid for integers is big numbers. Currently the isValid function is limited to 4 bytes or integers between -2,147,483,648 and 2,147,483,647 (like INT's in databses).
So isValid("Integer",99999999999999999) = FALSE
While isNumeric(99999999999999999) = TRUE
So I've even had to ditch my new preferred method of integer validation:
<cfif isNumeric(var) AND isValid("Integer",var)>
But being the stickler for clarity that I am (I like to be able to skim through a page and know what everything's doing) - and given my inability to quickly decipher what a RegEx is doing - I wasn't too quick to adopt the RegEx way and looked for other ways to validate my integers.
That brought me back to good 'ol:
<cfif round(var) is var> (like the isInt() function on CFLIB.org)
But you see, it turns out that that doesn't work either, because of this:
Round(9999999999999)=1E+013
If you try and round any number bigger than 12 digits, the result is the scientific representation of the number and will therefore not equate to the var even if its an integer.
I'm sure there are ways to fix that up, but now we're sacrificing the clarity I was striving to achieve, not mention the guilt for having to use so much overhead to do something as simple as validate an integer.
So conclusion: Ray's way's the best way - RegEx all the way.
(you may wanna update or add another isInt UDF on CFLIB)
I realize that this is a really old post, but the regex you suggested does not consider zero to be a valid integer. Bit of a problem, really :)
I think this would work: /^((-[1-9])|0)\d*/
Or, isValid("regex", "101", "^((-[1-9])|0)\d*)
Old, but still needed, and close, not quite. The '-' needs to be optional, and an ending "$" is needed.
Try this regex:
^((-?[1-9])|0)\d*$
Arrg, still not right... That version allowed "000" etc.
Try this:
^(0|((-?[1-9])\d*))$
Ray,
A fellow developer sent me a link to this post and mentioned he had tested the integer bug in CF9 and it was still there...which is....sad. I'll go with sad.
Ever get any word from Adobe on this?
Not that I know of. Adobe may consider it desired behavior due to how they treat #s in general.