你做错的是parseFloat()
用面向人类的符号表示小数部分的字符串,而只接受与JavaScriptparseFloat()
数字文字相对应的标准格式,这些文字与区域无关,始终使用点作为小数分隔符,并且没有千位分隔符。
此外,在所有答案中都使用了这个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