将字符串拆分为偏移子串的功能方法

时间:2015-04-18 18:02:23

标签: rust

我在rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)

我的目标是将长度为n的字符串拆分为长度为n-k+1的{​​{1}}偏移量子字符串。我的意思是,如果你有一个字符串:

k

我正在尝试获取包含任意长度ABCDEF的偏移子串的向量/迭代器。例如,k将产生

k=3

ABC BCD CDE DEF 会产生:

k=2

请注意,空格仅包含在上方以对齐子字符串以显示它们的相关性。输出向量只包括AB BC CD DE EF ABBC等。此外,只支持ASCII,但我更喜欢更安全,更通用的解决方案。

看起来很痛苦,以下程序代码似乎有效:

CD

但它很讨厌,我更喜欢更实用的解决方案。我花了几个小时试图找到一种方法,并在这个过程中学到了很多东西,但我对这个问题感到难过。

有什么想法吗?

PS - 我真的很惊讶上面的fn offset_slices(s: &str, n: usize) -> Vec<&str> { let mut slices: Vec<&str> = Vec::new(); for (i,_) in s.chars().enumerate() { if i > s.len() - n { break; } slices.push(&s[i..(i+n)]); } slices } 甚至编译。它只是返回指向输入的各个位置的指针吗?

2 个答案:

答案 0 :(得分:4)

fn offset_slices(s: &str, n: usize) -> Vec<&str> {
    (0 .. s.len() - n + 1).map(|i| &s[i .. i + n]).collect()
}

答案 1 :(得分:3)

你真的想要windows迭代器,但只存在切片而不是字符串(参见下面的注释)。由于您有ASCII数据,我们可以创建一个强制执行该约束的类型,然后使用一些不安全的代码。我们程序员可以保证不安全的代码 安全因为我们确保数据只是ASCII

作为huon-dbaupp points out,您应该尝试使用ascii crate。它现在似乎没有windows,但是如果你愿意的话,你有权将这些代码(适当调整)提交给那个箱子。 ^ _ ^

use std::slice;
use std::str;

struct AsciiString {
    bytes: Vec<u8>,
}

impl AsciiString {
    fn new(s: &str) -> AsciiString {
        for b in s.bytes() {
            assert!((b as u8) < 128);
        }
        AsciiString { bytes: s.bytes().collect() }
    }

    fn windows(&self, n: usize) -> Windows {
        Windows { iter: self.bytes.windows(n) }
    }
}

struct Windows<'a> {
    iter: slice::Windows<'a, u8>,
}

impl<'a> Iterator for Windows<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        self.iter.next().map(|bytes| {
            unsafe { str::from_utf8_unchecked(bytes) }
        })
    }
}

fn main() {
    let ascii = AsciiString::new("ABCDEF");
    for i in ascii.windows(3) {
        println!("{}", i);
    }
}
  

我真的很惊讶上面的slices.push(&amp; s [i ..(i + n)])甚至编译。它只是返回指向输入的各个位置的指针吗?

这是一个棘手的问题,但一旦理解了它就有意义了(事情总是如此?)

当您使用Index特征时,请注意它已针对str实施,而不是&str

fn index(&'a self, index: Idx) -> &'a Self::Output;

impl Index<Range<usize>> for str { ... }

这意味着索引返回值,其生命周期与输入相同。在这种情况下,您从&'foo str开始,最后得到&'foo str。从概念上讲,是的,&str是指向一块内存和一个长度的指针。当你对它进行切片时,你只是调整指针和长度,但底层存储仍将存活相同的生命周期。

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

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