111

Here's a simple scenario. I want to show the subtraction of two values show on my site:

//Value on my websites HTML is: "75,00"
var fullcost = parseFloat($("#fullcost").text()); 

//Value on my websites HTML is: "0,03"
var auctioncost = parseFloat($("#auctioncost").text());

alert(fullcost); //Outputs: 75
alert(auctioncost); //Ouputs: 0

Can anyone tell me what I'm doing wrong?

Only Bolivian Here
  • 35,719
  • 63
  • 161
  • 257

10 Answers10

204

This is "By Design". The parseFloat function will only consider the parts of the string up until in reaches a non +, -, number, exponent or decimal point. Once it sees the comma it stops looking and only considers the "75" portion.

To fix this convert the commas to decimal points.

var fullcost = parseFloat($("#fullcost").text().replace(',', '.'));
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 9
    Will this work in all regions? Isn`t using comma depending on your regional settings in OS? – Dusan Plavak Mar 13 '15 at 10:12
  • 26
    The code above will only remove the first ','. What if the number is 700,000,000? You need: .replace(/,/g, '') – hyankov Jul 09 '15 at 06:17
  • 23
    I think most people are forgetting that comma can be used as a thousand separator as well and not just as a decimal separator. – Peter Raeves May 12 '16 at 09:23
  • 4
    Hello there, what if input is `5.200,75` which means five thousand two hundred and point seventy five. – hasan05 Jun 19 '19 at 11:37
  • 1
    This answer will only work in the current scenario, and if for example, the number is 15,000 then that will show 15, which is incorrect! – itsHarshad Oct 07 '20 at 07:07
  • I join the others' criricism and insist that the fine, fast, and reliable soltuion is to parse the required format manually and diretly, as I do in my answer. – Anton Shepelev Jul 10 '21 at 15:02
41

javascript's parseFloat doesn't take a locale parameter. So you will have to replace , with .

parseFloat('0,04'.replace(/,/, '.')); // 0.04
Joe
  • 80,724
  • 18
  • 127
  • 145
  • 26
    What if the number is 7,000,000.15? – Peter Raeves May 12 '16 at 09:22
  • 9
    You are in charge of conforming your strings to look like a float, when trying to parse them. If your locale uses periods for decimal points, then you can safely strip all commas (thousands separators) before trying to parse it to a float. If your locale uses commas instead of periods for decimal points, you can safely remove any periods (thousands separators) and then change the comma (decimal point) to a period. – Ultroman the Tacoman May 03 '17 at 10:18
24

Why not use globalize? This is only one of the issues that you can run in to when you don't use the english language:

Globalize.parseFloat('0,04'); // 0.04

Some links on stackoverflow to look into:

Community
  • 1
  • 1
jamie
  • 819
  • 10
  • 5
21

parseFloat parses according to the JavaScript definition of a decimal literal, not your locale's definition. (E.g., parseFloat is not locale-aware.) Decimal literals in JavaScript use . for the decimal point.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
17

As @JaredPar pointed out in his answer use parseFloat with replace

var fullcost = parseFloat($("#fullcost").text().replace(',', '.'));

Just replacing the comma with a dot will fix, Unless it's a number over the thousands like 1.000.000,00 this way will give you the wrong digit. So you need to replace the comma remove the dots.

// Remove all dot's. Replace the comma.
var fullcost = parseFloat($("#fullcost").text().replace(/\./g,'').replace(',', '.'));

By using two replaces you'll be able to deal with the data without receiving wrong digits in the output.

Community
  • 1
  • 1
Michel Ayres
  • 5,891
  • 10
  • 63
  • 97
12

For anyone arriving here wondering how to deal with this problem where commas (,) and full stops (.) might be involved but the exact number format may not be known - this is how I correct a string before using parseFloat() (borrowing ideas from other answers):

function preformatFloat(float){
   if(!float){
      return '';
   };

   //Index of first comma
   const posC = float.indexOf(',');

   if(posC === -1){
      //No commas found, treat as float
      return float;
   };

   //Index of first full stop
   const posFS = float.indexOf('.');

   if(posFS === -1){
      //Uses commas and not full stops - swap them (e.g. 1,23 --> 1.23)
      return float.replace(/\,/g, '.');
   };

   //Uses both commas and full stops - ensure correct order and remove 1000s separators
   return ((posC < posFS) ? (float.replace(/\,/g,'')) : (float.replace(/\./g,'').replace(',', '.')));
};
// <-- parseFloat(preformatFloat('5.200,75'))
// --> 5200.75

At the very least, this would allow parsing of British/American and European decimal formats (assuming the string contains a valid number).

sbgib
  • 5,580
  • 3
  • 19
  • 26
  • It works great for both formats `1,234.56` and `1.234,56` – joseantgv May 06 '20 at 11:33
  • Exactly! It's more complicated than the other answers, but it's the best way to interpret numbers if you don't know which format the user will use (which is common in Europe). – Sygmoral Oct 04 '21 at 12:01
  • What is this number? "1,234"? One thousand two hundred and thirty-four point zero? Or One point two three four? The above function assumes the latter. It is still vague if there is one and not the other. One can only know for sure if both are used or if one is used more than once. – Yrag00 Aug 19 '22 at 15:47
7

It is better to use this syntax to replace all the commas in a case of a million 1,234,567

var string = "1,234,567";
string = string.replace(/[^\d\.\-]/g, ""); 
var number = parseFloat(string);
console.log(number)

The g means to remove all commas.

Check the Jsfiddle demo here.

mustapha mekhatria
  • 3,495
  • 1
  • 20
  • 26
  • 1
    Eh, no. That is seriously buggy by design. What if you are parsing a number from the 50% of the world that is using comma as a decimal separator - as the author of the answer did? Parsing `1,753123` should give you a number approx. like `1.75`, but you will end up with an answer that is one million times off. – oligofren Feb 11 '21 at 11:12
  • 2
    thx for the info. It is a solution as any other solution (nothing is perfect). You are welcome to add your contribution But please no need for the Eh no , and the downvoting. We are here to learn and to help each other – mustapha mekhatria Feb 19 '21 at 12:26
6

Numbers in JS use a . (full stop / period) character to indicate the decimal point not a , (comma).

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
1

What you do wrong is feed parseFloat() with strings that represent decimal fractions in a human-oriented notation, whereas parseFloat() accepts only the standard format corresponding with the JavaScript number literals, which are region-independent, always use the dot as the decimal separator, and have no thousands separator.

Futhermore, this parseFloat() function, used in all the answers, is too generous in what it accepts as correct input, preventing the detection of what in most cases is incorrect input:

Input      Result
'1Hello'   1
'1 and 2'  1
'1.2+3.4'  1.2
' 25  '    25

In order to get a stricter and therefore better-controlled behavior, I recommend that you implement your own parsing function. Here is mine:

// Parse a decimal fraction with specified thousands
// and group separators:
function /* number */ parse_float
(   /* string */ s      , // string to parse
    /* string */ thousep, // thousands separator, empty string if none
    /* string */ decsep   // decimal separator  , empty string if none
)
{   var /* integer */ whole, frac ; // whole and fractinal parts
    var /* integer */ wnext, fnext; // position of next char after parse
    var /* integer */ fraclen     ; // length of fractional part
    var /* integer */ ofs         ; // offset of the first digit
    var /* boolean */ done        ; // entire string scanned?
    var /* integer */ sign        ; // sign of result
    var /* number  */ res         ; // result
        /* labels  */ end: { whole: {

    // Check parameter types and availability:
    req_param( 's'      , s      , 'string' );
    req_param( 'thousep', thousep, 'string' );
    req_param( 'decsep' , decsep , 'string' );
    
    frac    = 0;
    fraclen = 0;
    res     = NaN;
    // Account for a possible sign:
    switch( s.charAt(0) )
    {   case '-': sign = -1; ofs = 1; break;
        case '+': sign = +1; ofs = 1; break;
        default : sign = +1; ofs = 0; break;
    }

    [done, wnext, whole] = parse_int_ts( s, ofs, thousep );
    if( isNaN( whole )               )           break end;
    if( done                         )           break whole;
    if( s.charAt( wnext ) !== decsep )           break end; 
    
    [done, fnext, frac] = parse_int( s, 0, wnext + 1 );
    if( !done                        )           break end;

    fraclen = fnext - wnext - 1;
    if( fraclen === 0                )           break end;

    } /* whole: */ res = ( whole + frac / Math.pow( 10, fraclen ) ) * sign;
    } /* end:   */ return res;
}

// Require that a value be specified and have the expected type:
function req_param( /* string */ param, /* variant */ val, /* string */ type )
{   var /* string */ errmsg;

    errmsg = ''; if( val === undefined   ) errmsg = 'is undefined';
    else         if( val === null        ) errmsg = 'is null';
    else         if( typeof val !== type ) errmsg = `must of type \`${type}'`;

    if( errmsg !== '' ) // there has been an error
    {   throw new Error(`Parameter \`${param}' ${errmsg}.`);  }
}

