一次迭代一个字符串,n个元素

时间:2015-04-16 09:09:28

标签: string iterator rust

我试图迭代一个字符串,但是在每个字符上迭代长度为n的片而不是迭代器。以下代码手动完成此操作,但有更实用的方法吗?

fn main() {
    let string = "AAABBBCCC";
    let offset = 3;
    for (i, _) in string.chars().enumerate() {
        if i % offset == 0 {
            println!("{}", &string[i..(i+offset)]);
        }
    }
}

3 个答案:

答案 0 :(得分:9)

我会使用PeekableTake的组合:

fn main() {
    let string = "AAABBBCCC";
    let mut z = string.chars().peekable();
    while z.peek().is_some() {
        let chunk: String = z.by_ref().take(3).collect();
        println!("{}", chunk);
    }
}

在其他情况下,Itertools::chunks可能会解决问题:

extern crate itertools;

use itertools::Itertools;

fn main() {
    let string = "AAABBBCCC";
    for chunk in &string.chars().chunks(3) {
        for c in chunk {
            print!("{}", c);
        }
        println!();
    }
}

关于拆分字符串的标准警告

每当开始拆分字符串时,请注意字节/字符/代码点/字形的问题。使用比ASCII字符更复杂的字符,一个字符一个字节,字符串切片操作字节!还有Unicode代码点的概念,但是多个Unicode字符可以组合形成人类认为的单个字符。这个东西非平凡

如果您实际上只有ASCII数据,那么将其存储为Vec<u8>可能是值得的。至少,我创建了一个包装&str的新类型,并且只显示ASCII安全方法,并在创建时验证它是ASCII。

答案 1 :(得分:2)

chunks()不适用于&str,因为它在字符串上的定义不是很明确 - 您是否希望块长度以字节为单位,或字符或字形集群?如果您事先知道您的字符串是ASCII格式,则可以使用以下代码:

use std::str;

fn main() {
    let string = "AAABBBCCC";
    for chunk in str_chunks(string, 3) {
        println!("{}", chunk);
    }
}

fn str_chunks<'a>(s: &'a str, n: usize) -> Box<Iterator<Item=&'a str>+'a> {
    Box::new(s.as_bytes().chunks(n).map(|c| str::from_utf8(c).unwrap()))
}

但是,如果您的字符串中包含非ASCII字符,它将立即中断。我非常确定可以实现一个迭代器,它将一个字符串拆分成代码点或字形集块 - 现在标准库中没有这样的东西了。

答案 2 :(得分:2)

您始终可以实现自己的迭代器。当然,这仍然需要相当多的代码,但它不在您使用字符串的位置。因此,你的循环保持可读性。

#![feature(collections)]

struct StringChunks<'a> {
    s: &'a str,
    step: usize,
    n: usize,
}

impl<'a> StringChunks<'a> {
    fn new(s: &'a str, step: usize) -> StringChunks<'a> {
        StringChunks {
            s: s,
            step: step,
            n: s.chars().count(),
        }
    }
}

impl<'a> Iterator for StringChunks<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        if self.step > self.n {
            return None;
        }
        let ret = self.s.slice_chars(0, self.step);
        self.s = self.s.slice_chars(self.step, self.n);
        self.n -= self.step;
        Some(ret)
    }
}

fn main() {
    let string = "AAABBBCCC";
    for s in StringChunks::new(string, 3) {
        println!("{}", s);
    }
}

请注意,这会在n unicode字符之后拆分。因此,字形或类似物可能最终分裂。