我现在正在学习用
nom
进行解析,出现了一些我无法自己解决的问题。有一个我想在这里问一下。
首先:我不确定我是否真的需要使用 nom
来实现此目的,但这似乎是检测空格、制表符、换行符和回车符的任何组合的最简单方法。我想用一个空格替换这些字符的任何序列。我的那种不优雅的解决方案看起来像这样:
enum EmptyOrStr {
Empty,
Str(char),
fn replace_multispaces<'a>(i: &str) -> IResult<&str, String> {
let (rest, tokens) = many0(alt((
map(multispace1, |_| EmptyOrStr::Empty),
// i would like to use `not(multispace1)` instead of `anychar`,
// but then the output type is `()` and I cannot put it into the
// `EmptyOrStr::Str( )`-variant
map(anychar, |s| EmptyOrStr::Str(s)),
)))(i)?;
Ok((
"",
tokens
.into_iter()
.map(|t| match t {
EmptyOrStr::Str(s) => format!("{s}"), // because s is a `char` not a `&str`
EmptyOrStr::Empty => " ".to_string(),
})
.collect::<String>(),
))
}
我没能用 &str 做到这一点。直觉上我猜想让
alt
内部的第二个解析器使用类似 take_till1(is_multispace1)
之类的东西会更好,但这需要一个条件,而不是解析器。
我认为有太多的东西一起使用,我无法理解所有内容。
理想情况下,用单个空格替换
multispace
不需要 nom。但我认为 multispace1 函数非常实用。
有什么明显的方法可以改进这个吗?
split_ascii_whitspace()
。
下面的示例函数使用
split_ascii_whitespace()
来分割输入并使用单个空格字符重新连接它。
fn strip_multispace(input: &str) -> String {
input.split_ascii_whitespace().collect::<Vec<&str>>().join(" ")
}
fn main() {
let s = "This is a string with\t multiple\n\r\n white\t\t\r\nspaces";
println!("{}", strip_multispace(s));
}
输出:
This is a string with multiple white spaces