From 8c51d4b002b2743fd50bc715429265aaaf482762 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 28 Oct 2011 16:01:10 -0700 Subject: [PATCH] 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 c7053486ccb..e37b9f386b1 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 d9de78b6009..04e16648b7d 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]