if input.is_empty() || input == "." {
return Ok(Value::sysmis());
}
- fn strip_prefix<'a>(input: &'a str, prefix: &str) -> (bool, &'a str) {
- if prefix.is_empty() {
- (false, input)
- } else if let Some(rest) = input.strip_prefix(prefix) {
- (true, rest.trim_start())
- } else {
- (false, input)
- }
- }
- fn strip_one_of<'a>(input: &'a str, chars: &[char]) -> (Option<char>, &'a str) {
- let mut iter = input.chars();
- match iter.next() {
- Some(c) if chars.contains(&c) => (Some(c), iter.as_str().trim_start()),
- _ => (None, input),
- }
- }
+ let mut p = StrParser::new(input.trim());
fn strip_integer(mut input: &str, grouping: Option<char>) -> &str {
while let Some(rest) = input.strip_prefix(|c: char| c.is_ascii_digit()) {
let rest = if let Some(grouping) = grouping {
input
}
- let (_, input) = strip_prefix(input, &*style.prefix.s);
- let (sign, input) = strip_one_of(input, &['-', '+']);
- let input = if sign.is_some() {
- strip_prefix(input, &*style.prefix.s).1
- } else {
- input
- };
- let (integer, input) = take(input, strip_integer(input, style.grouping.map(char::from)));
- let (decimals, input) = if let Some(rest) = input.strip_prefix(style.decimal.as_str()) {
- take(rest, rest.trim_start_matches(|c: char| c.is_ascii_digit()))
+ if p.strip_prefix(&*style.prefix.s) {
+ p.strip_ws();
+ }
+ let sign = p.strip_one_of(&['-', '+']).inspect(|_| p.strip_ws());
+ if sign.is_some() && p.strip_prefix(&*style.prefix.s) {
+ p.strip_ws();
+ }
+ let integer = p.advance(strip_integer(p.0, style.grouping.map(char::from)));
+ let decimals = if p.strip_prefix(style.decimal.as_str()) {
+ p.strip_matches(|c| c.is_ascii_digit())
} else {
- ("", input)
+ ""
};
- let (exp_sign, exponent, input) = if input.starts_with(['e', 'E', 'd', 'D', '+', '-']) {
- let (_e, rest) = strip_one_of(input, &['e', 'E', 'd', 'D']);
- let (exp_sign, rest) = strip_one_of(rest, &['-', '+']);
- let (exponent, rest) =
- take(rest, rest.trim_start_matches(|c: char| c.is_ascii_digit()));
- (exp_sign, exponent, rest)
+ let (exp_sign, exponent) = if p.0.starts_with(['e', 'E', 'd', 'D', '+', '-']) {
+ let _e = p
+ .strip_one_of(&['e', 'E', 'd', 'D'])
+ .inspect(|_| p.strip_ws());
+ let exp_sign = p.strip_one_of(&['-', '+']).inspect(|_| p.strip_ws());
+ let exponent = p.strip_matches(|c| c.is_ascii_digit());
+ (exp_sign, exponent)
} else {
- (None, "", input)
+ (None, "")
};
- let (_, input) = strip_prefix(input, &*style.suffix.s);
+ if p.strip_prefix(&*style.suffix.s) {
+ p.strip_ws();
+ }
- if !input.is_empty() {
+ if !p.0.is_empty() {
return Err(ParseErrorKind::NotNumeric);
}
}
write!(&mut number, "{exponent}").unwrap();
}
+ println!("{number}");
match f64::from_str(&number) {
Ok(value) => Ok(Value::Number(Some(value))),
}
}
+#[derive(Copy, Clone, Debug)]
+pub struct StrParser<'a>(pub &'a str);
+
+impl<'a> StrParser<'a> {
+ pub fn new(s: &'a str) -> Self {
+ Self(s)
+ }
+
+ pub fn strip_prefix(&mut self, prefix: &'a str) -> bool {
+ if prefix.is_empty() {
+ false
+ } else if let Some(rest) = self.0.strip_prefix(prefix) {
+ self.0 = rest;
+ true
+ } else {
+ false
+ }
+ }
+
+ fn strip_one_of(&mut self, chars: &[char]) -> Option<char> {
+ let mut iter = self.0.chars();
+ match iter.next() {
+ Some(c) if chars.contains(&c) => {
+ self.0 = iter.as_str();
+ Some(c)
+ }
+ _ => None,
+ }
+ }
+
+ fn strip_matches(&mut self, f: impl Fn(char) -> bool) -> &'a str {
+ self.advance(self.0.trim_start_matches(f))
+ }
+
+ fn strip_ws(&mut self) {
+ self.0 = self.0.trim_start();
+ }
+
+ fn advance(&mut self, rest: &'a str) -> &'a str {
+ let head = &self.0[..self.0.len() - rest.len()];
+ self.0 = rest;
+ head
+ }
+}
+
#[cfg(test)]
mod test {
use std::{