Search code examples
rustnom

Parse an integer to a float using Nom


Nom has an example of parsing a floating point number:

named!(unsigned_float <f32>, map_res!(
  map_res!(
    recognize!(
      alt!(
        delimited!(digit, tag!("."), opt!(complete!(digit))) |
        delimited!(opt!(digit), tag!("."), digit)
      )
    ),
    str::from_utf8
  ),
  FromStr::from_str
));

I want to extend this example to also support parsing "123" to 123.0. I've tried something like this with no luck:

named!(unsigned_float_v1 <f32>,
    map_res!(
        map_res!(
            alt!(
                recognize!(
                    alt!(
                        delimited!(digit, tag!("."), opt!(complete!(digit))) |
                        delimited!(opt!(digit), tag!("."), digit)
                    )
                ) |
                ws!(digit)
            ),
            str::from_utf8
        ),
        FromStr::from_str
    )
);

named!(unsigned_float_v2 <f32>,
    map_res!(
        map_res!(
            recognize!(
                alt!(
                    delimited!(digit, tag!("."), opt!(complete!(digit))) |
                    delimited!(opt!(digit), tag!("."), digit) |
                    digit
                )
            ),
            str::from_utf8
        ),
        FromStr::from_str
    )
);

Solution

  • You need to wrap the tag!(".") with complete! too, as follows:

    named!(unsigned_float_v2 <f32>,
        map_res!(
            map_res!(
                recognize!(
                    alt!(
                        delimited!(digit, complete!(tag!(".")), opt!(complete!(digit))) |
                        delimited!(opt!(digit), complete!(tag!("."), digit) |
                        digit
                    )
                ),
                str::from_utf8
            ),
            FromStr::from_str
        )
    );
    

    If the input is 123, the tag! would return Incomplete because it cannot decide if the next input is a .