strconv: fix strconv.atof64() inconsistency with the other .ato functions; make it return an error by default, when it detects an extra non number character after a number (#23815)

This commit is contained in:
kbkpbot 2025-02-27 14:31:59 +08:00 committed by GitHub
parent 62cbc8befe
commit 675fe14cbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 4 deletions

View File

@ -636,13 +636,13 @@ pub fn (s string) i64() i64 {
// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`.
@[inline]
pub fn (s string) f32() f32 {
return f32(strconv.atof64(s) or { 0 })
return f32(strconv.atof64(s, allow_extra_chars: true) or { 0 })
}
// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`.
@[inline]
pub fn (s string) f64() f64 {
return strconv.atof64(s) or { 0 }
return strconv.atof64(s, allow_extra_chars: true) or { 0 }
}
// u8_array returns the value of the hex/bin string as u8 array.

View File

@ -114,6 +114,7 @@ enum ParserState {
pinf // number is higher than +HUGE_VAL
minf // number is lower than -HUGE_VAL
invalid_number // invalid number, used for '#@%^' for example
extra_char // extra char after number
}
// parser tries to parse the given string into a number
@ -218,6 +219,9 @@ fn parser(s string) (ParserState, PrepNumber) {
if i == 0 && s.len > 0 {
return ParserState.invalid_number, pn
}
if i != s.len {
return ParserState.extra_char, pn
}
return result, pn
}
@ -387,13 +391,19 @@ fn converter(mut pn PrepNumber) u64 {
return result
}
@[params]
pub struct AtoF64Param {
pub:
allow_extra_chars bool // allow extra characters after number
}
// atof64 parses the string `s`, and if possible, converts it into a f64 number
pub fn atof64(s string) !f64 {
pub fn atof64(s string, param AtoF64Param) !f64 {
if s.len == 0 {
return error('expected a number found an empty string')
}
mut res := Float64u{}
mut res_parsing, mut pn := parser(s)
res_parsing, mut pn := parser(s)
match res_parsing {
.ok {
res.u = converter(mut pn)
@ -410,6 +420,13 @@ pub fn atof64(s string) !f64 {
.minf {
res.u = double_minus_infinity
}
.extra_char {
if param.allow_extra_chars {
res.u = converter(mut pn)
} else {
return error('extra char after number')
}
}
.invalid_number {
return error('not a number')
}

View File

@ -20,6 +20,9 @@ fn test_atof() {
0.0,
-0.0,
31234567890123,
0.01,
2000,
-300,
]
// strings
@ -31,6 +34,9 @@ fn test_atof() {
'0.0',
'-0.0',
'31234567890123',
'1e-2',
'+2e+3',
'-3.0e+2',
]
// check conversion case 1 string <=> string
@ -89,4 +95,16 @@ fn test_atof_errors() {
} else {
assert err.str() == 'not a number'
}
if x := strconv.atof64('uu577.01') {
eprintln('> x: ${x}')
assert false // strconv.atof64 should have failed
} else {
assert err.str() == 'not a number'
}
if x := strconv.atof64('123.33xyz') {
eprintln('> x: ${x}')
assert false // strconv.atof64 should have failed
} else {
assert err.str() == 'extra char after number'
}
}