rustmax::nom::multi

Function many

Source
pub fn many<I, E, Collection, F, G>(
    range: G,
    parser: F,
) -> impl Parser<I, Output = Collection, Error = E>
where I: Clone + Input, F: Parser<I, Error = E>, Collection: Extend<<F as Parser<I>>::Output> + Default, E: ParseError<I>, G: NomRange<usize>,
Expand description

Repeats the embedded parser and collects the results in a type implementing Extend + Default. Fails if the amount of time the embedded parser is run is not within the specified range.

ยงArguments

  • range Constrains the number of iterations.
    • A range without an upper bound a.. is equivalent to a range of a..=usize::MAX.
    • A single usize value is equivalent to value..=value.
    • An empty range is invalid.
  • parse The parser to apply.
use nom::multi::many;
use nom::bytes::complete::tag;

fn parser(s: &str) -> IResult<&str, Vec<&str>> {
  many(0..=2, tag("abc")).parse(s)
}

assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"])));
assert_eq!(parser("abc123"), Ok(("123", vec!["abc"])));
assert_eq!(parser("123123"), Ok(("123123", vec![])));
assert_eq!(parser(""), Ok(("", vec![])));
assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"])));

This is not limited to Vec, other collections like HashMap can be used:

use nom::multi::many;
use nom::bytes::complete::{tag, take_while};
use nom::sequence::{separated_pair, terminated};
use nom::AsChar;

use std::collections::HashMap;

fn key_value(s: &str) -> IResult<&str, HashMap<&str, &str>> {
  many(0.., terminated(
    separated_pair(
      take_while(AsChar::is_alpha),
      tag("="),
      take_while(AsChar::is_alpha)
    ),
    tag(";")
  )).parse(s)
}

assert_eq!(
  key_value("a=b;c=d;"),
  Ok(("", HashMap::from([("a", "b"), ("c", "d")])))
);

If more control is needed on the default value, fold can be used instead:

use nom::multi::fold;
use nom::bytes::complete::tag;


fn parser(s: &str) -> IResult<&str, Vec<&str>> {
  fold(
    0..=4,
    tag("abc"),
    // preallocates a vector of the max size
    || Vec::with_capacity(4),
    |mut acc: Vec<_>, item| {
      acc.push(item);
      acc
    }
  ).parse(s)
}


assert_eq!(parser("abcabcabcabc"), Ok(("", vec!["abc", "abc", "abc", "abc"])));