(How Much Is) That Doggie in the Window? How much is that doggie in the window?
The one with the waggly tail
How much is that doggie in the window?
I do hope that doggie's for sale
Patti Page
One of the problems you're likely to face when dealing with user input of currency in an international market is the difference between number formats and the ambiguity it may introduce.
If we ignore currencies that don't allow fractional values (like the Yen), there's a big difference when trying to convert either "123,456,789.01" and "123.456.789,01" even though when a human looks at them we can tell they're the same.
For UI engineers, you'll likely use either
parseInt
or parseFloat
- unless you give up entirely and pass the value unmodified. This poses a problem, because although there is a method to convert a number to a string that considers locale, the functions that convert strings to numbers do not.So, what are we to do? First, let's look at what's native in JavaScript to help us find the underlying assumptions. The
parseInt
method is pretty self-explanatory, aside from what happens on corner cases where you're trying to convert without a radix
or the like - and the parseFloat
method is only slightly less self-explanatory.The
parseFloat
method does not consider locale, even though the methods provided to convert a floating point to a string do. If, for example, a comma is used as a fractional separator, everything to the left of the comma will be taken as an integer. If the user - let's say one who lives in Germany - enters a number as 1.234,56 then our friendly method will convert that to 1 and 234 thousandths. If you're expecting one thousand two hundred thirty four and fifty-six hundredths, getting one and twenty-three hundredths is probably going to be disappointing. If the user - let's say one who lives in the US - enters a number as 1,234.56 then our friendly method will convert that to one (you won't even get the 234 thousandths).By looking at the behavior of
parseFloat
, we learn that a dot is always interpreted as a fractional separator. We (UI engineers) just need to determine what to do when there are multiple separators and, more importantly, both types of separators (comma and dot) in a number string.When writing numbers using separators, the rightmost separator is the fractional separator - everything else is a grouping separator - unless there are only grouping separators. How do we know if the separator is a grouping separator and not a fractional separator? We have to make an educated guess, based on the number of "groups".
Following these assumptions makes our enhanced parsing much simpler than what we might have thought at the beginning. All we need to do is split the string on the fractional separator, reconstruct the string in a format
parseFloat
always understands, and let parseFloat
do the heavy lifting - a little task that can easily be handled by creative use of the indexOf method, giving us something like the code below.JavaScript
Note that if you cannot use
lastIndexOf
, you'll need to reverse the string, use indexOf
and subtract that from the length
(and don't forget to subtract 1 because it's a zero-based index). Lines 2-7 change to those show below, but everything beyond the variable declaration and assignment block will remain the same.JavaScript
This method will accurately parse arabic numerals for the primary locale-based formats (shown below) much more reliably than
parseInt
or parseFloat
alone. As a demo, click on any of the amounts and a JavaScript alert message will appear that will show you the string as it is in the table cell, the value you would get if you used parseFloat, and the value my internationalized version returns.
Number format examples for multiple locales Locale Example Danish 4 294 967 295,123 English (CA) 4 294 967 295,123 English (GB) 4,294,967,295.12 English (US) 4,294,967,295.12 Finnish 4 294 967 295,123 French 4 294 967 295,123 French (CA) 4 294 967 295,123 German 4 294 967.295,123 Italian 4.294.967.295,123 Norwegian 4.294.967.295,123 Spanish 4.294.967.295,123 Swedish 4 294 967 295,123 Thai 4,294,967,295.12
Update
If you are coding specifically for next generation browsers, you can use the JavaScript Intl object to simplify your code, assuming you also know the user's locale (you can check browser support at http://caniuse.com/#feat=internationalization). If you can use the Intl object, your code becomes something like this...Happy coding.
No comments:
Post a Comment