Allows for arbitrary spacing between operands when parsing Complex

This commit is contained in:
Alan Liddell 2017-07-13 14:05:44 -04:00
parent e5e8266009
commit ac746c2a5d
1 changed files with 73 additions and 38 deletions

View File

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