Capture the entire contiguous matched input with nom
Asked Answered
I

1

7

I'm looking to apply a series of nom parsers and return the complete &str that matches. I want to match strings of the form a+bc+. Using the existing chain! macro I can get pretty close:

named!(aaabccc <&[u8], &str>,
   map_res!(
       chain!(
           a: take_while!(is_a) ~
               tag!("b") ~
               take_while!(is_c) ,
           || {a}
           ),
       from_utf8
   ));

where

fn is_a(l: u8) -> bool {
   match l {
       b'a' => true,
       _ => false,
   }
}

fn is_c(l: u8) -> bool {
    match l {
        b'c' => true,
        _ => false,
    }
}

Say we have 'aaabccc' as input. The above parser will match the input but only 'aaa' will be returned. What I would like to do is return 'aaabccc', the original input.

chain! is not the right macro for this, but there was not another that seemed more correct. What would the best way to do this be?


At the time of this writing I'm using nom 1.2.2 and rustc 1.9.0-nightly (a1e29daf1 2016-03-25).

Isidraisidro answered 30/3, 2016 at 5:25 Comment(0)
H
5

It appears as if you want recognized!:

if the child parser was successful, return the consumed input as produced value

And an example:

#[macro_use]
extern crate nom;

use nom::IResult;

fn main() {
    assert_eq!(aaabccc(b"aaabcccddd"), IResult::Done(&b"ddd"[..], "aaabccc"));
}

named!(aaabccc <&[u8], &str>,
   map_res!(
       recognize!(
           chain!(
               take_while!(is_a) ~
               tag!("b") ~
               take_while!(is_c),
               || {}
           )
       ),
       std::str::from_utf8
   )
);

fn is_a(l: u8) -> bool {
   match l {
       b'a' => true,
       _ => false,
   }
}

fn is_c(l: u8) -> bool {
    match l {
        b'c' => true,
        _ => false,
    }
}

I'm not sure if chain! is the best way of combining sequential parsers if you don't care for the values, but it works in this case.

Heikeheil answered 30/3, 2016 at 12:50 Comment(2)
Ah, I had misunderstood recognize!. Thank you!Isidraisidro
What if I have <&str, &str>, not <&[u8], &str>? I get error: no method named `offset` found for type `&str` in the current scopePrivatdocent

© 2022 - 2024 — McMap. All rights reserved.