views:

1526

answers:

4

A thought struck me as I was writing a piece of JavaScript code that processed some floating point values. What is the decimal point symbol in JavaScript? Is it always .? Or is it culture-specific? And what about .toFixed() and .parseFloat()? If I'm processing a user input, it's likely to include the local culture-specific decimal separator symbol.

Ultimately I'd like to write code that supports both decimal points in user input - culture-specific and ., but I can't write such a code if I don't know what JavaScript expects.

Added: OK, Rubens Farias suggests to look at similar question which has a neat accepted answer:

function whatDecimalSeparator() {
    var n = 1.1;
    n = n.toLocaleString().substring(1, 2);
   return n;
}

That's nice, it lets me get the locale decimal point. A step towards the solution, no doubt.

Now, the remaining part would be to determine what the behavior of .parseFloat() is. Several answers point out that for floating point literals only . is valid. Does .parseFloat() act the same way? Or might it require the local decimal separator in some browser? Are there any different methods for parsing floating point numbers as well? Should I roll out my own just-to-be-sure?

A: 

As far as I'm aware, javascript itself only knows about the . separator for decimals. At least one person whose judgement I trust on JS things concurs:

http://www.merlyn.demon.co.uk/js-maths.htm#DTS

Matt Sach
To add to this, see the old ECMAScript 262 specification on grammar wrt parsing numeric literals: http://bclary.com/2004/11/07/#a-7.8.3
Anonymous
Ah yes, always good to have official documentation for this sort of thing, thanks :)
Matt Sach
Yes, that's for literals. What about parsing string input?
Vilx-
Take a fixed number such as 1234.56 and run it through the `.toLocaleString()` method mentioned by jspcal. Examine the result to work out what your decimal and thousand separators are. Run all numbers displayed to the user through a function which applies those separators (see the link I gave for examples of that).
Matt Sach
+1  A: 

use:

theNumber.toLocaleString();

to get a properly formatted string with the right decimal and thousands separators

jspcal
OK. And how do I parse a string with these separators?
Vilx-
you'd need to strip out the seps, and make sure it conforms to something like: [\+\-]?([0-9]+|[0-9]*(\.([eE][\+\-]?[0-9]+))?)
jspcal
Fair enough, I can strip whatever is needed, and can replace the locale-specific separator with `.`. But is `.` the only thing that `.parseFloat()` expects?
Vilx-
See replies to Andy E's original answer (short answer: yes)
Matt Sach
yeah the spec requires decimal point dot
jspcal
A: 

Take a look into this question: With a browser, how do I know which decimal separator does the client use?

It's a clever way

Rubens Farias
Not bad. It's a step in the right direction. Now, if only I could be sure that `.parseFloat()` always expects a `.`...
Vilx-
+3  A: 

According to the specification, a DecimalLiteral is defined as:

DecimalLiteral ::
    DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt 
    . DecimalDigits ExponentPartopt 
    DecimalIntegerLiteral ExponentPartopt

and for satisfying the parseFloat argument:

  1. Let inputString be ToString(string).
  2. Let trimmedString be a substring of inputString consisting of the leftmost character that is not a StrWhiteSpaceChar and all characters to the right of that character.(In other words, remove leading white space.)
  3. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral (see 9.3.1), return NaN.
  4. Let numberString be the longest prefix of trimmedString, which might be trimmedString itself, that satisfies the syntax of a StrDecimalLiteral.
  5. Return the Number value for the MV

So numberString becomes the longest prefix of trimmedString that satisfies the syntax of a StrDecimalLiteral, meaning the first parseable literal string number it finds in the input. Only the . can be used to specify a floating-point number. If you're accepting inputs from different locales, use a string replace:

function parseLocalNum(num)
{
    return +(num.replace(",", "."));
}

The function uses the unary operator instead of parseFloat because it seems to me that you want to be strict about the input. parseFloat("1ABC") would be 1, whereas using the unary operator +"1ABC" returns NaN. This makes it MUCH easier to validate the input. Using parseFloat is just guessing that the input is in the correct format.

Andy E
That's for literals. Is `.parseFloat()` required to do the same?
Vilx-
Yes. `parseFloat("1,01")` in any locale will return `1`, not `1.01`
Andy E
Mozilla Developer Centre says: "parseFloat parses its argument, a string, and returns a floating point number. If it encounters a character other than a sign (+ or -), numeral (0-9), a decimal point, or an exponent, it returns the value up to that point and ignores that character and all succeeding characters. Leading and trailing spaces are allowed."https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/parseFloat
Matt Sach
@Vilx- parseFloat looks for the first matching DecimalLiteral in the string that is passed as the argument. Anything else will return NaN.
Andy E
Except that it conveniently doesn't define "decimal point". XD
Vilx-
Because that's already defined in the ECMAScript 262 specs for DecimalLiteral :)
Matt Sach
@Vilx- It defines a DecimalLiteral, and the DecimalLiteral defines the decimal point :)
Andy E
OK, I'll take your word for it! :)
Vilx-
@Vilx- LOL it's not my word, it's ECMA International's word!
Andy E
I'll take your word because I'm too lazy to look up the spec myself. XD Thanks! :)
Vilx-
lol fair enough :-)
Andy E