rustnom

Extract substring between `\"` with nom


From input "\"Name 1\" something else" I want to extract "Name 1" and the remaining string as " something else". Notice the escaped \".

My current solutions is

use nom::bytes::complete::{tag, is_not};
use nom::sequence::pair;
use nom::IResult;

fn parse_between(i: &str) -> IResult<&str, &str> {
    let (i, (_o1, o2)) = pair(tag("\""), is_not("\""))(i)?;
    if let Some(res) = i.strip_prefix("\"") {
        return Ok((res, o2));
    }
    Ok((i, o2))
}

fn main() {
    println!("{:?}", parse_between("\"Name 1\" something else"));
}

where the output is Ok((" something else", "Name 1")).

Is there a better way to do this? I feel as though calling strip_prefix is an extra step I shouldn't be doing?

Rust Playground link


Solution

  • I believe you're looking for delimited. Here's an example from the nom docs:

    use nom::{
      IResult,
      sequence::delimited,
      // see the "streaming/complete" paragraph lower for an explanation of these submodules
      character::complete::char,
      bytes::complete::is_not
    };
    
    fn parens(input: &str) -> IResult<&str, &str> {
      delimited(char('('), is_not(")"), char(')'))(input)
    }
    

    Adopting it to do what you're looking for:

    use nom::bytes::complete::is_not;
    use nom::character::complete::char;
    use nom::sequence::delimited;
    use nom::IResult;
    
    fn parse_between(i: &str) -> IResult<&str, &str> {
        delimited(char('"'), is_not("\""), char('"'))(i)
    }
    
    fn main() {
        println!("{:?}", parse_between("\"Name 1\" something else"));
        // Ok((" something else", "Name 1"))
    }