Daniel Trebbien
Daniel Trebbien

Reputation: 39218

How to implement a take_until_and_consume-like parser combinator that does not skip the tag?

I would like to write a nom parser combinator that takes as many bytes up to and including a tag sequence. I tried using take_until_and_consume!, but I found that the generated parser combinator discards the tag sequence:

#[macro_use]
extern crate nom;

named!(up_to_and_including_backslash, take_until_and_consume!("\\"));

fn main() {
    let res = up_to_and_including_backslash(b"    \\");
    println!("{:?}", res);
}

Results in:

Done([], [32, 32, 32, 32])

What I would like is for the tag sequence (in this case, the backslash character) to be included in the result:

Done([], [32, 32, 32, 32, 92])

How can I accomplish this?

Upvotes: 2

Views: 926

Answers (2)

クリホ
クリホ

Reputation: 440

update:
You want to use recognize! on take_until_and_consume!("\\") to add everything it consumed to the Output.

You would write your parser function like this:

#[macro_use]
extern crate nom;

named!(up_to_and_including_backslash, recognize!( take_until_and_consume!("\\") ));

fn main() {
    let res = up_to_and_including_backslash(b"    \\");
    println!("{:?}", res);
}

In case you needed to include the consumed symbols of multiple parsers to your Output you could put them all inside a do_parse! within recognize!. Like so:

recognize!( do_parse!( tag!("\\") >> take_until_and_consume!("\\") >> take!(4) >> () ) )

old:
The only way I got this to work was this ugly abomination.

named!(up_to_and_including_backslash,
    do_parse!(
        line: take_until_and_consume!("\\") >>
        (
            { 
                let mut complete_line:Vec<u8> = line.to_vec();
                complete_line.extend_from_slice(b"\\");
                &*complete_line
            }
        )
    )
);

Upvotes: 2

Neikos
Neikos

Reputation: 1980

Right now you are using the method take_until_and_consume whose Documentation says:

generates a parser consuming bytes until the specified byte sequence is found, and consumes it

The consume part is important, since it is what you want to avoid.

You could do something akin to this:

named!(up_to_and_including_backslash,
    do_parse!(
        line: take_until!("\\") >> char!('\\') >>
        (line)
    )
);

Which should return the line with your seperator.

Upvotes: -1

Related Questions