Используйте nom, чтобы найти несколько элементов в строке
Я пытаюсь написать парсер, который принимает &str
и возвращает Vec<&str>
где строки Vec - это IP-адреса. Единственный парсер, который я действительно могу получить, это Vec<Option<&str>>
где None
представляет байт, который не был частью IP. Как я могу "пропустить" байты, которые не являются частью IP, без их захвата?
Мой код парсера:
named!(ip<&str,&str>,
recognize!(
do_parse!(
digit >>
tag_s!(".") >>
digit >>
tag_s!(".") >>
digit >>
tag_s!(".") >>
digit >>
(
""
)
)
)
);
named!(extract_ips<&str,Vec<(&str)>>,
do_parse!(
list: many0!(
alt!(
do_parse!(
s: ip >>
(
Some(s)
)
) |
do_parse!(
anychar >>
(
None
)
)
)
) >> ({
list.into_iter().filter_map(|entry| {
match entry {
None => None,
other => other
}
}).collect()
})
)
);
Как видите, я использую alt!()
выразить "либо потреблять IP или потреблять байт", а затем many0!()
будет повторяться до тех пор, пока не будет выполнено использование строки. Я исправляю тип подписи, запустив filter_map
против разобранного результата. Как я могу пропустить использование одного байта и просто двигаться вперед в буфере? У этого синтаксического анализатора есть другая проблема, где, если строка не заканчивается IP nom, будет считать это неполным анализом.
Работает:
let msg1 = r##"a1.2.3.4a3.14a5.6.7.8"##;
let res: IResult<&str, Vec<&str>> = extract_ips(msg1);
Не работает:
let msg1 = r##"a1.2.3.4a3.14a5.6.7.8FOO"##;
let res: IResult<&str, Vec<&str>> = extract_ips(msg1);