I ran into an issue today where users were unable to lookup a certain part in our system. The part in question had a µ character in the product code (don’t get me started!). I started adding some debug outputs and found that when the part number was passed to our back end system, the µ had been replaced with an ‘M’!
After some more troubleshooting I figured out the culprit was ucase(). We run all part numbers through ucase() before passing them in. At first I thought this was a CF bug, after verifying that the java string.toUpperCase() method did exactly the same thing I had to look into it some more.
It turns out that M actually is the uppercase version of µ, sort of. The µ character, which is ascii code 181, is often used to abbreviate ‘micro’ as in microamp (µA) or microfarad (µF). Its the 12th letter of the greek alphabet, ‘Mu‘. The lowercase version is μ, the uppercase version is M.
I tested this on Railo and got exactly the same result, which makes sense because I think both engines just call the .toUpperCase() method in the JVM.
So while this is technically correct, I’m certain is almost never what the developer actually wants to do. I have not found a good way around this issue, except to maybe look specifically for this character, replace it out, do the ucase(), then put the character back. For now I was able to remove the ucase() calls because they were not absolutely necessary. Any other ideas?
Update: This is what I came up with as a work around. I thought it would be slow but benchmarking it shows its 0ms even with a 50 character string.
<cffunction name="safeUcase" returntype="string" hint="Uppercases only letters">
<cfargument name="inputString" />
<cfset local.outputString = "" >
<cfloop from="1" to="#Len(arguments.inputString)#" index="local.i">
<cfset local.chr = Mid(arguments.inputString,local.i,1) />
<cfset local.asciiCode = Asc(local.chr) />
<cfif local.asciiCode LTE 122 AND local.asciiCode GTE 97>
<cfset local.outputString &= ucase(local.chr) />
<cfelse>
<cfset local.outputString &= local.chr />
</cfif>
</cfloop>
<cfreturn local.outputString />
</cffunction>