创建一个字符串中的字符切片的滑动窗口迭代器

时间:2018-07-10 04:32:02

标签: string utf-8 rust iterator slice

我正在寻找使用slices.提供的%env MY_VAR MY_VALUE函数从%envString的最佳方法

我了解如何以这种方式使用Windows:

Windows<T>

但是解决此问题时我有点迷路:

windows

本质上,我正在寻找如何将字符串转换为可以与window方法一起使用的char切片。

3 个答案:

答案 0 :(得分:7)

此解决方案将为您效用。 (playground

fn main() {
    let tst = String::from("abcdefg");
    let inter = tst.chars().collect::<Vec<char>>();
    let mut windows = inter.windows(3);

    // prints ['a', 'b', 'c']
    println!("{:?}", windows.next().unwrap());
    // prints ['b', 'c', 'd']
    println!("{:?}", windows.next().unwrap());
    // etc...
    println!("{:?}", windows.next().unwrap());
}

字符串可以遍历其字符,但这不是切片,因此您必须将其收集到vec中,然后将其强制转换为切片。

答案 1 :(得分:7)

您面临的问题是String实际上被表示为幕后的Vec<u8>之类,并带有一些API可以让您访问char。在UTF-8中,一个代码点的表示形式可以是1到4个字节,并且都被压缩在一起以提高空间效率。

您可以直接获得整个String而不复制所有内容的唯一切片是&[u8],但是您不知道字节是对应于全部还是仅部分代码点

char类型与代码点完全对应,因此大小为4个字节,因此可以容纳任何可能的值。因此,如果您通过从char复制来构建String的一部分,则结果可能会大4倍。

为避免进行潜在的大型临时内存分配,您应考虑采用一种更为懒惰的方法–遍历String,在恰好char的边界处进行切片。像这样:

fn char_windows<'a>(src: &'a str, win_size: usize) -> impl Iterator<Item = &'a str> {
    src.char_indices()
        .flat_map(move |(from, _)| {
            src[from ..].char_indices()
                .skip(win_size - 1)
                .next()
                .map(|(to, c)| {
                    &src[from .. from + to + c.len_utf8()]
                })
    })
}

这将为您提供一个迭代器,其中的项为&str,每个项有3个char

let mut windows = char_windows(&tst, 3);

for win in windows {
    println!("{:?}", win);
}

此方法的优点在于,它根本没有进行任何复制-迭代器生成的每个&str仍然是原始源String的一部分。


所有这些复杂性是因为Rust默认情况下对字符串使用UTF-8编码。如果您完全知道您的输入字符串不包含任何多字节字符,则可以将其视为ASCII字节,并且获取切片变得容易:

let tst = String::from("abcdefg");
let inter = tst.as_bytes();
let mut windows = inter.windows(3);

但是,您现在有了字节片,并且需要将它们重新转换为字符串才能对它们执行任何操作:

for win in windows {
    println!("{:?}", String::from_utf8_lossy(win));
}

答案 2 :(得分:5)

您可以使用itertools遍历任何迭代器的窗口,宽度最大为4:

extern crate itertools; // 0.7.8

use itertools::Itertools;

fn main() {
    let input = "日本語";

    for (a, b) in input.chars().tuple_windows() {
        println!("{}, {}", a, b);
    }
}

另请参阅: