Iterating over Multiple Lines Using the Rust NOM Parsing Library

1.7k Views Asked by At

I'm trying to learn NOM for a project in Rust. I have a text file that consists of: [tag="#43674"]char[/tag] with multiple tags back to back on each line. I'm trying to pull the '#43674' and 'char', store them in a tuple (x, y) and then push those into a vector Vec<(x, y)> for each line of the text file. So far I have successfully combined parsers into two functions; one for the '#43674' and one for 'char' which I then combine together to return <IResult<&str, (String, String)>. Here is the code:

fn color_tag(i: &str) -> IResult<&str, &str> {
    delimited(tag("[color="), take_until("]"), tag("]"))(i)
}

fn char_take(i: &str) -> IResult<&str, &str> {
    terminated(take_until("[/color]"), tag("[/color]"))(i)
}

pub fn color_char(i: &str) -> IResult<&str, (String, String)> {
    let (i, color) = color_tag(i)?;
    let (i, chara) = char_take(i)?;
    let colors = color.to_string();
    let charas = chara.to_string();

    let tuple = (colors, charas);
    
    Ok((i, tuple))
}

How can I iterate this function over a given line of the text file? I already have a function that iterates the text file into lines, but I need color_char to repeat for each closure in that line. Am I missing the point entirely?

1

There are 1 best solutions below

1
On BEST ANSWER

You'll probably want to use the nom::multi::many0 combinator to match a parser multiple times, and you can also use the nom::sequence::tuple combinator to combine your color_tag and char_take parsers

// Match color_tag followed by char_take
fn color_char(i: &str) -> IResult<&str, (&str, &str)> {
    tuple((color_tag, char_take))(i)
}

// Match 0 or more times on the same line
fn color_char_multiple(i: &str) -> IResult<&str, Vec<(String, String)>> {
    many0(color_char)(i)
}

To parse multiple lines, you can modify color_char() to match a trailing newline character with one of the character parsers provided by nom, such as nom::character::complete::line_ending, make it optional using nom::combinator::opt, and combine it with something like nom::sequence::terminated:

terminated(tuple((color_tag, char_take)), opt(line_ending))(i)