在Rust中,将一个&str拆分为每个字符一个的&str迭代器的惯用方式是什么?

5
如果我想将类似于“aeiou”的&str转换为大致等同于["a", "e", "i", "o", "u"].iter()的迭代器,最常见的方法是什么?
我尝试过"aeiou".split(""),这对我来说似乎很常见,但我得到了空的&str在开头和结尾。
我尝试过"aeiou".chars(),但从那里开始转换char&str变得非常丑陋和笨拙。
暂时地,我只是打出了["a", "e", "i", "o", "u"].iter(),但一定有更简单、更常见的方法。
为了上下文,在每个值上循环并将其传递到类似于string.matches(vowel).count()的东西中。
以下是我的整体代码。也许我在别的地方走错了。
fn string_list_item_count<'a, I>(string: &str, list: I) -> usize
where
    I: IntoIterator<Item = &'a str>,
{
    let mut num_instances = 0;

    for item in list {
        num_instances += string.matches(item).count();
    }

    num_instances
}

// snip

string_list_item_count(string, vec!["a", "e", "i", "o", "u"])

// snip

如果我能让string_list_item_count接受迭代器中实现了std::str::pattern::Pattern特性的类型,那么我认为该函数将可以接受&strchar类型的迭代器,但是Pattern特性是一个夜间不稳定的API,我正在尝试避免使用它们。

这个回答解决了你的问题吗?如何将字符串转换为字符列表? - asky
1
不,我基本上是想做相反的事情。将字符的迭代器转换为&strs的迭代器。 - user457586
1
在您的问题背景下,您如何定义字符?ASCII字符?Unicode代码点?字形簇?...? - Lukas Kalbertodt
这是一个很好的观点。这也是为什么我希望Pattern是稳定的,这样我就不必指定确切的类型。我希望我可以使用.matches接受的任何内容。对我来说,.matches是稳定的,但它的基础特性却不是,这有点奇怪。 - user457586
3个回答

6
您可以使用 split_terminator 替换 split 以跳过迭代器末尾的空字符串。另外,如果您skip掉迭代器的第一个元素,则可以得到想要的结果:
let iterator = "aeiou".split_terminator("").skip(1);
println!("{:?}", iterator.collect::<Vec<_>>());

输出:

["a", "e", "i", "o", "u"]

1
哦,那很有趣。虽然比键入vec更多字符,但仍感觉有些糟糕。 - user457586
1
是的。但对于较长的字符串,它的扩展性更好。 - sshashank124

2

我会使用空字符串对 str::split 进行分割,然后使用 Iterator::filter 删除任何空字符串:

fn string_chars(s: &str) -> impl Iterator<Item = &str> {
    s.split("").filter(|s| !s.is_empty())
}

fn main() {
    assert_eq!(
        string_chars("aeiou").collect::<Vec<_>>(),
        ["a", "e", "i", "o", "u"],
    );
}

1
一个闭包也可以作为模式
fn main() {
    let vowels = "aeiou";
    let s = "the quick brown fox jumps over the lazy dog";
    let count = string_item_count(s, vowels);
    dbg!(count);
}

fn string_item_count(string: &str, pat: &str) -> usize {
    let pred = |c| pat.contains(c);
    string.matches(pred).count()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接