// Parse an integer with a specified thousands separator:
function /* object[] */ parse_int_ts
(   /* string    */ s    , // input string
    /* integer   */ start, // start position
    /* character */ sep  , // thousands separator
)
// Returns an array of:
//   0: boolean -- entire string was scanned
//   1: integer -- index of next character to scan
//   2: integer -- resulting inteer 
{   var /* boolean */ full;
    var /* integer */ next;
    var /* integer */ res;
    var /* integer */ len;
    var /* integer */ psep;
    var /* integer */ result;
    
    res     = 0;
    psep    = 0;
    while( true )
    {   result = NaN; // mark an error
        [full, next, res] = parse_int( s, res, start );
        len = next - start;
        if( len === 0  )                 break; // nothing parsed
        if( sep !== '' )
        {   if( psep  >  0 && len !== 3 ) break; // non-first group not 3 digits
            if( psep === 0 && len  >  3 ) break; // first group longer than 3 digits
        }
        result = res; // mark success
        if( s.charAt(next) !== sep )     break;
        if(  full   )                    break;
        start = next;
        psep  = next;
        start = start + 1;
    }
    return [full, next, result];
}

// Parse a compact of digits beginning at position `start' 
// in string `s' as an integer number:
function /* object[]*/ parse_int
(   /* string  */ s   , // input string
    /* integer */ init, // initial value
    /* integer */ start // start position in `s'
)
// Returns an array of:
// 0: boolean -- entire string was scanned
// 1: integer -- index of next character to scan
// 2: integer -- result
{   const /* integer */ ASCII_0 = 48;

    var /* boolean   */ full; // \
    var /* integer   */ next; //  > the return value
    var /* integer   */ res ; // /
    var /* integer   */ n, i; // string length and current position
    var /* integer   */ code; // character code

    n    = s.length;
    full = true;
    next = n;
    res  = init;
    for( i = start; i < n; i += 1 )
    {   code = s.charCodeAt(i);
        if( code < ASCII_0 || code >= ASCII_0 + 10 )
        {   next = i;
            full = false;
            break;
        }
        res = res * 10 + code - ASCII_0;
    }
    if( code === undefined ) res = NaN;
    return [ full, next, res ];
}

