【问题标题】:Parse hex and decimal number解析十六进制和十进制数
【发布时间】:2022-11-16 13:33:17
【问题描述】:

刚开始使用 crate nom。尝试了最简单的例子:

use nom::{
    bytes::complete::tag,
    character::complete::{hex_digit1, space0},
    combinator::{map, opt},
    error::Error,
    sequence::{delimited, pair},
    IResult,
};

#[derive(Debug, PartialEq)]
pub enum Expression {
    Number(u16),
}

fn evaluate_number(prefix: Option<&str>, input: &str) -> Expression {
    println!("### evaluate_number input = {}", &input,);
    let num = match prefix {
        Some(_) => u16::from_str_radix(input, 16), // TODO: convert negative number => u16!!!
        None => u16::from_str_radix(input, 10),
    };
    Expression::Number(num.unwrap())
}

fn hex_digit_with_prefix(input: &str) -> IResult<&str, (Option<&str>, &str), Error<&str>> {
    pair(opt(tag("#")), hex_digit1)(input)
}

fn parse_number(input: &str) -> IResult<&str, Expression> {
    map(
        delimited(space0, hex_digit_with_prefix, space0),
        |(x, y)| evaluate_number(x, y),
    )(input)
}

// cargo watch -- cargo test expression -- --nocapture
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_number() {
        let (_, exp) = parse_number(&"  #abc  ").unwrap();

        assert!(exp == Expression::Number(0xabc));

        let (_, exp) = parse_number(&"  987  ").unwrap();

        assert!(exp == Expression::Number(987));
    }
}

此外,如果我包括符号,事情就会变得更加复杂:

fn parse_hex_digit(input: &str) -> IResult<&str, (Option<Option<&str>, &str>, &str), Error<&str>> {
    pair(pair(opt(tag("#")), opt(tag("#"))), hex_digit1)(input)
}

看起来example 给出的方法更适合我。 拜托,您能否建议为了保持代码简单和可维护的方向是什么?

【问题讨论】:

    标签: rust nom


    【解决方案1】:

    我认为你的例子看起来不错。我不能说它是否更具可读性和可维护性,但这里有一个略微修改并且可能稍微更直接的语法和一个符号。我不确定为什么需要表达式,所以我自愿选择了整数。希望它没问题,如果需要,您可以更改为 Expression。

    use nom::{
        bytes::complete::tag,
        character::complete::{hex_digit1, space0},
        combinator::{map, opt},
        error::Error,
        sequence::{delimited, pair},
        IResult,
        branch::alt,
        multi::{many0, many1},
        combinator::{map_res, recognize},
        sequence::{preceded, terminated},
        character::complete::{char, one_of},
        sequence::tuple,
    };
    
    fn decimal(input: &str) -> IResult<&str, i64> {
        map_res(
            tuple(
                (
                    opt(char('-')),
                    recognize(many1(one_of("0123456789"))),
                )
            ),
            |(sign, digits): (Option<char>, &str)| {
                let sign = if sign.is_some() { -1 } else { 1 };
                digits.parse::<i64>().map(|n| sign * n)
            }
        )(input)
    }
    
    fn hexadecimal_value(input: &str) -> IResult<&str, i64> {
        map_res(
            tuple(
                (
                    opt(char('-')),
                    alt((tag("#"), tag("0x"), tag("0X"))),
                    recognize(many1(one_of("0123456789abcdefABCDEF"))),
                )),
            |(sign, _, digits)| {
                let sign = if sign.is_some() { -1 } else { 1 };
                i64::from_str_radix(digits, 16).map(|n| sign * n)
            }
        )(input)
    }
    
    fn parse_number(input: &str) -> IResult<&str, i64> {
        delimited(
            space0,
            alt((decimal, hexadecimal_value)),
            space0,
        )(input)
    }
    
    // cargo watch -- cargo test expression -- --nocapture
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_parse_number() {
            let (_, exp) = parse_number("  -#abc  ").unwrap();
    
            assert!(exp == -0xabc);
    
    
            let (_, exp) = parse_number("  -987  ").unwrap();
            assert!(exp == -987);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 2010-12-30
      • 2011-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多