From d5cb9b6630028c3d770a9969abfec94ed0f38b45 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 28 Oct 2011 16:01:10 -0700 Subject: [PATCH 1/2] Make float::from_str ignore whitespace (#1089) Discard leading and trailing whitespace, for consistency with C/JS/Java/etc. Also, don't allow floating point numbers that start or end with 'e'. --- src/lib/float.rs | 24 +++++++++++++++++++++--- src/test/stdtest/float.rs | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/lib/float.rs b/src/lib/float.rs index c7053486ccb5a..e37b9f386b14e 100644 --- a/src/lib/float.rs +++ b/src/lib/float.rs @@ -48,6 +48,8 @@ This function accepts strings such as * "5." * ".5", or, equivalently, "0.5" +Leading and trailing whitespace are ignored. + Parameters: num - A string, possibly empty. @@ -58,6 +60,8 @@ Returns: Otherwise, the floating-point number represented [num]. */ fn from_str(num: str) -> float { + num = str::trim(num); + let pos = 0u; //Current byte position in the string. //Used to walk the string in O(n). let len = str::byte_len(num); //Length of the string, in bytes. @@ -66,6 +70,12 @@ fn from_str(num: str) -> float { let total = 0f; //Accumulated result let c = 'z'; //Latest char. + //The string must start with one of the following characters. + alt str::char_at(num, 0u) { + '-' | '+' | '0' to '9' | '.' {} + _ { ret NaN(); } + } + //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly. let neg = false; //Sign of the result alt str::char_at(num, 0u) { @@ -89,9 +99,12 @@ fn from_str(num: str) -> float { total = total * 10f; total += ((c as int) - ('0' as int)) as float; } - _ { + '.' | 'e' | 'E' { break; } + _ { + ret NaN(); + } } } @@ -106,9 +119,12 @@ fn from_str(num: str) -> float { decimal /= 10.f; total += (((c as int) - ('0' as int)) as float)*decimal; } - _ { + 'e' | 'E' { break; } + _ { + ret NaN(); + } } } } @@ -132,7 +148,6 @@ fn from_str(num: str) -> float { while(pos < len) { let char_range = str::char_range_at(num, pos); c = char_range.ch; - pos = char_range.next; alt c { '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' { exponent *= 10u; @@ -142,6 +157,7 @@ fn from_str(num: str) -> float { break; } } + pos = char_range.next; } let multiplier = pow_uint_to_uint_as_float(10u, exponent); //Note: not [int::pow], otherwise, we'll quickly @@ -151,6 +167,8 @@ fn from_str(num: str) -> float { } else { total = total * multiplier; } + } else { + ret NaN(); } } diff --git a/src/test/stdtest/float.rs b/src/test/stdtest/float.rs index d9de78b60090a..04e16648b7d16 100644 --- a/src/test/stdtest/float.rs +++ b/src/test/stdtest/float.rs @@ -3,6 +3,8 @@ import std::float; #[test] fn test_from_str() { + assert ( float::from_str("3") == 3. ); + assert ( float::from_str(" 3 ") == 3. ); assert ( float::from_str("3.14") == 3.14 ); assert ( float::from_str("+3.14") == 3.14 ); assert ( float::from_str("-3.14") == -3.14 ); @@ -10,11 +12,30 @@ fn test_from_str() { assert ( float::from_str("2.5e10") == 25000000000. ); assert ( float::from_str("25000000000.E-10") == 2.5 ); assert ( float::from_str("") == 0. ); - assert ( float::isNaN(float::from_str(" ")) ); assert ( float::from_str(".") == 0. ); + assert ( float::from_str(".e1") == 0. ); + assert ( float::from_str(".e-1") == 0. ); assert ( float::from_str("5.") == 5. ); assert ( float::from_str(".5") == 0.5 ); assert ( float::from_str("0.5") == 0.5 ); + assert ( float::from_str("0.5 ") == 0.5 ); + assert ( float::from_str(" 0.5 ") == 0.5 ); + assert ( float::from_str(" -.5 ") == -0.5 ); + assert ( float::from_str(" -.5 ") == -0.5 ); + assert ( float::from_str(" -5 ") == -5. ); + + assert ( float::isNaN(float::from_str("x")) ); + assert ( float::from_str(" ") == 0. ); + assert ( float::from_str(" ") == 0. ); + assert ( float::from_str(" 0.5") == 0.5 ); + assert ( float::from_str(" 0.5 ") == 0.5 ); + assert ( float::from_str(" .1 ") == 0.1 ); + assert ( float::isNaN(float::from_str("e")) ); + assert ( float::isNaN(float::from_str("E")) ); + assert ( float::isNaN(float::from_str("E1")) ); + assert ( float::isNaN(float::from_str("1e1e1")) ); + assert ( float::isNaN(float::from_str("1e1.1")) ); + assert ( float::isNaN(float::from_str("1e1-1")) ); } #[test] From 4320d06ce23f38b31ef0ed3b0965b4327077a072 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Sun, 30 Oct 2011 07:29:15 -0700 Subject: [PATCH 2/2] Fix int::parse_buf for negative numbers (#1102) --- src/lib/int.rs | 6 ++++-- src/test/stdtest/int.rs | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/lib/int.rs b/src/lib/int.rs index e0c0a97f0ba02..41d166fe3fc14 100644 --- a/src/lib/int.rs +++ b/src/lib/int.rs @@ -103,16 +103,18 @@ fn parse_buf(buf: [u8], radix: uint) -> int { fail; } let i = vec::len::(buf) - 1u; + let start = 0u; let power = 1; + if buf[0] == ('-' as u8) { power = -1; - i -= 1u; + start = 1u; } let n = 0; while true { n += (buf[i] - ('0' as u8) as int) * power; power *= radix as int; - if i == 0u { ret n; } + if i <= start { ret n; } i -= 1u; } fail; diff --git a/src/test/stdtest/int.rs b/src/test/stdtest/int.rs index 4a87908e5a64f..282e16daf08a0 100644 --- a/src/test/stdtest/int.rs +++ b/src/test/stdtest/int.rs @@ -3,6 +3,21 @@ use std; import std::int; import std::str::eq; +#[test] +fn test_from_str() { + assert(int::from_str("0") == 0); + assert(int::from_str("3") == 3); + assert(int::from_str("10") == 10); + assert(int::from_str("123456789") == 123456789); + assert(int::from_str("00100") == 100); + + assert(int::from_str("-1") == -1); + assert(int::from_str("-3") == -3); + assert(int::from_str("-10") == -10); + assert(int::from_str("-123456789") == -123456789); + assert(int::from_str("-00100") == -100); +} + #[test] fn test_to_str() { assert (eq(int::to_str(0, 10u), "0")); @@ -29,4 +44,4 @@ fn test_overflows() { assert (int::max_value() > 0); assert (int::min_value() <= 0); assert (int::min_value() + int::max_value() + 1 == 0); -} \ No newline at end of file +}