|
| 1 | +extern crate nom; |
| 2 | + |
| 3 | +use nom::IResult; |
| 4 | +use nom::bytes::complete::tag; |
| 5 | +use nom::sequence::{separated_pair, terminated}; |
| 6 | +use nom::character::complete::alphanumeric1; |
| 7 | +use nom::combinator::iterator; |
| 8 | +use std::iter::Iterator; |
| 9 | +use std::collections::HashMap; |
| 10 | + |
| 11 | +fn main() { |
| 12 | + let mut data = "abcabcabcabc"; |
| 13 | + |
| 14 | + fn parser(i: &str) -> IResult<&str, &str> { |
| 15 | + tag("abc")(i) |
| 16 | + } |
| 17 | + |
| 18 | + // `from_fn` (available from Rust 1.34) can create an iterator |
| 19 | + // from a closure |
| 20 | + let it = std::iter::from_fn(move|| { |
| 21 | + match parser(data) { |
| 22 | + // when successful, a nom parser returns a tuple of |
| 23 | + // the remaining input and the output value. |
| 24 | + // So we replace the captured input data with the |
| 25 | + // remaining input, to be parsed on the next call |
| 26 | + Ok((i, o)) => { |
| 27 | + data = i; |
| 28 | + Some(o) |
| 29 | + }, |
| 30 | + _ => None |
| 31 | + } |
| 32 | + }); |
| 33 | + |
| 34 | + for value in it { |
| 35 | + println!("parser returned: {}", value); |
| 36 | + } |
| 37 | + |
| 38 | + println!("\n********************\n"); |
| 39 | + |
| 40 | + let data = "abcabcabcabc"; |
| 41 | + |
| 42 | + // if `from_fn` is not available, it is possible to fold |
| 43 | + // over an iterator of functions |
| 44 | + let res = std::iter::repeat(parser).take(3).try_fold((data, Vec::new()), |(data, mut acc), parser| { |
| 45 | + parser(data).map(|(i, o)| { |
| 46 | + acc.push(o); |
| 47 | + (i, acc) |
| 48 | + }) |
| 49 | + }); |
| 50 | + |
| 51 | + // will print "parser iterator returned: Ok(("abc", ["abc", "abc", "abc"]))" |
| 52 | + println!("\nparser iterator returned: {:?}", res); |
| 53 | + |
| 54 | + println!("\n********************\n"); |
| 55 | + |
| 56 | + let data = "key1:value1,key2:value2,key3:value3,;"; |
| 57 | + |
| 58 | + // `nom::combinator::iterator` will return an iterator |
| 59 | + // producing the parsed values. Compared to the previous |
| 60 | + // solutions: |
| 61 | + // - we can work with a normal iterator like `from_fn` |
| 62 | + // - we can get the remaining input afterwards, like with the `try_fold` trick |
| 63 | + let mut nom_it = iterator(data, terminated(separated_pair(alphanumeric1, tag(":"), alphanumeric1), tag(","))); |
| 64 | + |
| 65 | + let res = nom_it.map(|(k, v)| (k.to_uppercase(), v)).collect::<HashMap<_, _>>(); |
| 66 | + |
| 67 | + let parser_result: IResult<_, _> = nom_it.finish(); |
| 68 | + let (remaining_input, ()) = parser_result.unwrap(); |
| 69 | + |
| 70 | + // will print "iterator returned {"key1": "value1", "key3": "value3", "key2": "value2"}, remaining input is ';'" |
| 71 | + println!("iterator returned {:?}, remaining input is '{}'", res, remaining_input); |
| 72 | +} |
| 73 | + |
0 commit comments