Вот один из способов сделать это:
use nom::types::CompleteStr;
use nom::*;
named!(csv_style_string<CompleteStr, String>,
delimited!(
char!('"'),
map!(
many0!(
alt!(
// Eat a " delimiter and the " that follows it
tag!("\"\"") => { |_| '"' }
| // Normal character
none_of!("\"")
)
),
// Make a string from a vector of chars
|v| v.iter().collect::<String>()
),
char!('"')
)
);
fn main() {
println!(r#""Alo\"ha" = {:?}"#, csv_style_string(CompleteStr(r#""Alo""ha""#)));
println!(r#""" = {:?}"#, csv_style_string(CompleteStr(r#""""#)));
println!(r#"bad format: {:?}"#, csv_style_string(CompleteStr(r#""A""" e""#)));
}
(я написал это полностью, но решение, подобное вашему, основанное на внешней функции вместо map!()
каждого символа, тоже будет работать, и может быть более эффективным.)
Волшебство здесь, которое также решило бы вашу проблему регулярного выражения, состоит в использовании CompleteStr.Это в основном говорит nom
, что ничего не придет после этого ввода (в противном случае nom
предполагает, что вы выполняете потоковый парсер, поэтому может последовать больше ввода).
Это необходимо, потому что нам нужно знать, чтоделать с "
, если это последний символ, введенный в nom
.В зависимости от символа, который следует за ним (другой "
, нормальный символ или EOF), мы должны принять другое решение - следовательно, результат Incomplete
, означающий, что nom
не имеет достаточного ввода, чтобы сделатьрешение.Сообщение nom
о том, что EOF будет следующим, решит эту нерешительность.
Дополнительная информация по Incomplete
в блоге автора nom
: http://unhandledexpression.com/general/2018/05/14/nom-4-0-faster-safer-simpler-parsers.html#dealing-with-incomplete-usage
Вы можете заметить, что этоПарсер на самом деле не отклоняет неверный ввод, но анализирует начало и возвращает остаток.Если вы используете этот синтаксический анализатор в качестве подпарамера в другом парсере, последний затем передаст остаток следующему подпарсеру, который также будет аварийно завершать работу (поскольку он будет ожидать запятую), вызывая сбой всего синтаксического анализатора.
Если вы не хотите этого, вы можете сделать csv_style_string
матч peek!(alt!(char!(',')|char!('\n")|eof!()))
.