DEV Community

James Moberg
James Moberg

Posted on

1

Convert Numbers to Text using ColdFusion and ICU4J

(This is a repost from my abandoned tumblr blog; dated 2016-11-17)

A client requested that we spell out numbers on their website in order to clarify some financial totals.  I initially planned on using the ColdFusion NumberAsString UDF from 2002. After reviewing the results, I thought it was worth a unit test comparison to review the results against ICU4J (java).

In the end, I decided to use ICU4J because:

  • ICU4J converts text using 180+ locales. Numbers are translated to each language (Chinese, Thai, French, Spanish, etc)
  • UDF adds title case capitalization to all number strings. (if needed, you can do this separately.)
  • UDF doesn't support negative values and will throw a CF error.
  • UDF doesn't use hyphenized numbers ("Forty Three" versus "forty-three")
  • UDF uses "cardinal-verbose" format w/o hyphened numbers (Adds the word "and" where commas should be.)
  • UDF decimal places are treated as positive-type number words (instead of using "point four three" for ".43")
123 = "one hundred twenty-three"
100001 = "one hundred thousand one"
9 = "nine"
64578.25 = "sixty-four thousand five hundred seventy-eight point two five"
0.333 = "zero point three three three"
Enter fullscreen mode Exit fullscreen mode

Here's the CFML source code:
https://gist.github.com/JamoCA/cd343524e417f382d5c706954e52dfaf

<!--- 2016-11-17 SpellOutNumberUS UDF
Blog: https://dev.to/gamesover/convert-numbers-to-text-using-coldfusion-and-icu4j-33kn
Tweet: https://x.com/gamesover/status/1816618788944773584
Requires icu4j-55_1.jar from http://site.icu-project.org/home/why-use-icu4j (Copy to Java Path or use JavaLoader)
Number Formats (Availability determined based on locale)
%spellout-ordinal-verbose: one hundred and twenty-third
%spellout-ordinal: one hundred twenty-third
%spellout-cardinal-verbose: one hundred and twenty-three
%spellout-cardinal: one hundred twenty-three
%spellout-numbering-verbose: one hundred and twenty-three
%spellout-numbering: one hundred twenty-three
%spellout-numbering-year: one hundred twenty-three
Some locales may need <cfprocessingDirective pageencoding="utf-8"> and setLocale("LOCALE_CODE") in order to render
--->
<cfscript>
function spellOutNumberUS(myNumber){
var response = "unknown numeric value";
if (!StructKeyExists(Request, "spellOutUlocale")){
Request.spellOutUlocale = createObject("java","com.ibm.icu.util.ULocale");
Request.spellOutthisLocale = Request.spellOutUlocale.init("en_US");
Request.spellOutruleBased = createObject("java","com.ibm.icu.text.RuleBasedNumberFormat").init(Request.spellOutthisLocale, 1);
}
if (isNumeric(arguments.myNumber)){
if (int(arguments.myNumber) IS arguments.myNumber){
response = Request.spellOutruleBased.format(javacast("long", val(trim(arguments.myNumber))), "%spellout-numbering");
} else {
response = Request.spellOutruleBased.format(javacast("double", val(trim(arguments.myNumber))), "%spellout-numbering");
}
}
return response;
}
</cfscript>
<!--- Run some random number tests.
NOTE: I compared with NumberAsString UDF. http://cflib.org/udf/NumberAsString Some differences:
- ICU4J converts text using 180+ locales. Numbers are translated to each language (Chinese, Thai, French, Spanish, etc)
- UDF adds title case capitalization to all number strings. (if needed, you can do this separately.)
- UDF doesn't support negative values and will throw a CF error.
- UDF doesn't use hyphenized numbers ("Forty Three" versus "forty-three")
- UDF uses "cardinal-verbose" format w/o hyphened numbers (Adds the word "and" where commas should be.)
- UDF decimal places are treated as positive-type number words (instead of using "point four three" for ".43")
--->
<h1>ICU4J - Spell Out Numbers (US)</h1>
<ol>
<CFLOOP FROM="1" to="100" INDEX="thisNum">
<CFSET n = val(RandRange(1, 2147483646, "SHA1PRNG"))>
<CFSET NDec = 0>
<CFIF RandRange(1,2,"SHA1PRNG") eq 1>
<CFSET NDec = val(RandRange(0, 99, "SHA1PRNG")) / 100>
<CFSET N = N + NDec>
</CFIF>
<CFIF RandRange(1,2,"SHA1PRNG") eq 1>
<CFSET N = N * -1>
</CFIF>
<li><h3>#N# = <b>#DecimalFormat(N)#</b></h3><!---
UDF = <CFTRY>#NumberAsString(N)#<CFCATCH><b>ERROR - #CFCATCH.Message#</b></CFCATCH></CFTRY><br>--->
ICU4J = <CFTRY>#spellOutNumberUS(N)#<CFCATCH><b>ERROR - #CFCATCH.Message#</b></CFCATCH></CFTRY></li>
</CFLOOP>
</ol>

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay