Как реализовать подобный take_until_and_consume комбинатор парсера, который не пропускает тег?

Я хотел бы написать комбинатор имени синтаксического анализатора, который занимает столько байтов до и включая последовательность тегов. Я пытался с помощью take_until_and_consume!, но я обнаружил, что сгенерированный синтаксический анализатор отбрасывает последовательность тегов:

#[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);
}

Результаты в:

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

Я хотел бы, чтобы последовательность тегов (в данном случае символ обратной косой черты) была включена в результат:

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

Как я могу сделать это?

2 ответа

Решение

Обновить:
Вы хотите использовать recognize! на take_until_and_consume!("\\") чтобы добавить все, что он потребляет на выходе.

Вы бы написали свою функцию парсера следующим образом:

#[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);
}

В случае, если вам нужно включить потребляемые символы нескольких парсеров в ваш вывод, вы можете поместить их все в do_parse! в recognize!, Вот так:

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

старый:
Единственный способ заставить это работать - это мерзкая мерзость.

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
            }
        )
    )
);

Прямо сейчас вы используете метод take_until_and_consume чья документация гласит:

генерирует синтаксический анализатор байтов, пока не будет найдена указанная последовательность байтов, и потребляет ее

Потребляющая часть важна, так как это то, чего вы хотите избежать.

Вы могли бы сделать что-то похожее на это:

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

Который должен вернуть линию с вашим сепаратором.

Другие вопросы по тегам