And a test program that uses parse_float() to parse numbers of your format:

function test( /* string */ s )
{   var res;
    res = parse_float( s, ' ', ',' );
    console.log(`${('            ' + `[${s}]`).slice(-12)} => ${res}`);
}

test( ''           );
test( '12'         );
test( '12a'        );
test( '12,'        );
test( '12,345'     );
test( '12 345'     );
test( '123 45'     );
test( '1 234 567'  );
test( '12 345 56'  );
test( '12345'      );
test( '12 435,678' );
test( '+1,2'       );
test( '-2 345'     );

It writes:

          [] => NaN
        [12] => 12
       [12a] => NaN
       [12,] => NaN
    [12,345] => 12.345
    [12 345] => 12345
    [123 45] => NaN
 [1 234 567] => 1234567
 [12 345 56] => NaN
     [12345] => NaN
[12 435,678] => 12435.678
      [+1,2] => 1.2
    [-2 345] => -2345
Anton Shepelev
  • 922
  • 9
  • 19
-1

In my case, I already had a period(.) and also a comma(,), so what worked for me was to replace the comma(,) with an empty string like below:

parseFloat('3,000.78'.replace(',', '')) 

This is assuming that the amount from the existing database is 3,000.78. The results are: 3000.78 without the initial comma(,).

Zack
  • 472
  • 7
  • 16