Kaynağa Gözat

Allows for arbitrary spacing between operands when parsing Complex

Alan Liddell 7 yıl önce
ebeveyn
işleme
ac746c2a5d
1 değiştirilmiş dosya ile 75 ekleme ve 40 silme
  1. 75 40
      complex/src/lib.rs

+ 75 - 40
complex/src/lib.rs

@@ -750,42 +750,64 @@ impl<T> FromStr for Complex<T> where
     /// Parses `a +/- bi`; `ai +/- b`; `a`; or `bi` where `a` and `b` are of type `T`
     fn from_str(s: &str) -> Result<Complex<T>, ParseComplexError>
     {
-        // first try to split on " + "
-        let mut split_p = s.splitn(2, " + ");
-
-        let mut a = match split_p.next() {
-            None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
-            Some(s) => s.trim_right().to_string()
-        };
-
-        let mut b = match split_p.next() {
-            // no second item could mean we need to split on " - " instead
-            None => {
-                let mut split_m = s.splitn(2, " - ");
-
-                a = match split_m.next() {
-                    None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
-                    Some(s) => s.trim_right().to_string()
-                };
-
-                let c = match split_m.next() {
-                    None => {
-                        // if `a` is imaginary, let `b` be real (and vice versa)
-                        match a.rfind('i') {
-                            None => "0i".to_string(),
-                            _ => "0".to_string()
+        let imag = 'i';
+
+        let mut a = String::with_capacity(s.len());
+        let mut b = String::with_capacity(s.len());
+
+        let mut first = true;
+        let mut char_indices = s.char_indices();
+        let mut pc = ' ';
+
+        loop {
+            match char_indices.next() {
+                Some(t) => {
+                    let i = t.0;
+                    let cc = t.1;
+                    if cc == '+' {
+                        // handle exponents
+                        if pc != 'e' && pc != 'E' {
+                            first = false;
+                            // don't carry '+' over into b
+                            pc = ' ';
+                            continue;
+                        }
+                    } else if cc == '-' {
+                        // handle exponents and negative numbers
+                        if i > 0 && pc != 'e' && pc != 'E' {
+                            first = false;
+                            // DO carry '-' over into b
                         }
                     }
-                    Some(s) => {
-                        "-".to_string() + s.trim_left()
+
+                    if !first && cc == ' ' && pc == '-' {
+                        // ignore whitespace between minus sign and next number
+                        continue;
+                    }
+
+                    if first {
+                        a.push(cc);
+                    } else {
+                        b.push(cc);
                     }
-                };
-                c
-            },
-            Some(s) => s.trim_left().to_string()
-        };
 
-        let re = match a.rfind('i') {
+                    pc = cc;
+                },
+                None => break,
+            }
+        }
+
+        a = a.trim_right().to_string();
+        b = b.trim_left().to_string();
+
+        if b.is_empty() {
+            b = match a.rfind(imag) {
+                None => "0i".to_string(),
+                _ => "0".to_string()
+            };
+        }
+
+        let re = match a.rfind(imag) {
             None => {
                 try!(T::from_str(&a)
                     .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
@@ -796,20 +818,20 @@ impl<T> FromStr for Complex<T> where
             }
         };
 
-        let im = match a.rfind('i') {
+        let im = match a.rfind(imag) {
             None => {
                 // a is real
                 match b.pop() {
                     // b was empty
                     None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
                     Some(c) => {
-                        if c == 'i' {
+                        if c == imag {
                             // b is imaginary
                             if b.is_empty() {
-                                // b was just 'i'
+                                // b was just 'imag'
                                 b = "1".to_string();
                             } else if b == "-" {
-                                // b was just '-i'
+                                // b was just '-imag'
                                 b = "-1".to_string();
                             }
                         } else {
@@ -823,17 +845,17 @@ impl<T> FromStr for Complex<T> where
                     .map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
             },
             _ => {
-                // a contains an 'i'
+                // a contains imag
                 match a.pop() {
                     None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
                     Some(c) => {
-                        if c == 'i' {
+                        if c == imag {
                             // a is imaginary
                             if a.is_empty() {
-                                // a was just 'i'
+                                // a was just 'imag'
                                 a = "1".to_string();
                             } else if a == "-" {
-                                // a was just '-i'
+                                // a was just '-imag'
                                 a = "-1".to_string();
                             }
                         } else {
@@ -1553,25 +1575,38 @@ mod test {
         test(_0_0i, "-0".to_string());
         test(_0_0i, "-0i".to_string());
         test(_0_0i, "0 + 0i".to_string());
+        test(_0_0i, "0+0i".to_string());
         test(_0_0i, "0 - 0i".to_string());
+        test(_0_0i, "0-0i".to_string());
 
         test(_1_0i, "1".to_string());
         test(_1_0i, "1 + 0i".to_string());
+        test(_1_0i, "1+0i".to_string());
         test(_1_0i, "1 - 0i".to_string());
+        test(_1_0i, "1-0i".to_string());
 
         test(_1_1i, "1 + i".to_string());
+        test(_1_1i, "1+i".to_string());
         test(_1_1i, "1 + 1i".to_string());
+        test(_1_1i, "1+1i".to_string());
 
         test(_0_1i, "i".to_string());
         test(_0_1i, "1i".to_string());
         test(_0_1i, "0 + i".to_string());
+        test(_0_1i, "0+i".to_string());
         test(_0_1i, "-0 + i".to_string());
+        test(_0_1i, "-0+i".to_string());
         test(_0_1i, "0 + 1i".to_string());
+        test(_0_1i, "0+1i".to_string());
         test(_0_1i, "-0 + 1i".to_string());
+        test(_0_1i, "-0+1i".to_string());
 
         test(_neg1_1i, "-1 + i".to_string());
+        test(_neg1_1i, "-1+i".to_string());
         test(_neg1_1i, "-1 + 1i".to_string());
+        test(_neg1_1i, "-1+1i".to_string());
 
         test(_05_05i, "0.5 + 0.5i".to_string());
+        test(_05_05i, "0.5+0.5i".to_string());
     }
 }