Search code examples
rustnom

How to use nom take_while and is_digit for a &str input


I'm trying to learn nom and have a problem where take_while does not accept is_digit or any other is_xxxx.

I have rows that I want to parse that looks like this

#123 = ABCDEF (...);

where I want to get the '123' part (and eventually the ABCDEF and the (...) parts as well. But one thing at the time I guess).

My parser currently looks like this

use nom::{
  bytes::complete::take_while,
  character::is_digit,
  error::ParseError,
  IResult
};

// Get row id
fn id<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
    take_while(is_digit)(i)
}

The is_digit definition looks like this

pub fn is_digit(chr: u8) -> bool

And since the id parser takes a &str it will complain about the mismatch in types. But is it possible somehow to use the is_digit anyway? Can I do a type conversion somewhere without having to allocate anything. I really want this to be as efficient as possible.

It feels like the provided is_xxxx functions should be used in these kinds of situations, but I might be wrong about it.

Thanks!


Solution

  • You can easily adapt is_digit to a char. First, all digits are valid ASCII, so we should check first if the character is ASCII. If it's ASCII, we can safely convert to u8.

    // pub fn is_digit(chr: u8) -> bool;
    
    pub fn is_char_digit(chr: char) -> bool {
        return chr.is_ascii() && is_digit(chr as u8)
    }
    

    You could also use the trait method is_dec_digit, which is just a wrapper for char.is_digit.