Это довольно сложно, но работает следующее:
//# nom = "5.0.1"
use nom::{
bytes::complete::{escaped_transform, tag},
character::complete::none_of,
combinator::{recognize, map_parser},
multi::{many0, separated_list},
sequence::delimited,
IResult,
};
fn main() {
let (_, res) = parse_quoted("'abc''def'").unwrap();
assert_eq!(res, "abc'def");
let (_, res) = parse_quoted("'xy@$%!z'").unwrap();
assert_eq!(res, "xy@$%!z");
let (_, res) = parse_quoted("'single quotes -> '' and so on...'").unwrap();
assert_eq!(res, "single quotes -> ' and so on...");
}
fn parse_quoted(input: &str) -> IResult<&str, String> {
let seq = recognize(separated_list(tag("''"), many0(none_of("'"))));
let unquote = escaped_transform(none_of("'"), '\'', tag("'"));
let res = delimited(tag("'"), map_parser(seq, unquote), tag("'"))(input)?;
Ok(res)
}
Некоторые объяснения:
- парсер
seq
распознает любую последовательность, которая чередуется между двойными кавычками и чем-то еще; unquote
преобразует любые двойные кавычки в одинарные; map_parser
затем объединяет их вместе для получения желаемого результата.
Имейте в виду, чтоиз-за использования комбинатора escaped_transform
результат анализа равен String
вместо &str
. Т.е. есть дополнительные отчисления.