Did You Know That "000" Equals "00A" In ColdFusion?
Dan Roberts just pointed out this very strange bug to me; apparently in ColdFusion the strings "0" (zero) and "A" are not equal unless they are preceded by zeros, in which case they are considered equal. I am sure this is a known bug, but I had never seen it, so I thought I would throw it out there.
To test this, I ran a bunch of comparison tests to see what worked and what failed:
<!--- Set the two strings for comparison. ---> <cfset strA = "00A" /> <cfset strB = "000" /> <p> <cfif (strA EQ strB)> #strA# EQ #strB# <cfelse> #strA# NEQ #strB# </cfif> </p> <p> <cfif (ToString( strA ) EQ ToString( strB ))> #strA# EQ #strB# (Using CF ToString()) <cfelse> #strA# NEQ #strB# (Using CF ToString()) </cfif> </p> <p> <cfif (strA.ToString() EQ strB.ToString())> #strA# EQ #strB# (Using Java ToString()) <cfelse> #strA# NEQ #strB# (Using Java ToString()) </cfif> </p> <p> <cfif strA.Equals( strB )> #strA# EQ #strB# (using Java Equals()) <cfelse> #strA# NEQ #strB# (using Java Equals()) </cfif> </p> <p> <cfif NOT Compare( strA, strB )> #strA# EQ #strB# (using Compare) <cfelse> #strA# NEQ #strB# (using Compare) </cfif> </p> <p> <cfif NOT strA.CompareTo( strB )> #strA# EQ #strB# (using CompareTo()) <cfelse> #strA# NEQ #strB# (using CompareTo()) </cfif> </p>
None of these should come out as being equal, but running the above code gives us the following output:
00A EQ 000
00A EQ 000 (Using CF ToString())
00A EQ 000 (Using Java ToString())
00A NEQ 000 (using Java Equals())
00A NEQ 000 (using Compare)
00A NEQ 000 (using CompareTo())
As you can see, the standard ColdFusion "EQ" operator works on all string values (no matter how that string value was generated). But, all of the more "Java-oriented" and character-wise approaches truthfully tell the two strings apart. This doesn't seem to happen with anything but "0" and "A". Very strange.
Want to use code from this post? Check out the license.
I would let the CF team know.
I submitted a bug report to Adobe not much earlier today.
Thanks for testing all of the equality functions/operators. I had to add some extra code to deal with this but will probably just switch it out with Compare() tomorrow.
I would be curious to know how you even found this?!? Also as far as moving to the Compare() method... you probably want to move to CompareNoCase() as it is case-insensitive and the EQ operator is also case-insensitive.
The company I work for manages a database of federal and states legislators. For some odd reason my boss decide way back when that the district field should have leading zeros, which he says makes it easier to eyeball problems. For example a district 1 is 001, a district A is 00A and officials without a district have 000. I was checking for district fields of 000 and of course ran into problems when records with 00A matched as well.
This came up a couple years ago but I just threw in a quick IsNumeric check which 00A fails on. That worked so I commented about the problem and moved on. Saw the comment today and thought it was about time I should bring it to their attention.
just did a small test and found that the IS operator behaves just like EQ.
The following link has some interesting information on the subject.
Regarding the above problem it says:
"Short strings, such as 1a and 2P, can produce unexpected results. ColdFusion can interpret a single "a" as AM and a single "P" as PM. This can cause ColdFusion to interpret strings as date-time values in cases where this was not intended."
So coldfusion is comparing 0:00 AM to 0:00 AM.
Nicely done! I guess this is ColdFusion's attempt to make things super easy for people to use (and at the same time, sacrificing a tiny bit of predictability). I certainly do love how easy it is to compare date/times in CF.
Thanks Gary. That gives me some idea of what's probably going on.
Oddly though I can only get it to happen with EQ using 0 and 0A. Doesn't happen with 1 and 1A for example or 13 and 1P. GT and LT only compare like this if you include letters on both strings. Anyways, something to keep in mind.
1 and 1a dont work because coldfusion turns the time into a fraction.
So for example the values
<cfset strA = "0.25" />
<cfset strB = "6A" />
would work. As strB is turned into 6:00 AM which is a quarter of a day (6/24 = 0.25).
Try "1p" EQ "13:"
Note the colon which, I guess, makes CF believe the string actually is the hour part of a time value.
I recently had a somewhat similar problem with some floating point values in CF. I was comparing values from records in two different sets of SQL Server query results, values that when cfdumped to the screen were exactly the same, yet the EQ comparison always evaluated as false. I tried doing a javacast() of both values to double and comparing them, but the EQ still came back false. Again, cfdumping the returned values from javacast() seemed to confirm they were the exact same values. So I tried converting the values using DecimalFormat(). The EQ comparison correctly evaluated as true.
Thought you guys might find it interesting to know the results of this code on Scorpio and BlueDragon (I have access to both). Scorpio is identical to CF 7, so they haven't 'fixed' this (yet). However, BlueDragon does it all correctly:
Go Blue Dragon! I can't wait to get my hands on Scorpio!
We are lucky enough to have an ex-Adobe employee on our team, and he was able to get us a copy of Scorpio Beta. I wish I could share some of the new stuff they've got in there, but maybe it suffices to say that I'm very excited about the additions. And I'm not talking about all the boring Adobe product integration we've already heard about.
I want to see if I can get a Beta. Apparently there is some program for it... time to do some snooping.
AFAIK the Scorpio Beta is public. Ben Forta posted a link to the Adobe Prerelease Program in his blog: http://www.forta.com/blog/index.cfm/2007/1/22/Anyone-Want-To-Beta-Test-Scorpio
can i use a wildcard when comparing in coldfusion
<cfif #variable# eq 'AE%'>
You cannot use a SQL wild card when comparing values. However, you can use a regular expression and the REFind() function.
<cfif #variable# eq 'AE%'>
and make it into:
<cfif REFind( "^AE.+?", variable )>
The "^" means match at the beginning of the string.
AE is the literal string you are looking for.
.+? means at least ONE character after AE but don't bother checking more than one. You can probably remove this and JUST use "^AE", but it depends on what you want to do.
Regular expressions are totally awesome. If you want to know more about them, check out this primer:
CFML supports the CONTAINS operator:
<cfif variable CONTAINS 'AE'>
Just keep in mind that this operator is case insensitive, like all basic decision operators in CFML.
For more information, take a look at the docs: http://livedocs.adobe.com/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=ColdFusion_Documentation&file=00000928.htm
Thanks for the tip!!!
Super old thread, but this obviously is still an issue (or intended to be this way???) :) I found this thread when searching for why CF was telling me that '14-0008' is equal to '14-8'. I would think that quotes around the string mean to read it as a string! Now I'm using CompareNoCase and it works great, just kind of odd behavior.
Thanks for sharing!