QuackFuzed.com is the personal ColdFusion coding blog of Matt Quackenbush. It exists primarily as a place for the author to learn, and hopefully to assist others in learning and/or avoiding some of the same pitfalls and mistakes. (Quack certainly makes enough mistakes daily to make up for the entire ColdFusion community.)

isValid() Bug?

Posted on July 15, 2008 at 6:22 AM in ColdFusion

I wrote some brand new validation routines over the weekend and went to test them out tonight; lo and behold, they completely failed. Pass valid data, and they simply failed. I was scratching my head. I've written a ton of regex (regular expressions) over the years, so I knew that my regex was correct. It had to be something else.

[Continue Reading]

Comments
(Comment Moderation is enabled. Your comment will not appear until approved.)

On 7/15/08 at 9:22 AM, Shaun Moore said:

It seems to me that the IsValid() tag is working correctly. In your example you have string set to: passw0Rd with the o in password a zero. Since that doesn't fall in the A-Z range you have, it doesn't match the IsValid() tag you have and so you'd get No returned. If the o in passw0Rd was an o and not a zero, it would return a yes, or if you included 0-9 in the range of your regex.

On 7/15/08 at 9:25 AM, Shaun Moore said:

One final comment. Since you have your regex set to "[A-Z]+" it is only checking for caps. So even if you changed the 0 to an o, it would fail. You'd have to have the string set to PASSWORD for it to work, either that or modify your regex to include the range of a-z also.

On 7/15/08 at 11:49 AM, Brad Wood said:

I'm guessing it isn't a bug. The refind is looking for at least one instance of your regular expression somewhere inside the string and the isvalid expects the ENTIRE string to match it.

You would probably need to add that there could be zero or more non-uppercase characters before and after the one or more upper case charactes. Something like"
.*[A-Z]+.*

Right now you are telling isvalid that the ENTIRE string needs to consist of one or more uppercase characters.

On 7/15/08 at 2:24 PM, Matt Quackenbush said:

Thanks guys for your comments, but I have to disagree with you. If I were testing for the entire string to consist of UPPER case, I'd write A[A-Z]+. That regex indicates that the match be from the beginning (A) to the end () of the string. Instead, all I'm looking for is one single occurrence of an UPPER case letter, which reFind() correctly indicates.

On 7/15/08 at 2:38 PM, Shaun Moore said:

Matt, the way that the REFind is working how you have it is that it is returning the position of the first match, in this case 7, since the 7th character is an uppercase R, which is the first match. It isn't saying that it is matching the entire string, only the 7th character. The IsValid tag looks for the entire string to be matched. You can see this yourself using the link you gave to the CF livedocs above: "A JavaScript regular expression that the parameter must match." This is looking for the entire string, and if it finds it, it will return true. You can see this if you change the string to PASSWORD, all letters and caps, or if you change your regex to include a-z and 0-9.

A great way to test for this quickly is using this site: http://regexpal.com/ which has a regex tester. You can place the regex in the top and place your string in the bottom and see if it will match. Using your regex it will match PASSWORD but not the string you have.

On 7/15/08 at 2:53 PM, Matt Quackenbush said:

Shaun, maybe I'm an idiot and just can't "see" what you're saying, but even the link you provided correctly indicates the 7th position. You keep saying that isValid() is testing the entire string, and that may well be, but that is *not* what the regex translates to. The regex "[A-Z]+" will match _anywhere_ within the string. The regex "A[A-Z]+" will match only if it's the entire string. That behavior is the same in JavaScript, perl, and every other language I've played in. It even works that way in ColdFusion, with reFind() and reFindNoCase(). Just not in isValid(). Surely Adobe didn't intend for all the regex you've written in your life to go out the window with isValid() and the rules have all changed?

On 7/15/08 at 3:01 PM, Shaun Moore said:

Matt, I see what you're saying now. I didn't realize you were only trying to ensure that they had one capital letter. I thought you were trying to match the string. The way you have it with REFind will obviously do what you want. The difference is, the IsValid tag has to match the entire thing. And if you use [A-Z]+, it will match more than one instance of A-Z. So if you had PASSWORD it would work, but if you had anything other than all capital letters it would fail. There isn’t a way (that I know of) to use IsValid to only match part of the string. I suppose you could turn the characters of the string into a list and then loop through that and check to see if any match the A-Z requirement, but that would be more code that you don’t need.

Still, I don’t see this as a bug, this is just how the IsValid function is supposed to work. I use it a lot to check form data to ensure that it is the correct type.

On 7/15/08 at 3:10 PM, Matt Quackenbush said:

Shaun, I just ran a few more tests, and, as you suggested, isValid() requires that the entire string match the regex. I have two major problems with that:

1. The documentation simply does not state that.

