首页 > 解决方案 > 以 nom 解析一个数字

问题描述

我正在尝试使用 nom5 传递一些锌格式 https://www.project-haystack.org/doc/Zinc

数字格式可以像以下任何一种格式

1、-34、10_000、5.4e-45、-5.4e-45、9.23kg、74.2°F、4 分钟、INF、-INF、NaN

我相信如果指定,单位可以是任何单位。

我有一些简单数字传递的例子,比如 Parsing number with nom 5.0

fn number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
    map(
        tuple((
            opt(char('-')),
            many1(digit1),
            opt(preceded(char('.'), many1(digit1)))
        )),
        |s| Token::Number(s)
    )(i)
}

但我不确定如何处理这些值,这些值也可能是 INF 或 -INF、NaN 以及可能添加的单位。

我将如何处理这个案子?

谢谢

标签: rustnom

解决方案


最后我把它建成了

fn simple_number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {

    map(
        recognize(tuple( (opt(alt((char('-'), char('+')))), many1(digit1), opt(preceded(char('.'), many1(digit1)))) ) ),
        |s: &str| Token::Number(s.parse::<f64>().unwrap(), "".into())
        //|s: &str| Token::Var(s.into())
    )(i)
}

fn exponent<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
    map(
        recognize(tuple(  ( alt((char('e'), char('E'))), simple_number  )) ),
        |s: &str| Token::Var(s.into())
    )(i)
}

fn number<'a>(i: &'a str) -> IResult<&'a str, f64, (&'a str, ErrorKind)> {
    map(
        recognize(tuple((simple_number, opt(exponent))) ),
        |s: &str| s.parse::<f64>().unwrap()
    )(i)
}

fn units<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
    alphanumeric1(i)
}

fn number_with_unit<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
    map(
        tuple((number, opt(units))),
        |t: (f64, Option<&str>)| Token::Number(t.0, t.1.unwrap_or(&"".to_string()).into())
    )(i)
}

// Number: 1, -34, 5.4, -5.4, 9.23, 74.2, 4, 5.4e-45, -5.4e-45, 67.3E7 INF -INF +INF NAN
fn zinc_number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {

    alt( (number_with_unit, inf, nan) ) (i)
}

推荐阅读