1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
pub fn str_windows<'a>(input: &'a str, size: usize) -> impl Iterator<Item=&'a str> {
StrWindowsIter {
inner: input,
size,
}
}
struct StrWindowsIter<'a> {
inner: &'a str,
size: usize,
}
impl<'a> Iterator for StrWindowsIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.size == 0 {
return Some("");
}
let mut char_count = 0;
let mut first_char_len = 0;
let mut found_first_char = false;
for pos in 1..=self.inner.len() {
if self.inner.is_char_boundary(pos) {
char_count += 1;
if ! found_first_char {
first_char_len = pos;
found_first_char = true;
}
}
if char_count == self.size {
let inner = self.inner;
self.inner = &inner[first_char_len..];
return Some(&inner[..pos]);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::str_windows;
#[test]
fn it_works() {
let test_str = "test str_😃";
let expected_arr = ["te", "es", "st", "t ", " s", "st", "tr", "r_", "_😃"];
for (test, &expected) in str_windows(test_str, 2).zip(expected_arr.iter()) {
println!("{} = {}", test, expected);
assert_eq!(test, expected);
}
assert_eq!(str_windows(test_str, 2).count(), expected_arr.len());
}
#[test]
fn degenerate() {
let test_str = "any string";
let mut iter = str_windows(test_str, 0);
for _ in 0..100 {
assert_eq!(iter.next(), Some(""));
}
}
}