Javascript解析浮点数忽略了逗号后面的小数

Javascript parse float is ignoring the decimals after my comma

本文关键字:小数 浮点数 Javascript      更新时间:2023-09-26

下面是一个简单的场景。我想在我的网站上显示两个值的减法:

//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
谁能告诉我我做错了什么?

这是"By Design"。parseFloat函数将只考虑字符串的部分,直到它达到非+、-、数字、指数或小数点。一旦它看到逗号,它就停止查找,只考虑"75"部分。

  • https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseFloat

要解决此问题,请将逗号转换为小数点。

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

javascript的parseFloat不接受locale参数。所以你必须将,替换为.

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

为什么不用globalize呢?当你不使用英语时,这只是你可能遇到的问题之一:

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

关于stackoverflow的一些链接:

    Jquery全球化
  • JQuery的全球化不工作

parseFloat根据十进制文字的JavaScript定义进行解析,而不是根据您的语言环境定义。(例如,parseFloat不是区域感知的。)JavaScript中的十进制文字使用.作为小数点

正如@JaredPar在他的回答中指出的,使用 parseFloat 代替

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

只是用dot替换comma将修复,除非它是像1.000.000,00这样的数千个数字,否则会给你错误的数字。所以你需要替换comma,移除dots

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

通过使用两个替换,您将能够处理数据而不会在输出中接收到错误的数字。

对于任何到达这里想知道如何处理这个问题的逗号(,)和句号(.)可能涉及,但确切的数字格式可能不知道-这就是我如何在使用parseFloat()之前纠正字符串(借用其他答案的想法):

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

至少,这将允许解析英国/美国和欧洲的十进制格式(假设字符串包含有效数字)。

在一百万1,234,567

的情况下,最好使用这种语法替换所有的逗号。
var string = "1,234,567";
string = string.replace(/[^'d'.'-]/g, ""); 
var number = parseFloat(string);
console.log(number)

g表示删除所有逗号。

JS中的数字使用.(句号/句号)字符来表示小数点,而不是,(逗号)。

您的错误之处在于为parseFloat()提供以面向人的记数法表示十进制分数的字符串,而parseFloat()只接受与JavaScript数字字量对应的标准格式,这些格式与地区无关,始终使用点作为小数分隔符,并且没有千位分隔符。

此外,这个用于所有答案的parseFloat()函数在接受正确输入方面过于慷慨,在大多数情况下阻止了对错误输入的检测:

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

为了获得更严格的、更好控制的行为,我建议您实现自己的解析函数。这是我的:

// 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 ];
}

和一个使用parse_float()来解析格式数字的测试程序:

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'     );

它写道:

          [] => 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

在我的情况下,我已经有了一个句号(.)和一个逗号(,),所以对我来说有效的是replace逗号(,)和一个空字符串,如下所示:

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

假设来自现有数据库的数量为3,000.78。结果为:3000.78,不包含初始逗号(,)