2. That behavior is the stupidest thing on the planet. WTF is the point of writing regex if the function is going to override what you write? And forcing the entire string to match from start to finish when the regex only calls for a one (or more) characters is absolutely asinine.

On 7/15/08 at 3:21 PM, Shaun Moore said:

Matt, I use it for validation where I want to be sure they put in exactly what I need. For example, on a CAPTCHA I made I have the images in a certain format, and to be sure they are using that format I check with this tag:

IsValid("regex", Form.IMGCode, "[a-zA-Z]{1}[0-9]{2}[a-zA-Z]{1}[0-9]{2}")

I've used this in certain date fields as well to be sure they are using a date range I want in a format I want:

IsValid("regex", Evaluate("Form.#Variables.FN#"), "^20[0-9]{2}")

So for cases like this it is very useful.

On 7/15/08 at 3:34 PM, Matt Quackenbush said:

Shaun, I get what you're saying, and that's cool. My issue with that is that, as I stated above, isValid() is actually changing the meaning of the regex that you're writing, and it is undocumented behavior. IMO, you'd be far better off writing...

if ( reFind("A[a-zA-Z]{1}[0-9]{2}[a-zA-Z]{1}[0-9]{2}", form.IMGCode) EQ 1 ) { return true }

and

if ( reFind("A^20[0-9]{2}", form[variables.FN]) EQ 1 ) { return true }

Relying on what amounts to bullshit behavior from isValid() will cause you problems if you move that to any other language, or even to reFind()/reFindNoCase(). For example, try this at the JavaScript site you linked to...

regex: [a-zA-Z]{1}[0-9]{2}[a-zA-Z]{1}[0-9]{2}

string: 8888a99A99zzzzzzzzzzzzzzzzzzzzzzzzzzzz

You'll correctly get a match. Now then, try the following...

regex: ^[a-zA-Z]{1}[0-9]{2}[a-zA-Z]{1}[0-9]{2}$

string: 8888a99A99zzzzzzzzzzzzzzzzzzzzzzzzzzzz

You will *not* get a match on that one, because the regex indicates that it must be the full string.

On 7/15/08 at 3:36 PM, Brad Wood said:

refind and isvalid are meant for two different things and the docs clearly state that.

The Livedocs for refind say:
"This function finds the first occurrence of a regular expression in a string."

"occurrence ... in a string" means that it looks for your expression among other, possibly non-matching strings inside of the string you specify.

The Livedocs for isvalid say:
"A JavaScript regular expression that the parameter must match"

Notice it says "the parameter", not "a portion" or "part" of the parameter. The entire parameter must be described by the pattern.

refind is meant for searching within a string, isvalid is meant for validating a string in its entirety. I think the behavior makes sense.

On 7/15/08 at 3:47 PM, Matt Quackenbush said:

Brad, I *think* I can bring myself to accept "the parameter" being their lame-ass attempt to indicate that isValid() is going to change the behavior of the regex that you write. But it still does not change the fact that the function *is* changing what you wrote to mean something else.

As far as the reFind()/reFindNoCase() portion of your comment goes, it seems that you are suggesting that they should not be used for matching an entire string. If that's the case, I do not agree.

On 7/15/08 at 4:08 PM, Matt Quackenbush said:

To continue my thought from above...

Yes, isValid() changes the behavior of what I wrote, which is very aggravating, because I believe the regex author should have full control over the regex. Otherwise, why write it? That said, if the docs _clearly_ stated that the parameter would have to match from beginning to end, then I could accept that. At least then the author would know that they have to change their regex.

Thank you Shaun and Brad both for your input. :-)

On 7/15/08 at 4:14 PM, Brad Wood said:

You certainly *could* use refind to match an entire string, but that is not its primary purpose. Its primary purpose is to tell you where in a string a substring can be found. That’s why the function returns an integer which is the location in the string that the substring exists, not a boolean. If I wanted to match an entire string I would probably just use isvalid for that. Either that or modify my regex into refind to start with ^ and end with $.

I can see your confusion since isvalid basically does the same thing as ^[A-Z]+$ when all you typed in was [A-Z]+ but the context of the function and what the docs describe as its behavior determine exactly what it is going to do with your regular expression.

I wouldn’t say the function is “changing” your regex. Your regex is simply a pattern, and the function can look for the pattern however and wherever it pleases based on its requirements.

On 7/15/08 at 4:33 PM, Matt Quackenbush said:

Brad, as I stated above, I now see your point about the context of isValid(), I just cannot agree with removing that control from the author. In other words, we shall agree to disagree. :-)
CodeBassRadio

Latest Articles

Eventually something really brilliant and witty will appear right here.

Calendar

July 2008
S M T W T F S
« Jun   Aug »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Subscribe

Enter a valid email address.

The Obligatory Wish List