rust 如何使用nom将带符号的字符串解析为i32?

a6b3iqyw  于 2022-12-19  发布在  其他
关注(0)|答案(3)|浏览(233)

使用nom机箱,我试图编写一个解析器,它可以从String中识别有符号的i32数字,也就是说,可以将字符串-42转换为i32表示。
到目前为止,我已经得到了以下代码,但我无法解析负数:

use nom::types::CompleteStr;
use std::str::FromStr;

named!(
    i32_parser<CompleteStr, i32>,
    map_res!(nom::digit, |CompleteStr(s)| i32::from_str(s))
);

#[test]
fn parse_i32_positive() {
    assert_eq!(
        i32_parser(CompleteStr::from("42")),
        Ok((CompleteStr::from(""), 42))
    );
}

#[test]
fn parse_i32_negative() {
    assert_eq!(
        i32_parser(CompleteStr::from("-42")),
        Ok((CompleteStr::from(""), -42))
    );
}

我还尝试了以下方法,但出现了一个隐含的编译错误:

named!(
     i32_parser<CompleteStr, i32>,
     map_res!(alt!(char!('-') | nom::digit), |CompleteStr(s)| i32::from_str(s))
 );
^ expected char, found struct `nom::types::CompleteStr`

有什么建议吗?或者用nom来实现这一点的更简单的方法?
我明确地希望用nom来实现这一点,因为我试图解析一个更复杂的结构。i32::from_str(s)适用于简单的字符串,但这不是我想要的。

carvr3hs

carvr3hs1#

recognize!宏可以帮助您。它返回解析后的输入字符串而不是解析器输出,然后可以像往常一样进行转换。例如:

named!(i32_parser<&str, i32>,
    map_res!(
        recognize!(tuple!(opt!(char!('-')), digit)),
        FromStr::from_str)
);
irlmq6kh

irlmq6kh2#

更新了现代非宏名称:

fn parse_isize(input: &str) -> IResult<&str, isize> {
    let (i, number) = map_res(recognize(preceded(opt(tag("-")), digit1)), |s| {
        isize::from_str(s)
    })(input)?;

    Ok((i, number))
}
yyyllmsg

yyyllmsg3#

alt!(char!('-') | nom::digit)“返回”一个字符,所以你的lambda需要接受一个字符作为参数,并且它可能是'-',所以在运行时调用i32::from_str将会失败。
与其在一个步骤中处理符号和数字,不如将问题分解为两部分,例如使用do_parse

named!(
    i32_parser<CompleteStr, i32>,
    do_parse!(
        minus: opt!(char!('-')) >>
        digits: many1!(digit) >>
        ({
            let sign = if minus.is_some() { -1 } else { 1 };
            let mut number = 0;
            for digit in digits {
                number = number*10 + i32::from_str(digit.0).unwrap();
            }
            sign * number
        })
    )
);

相关问题