在字符后查找字符串中下一个字符边界索引

8
给定字符串 s,以及索引 i,它是字符 开始的位置:
let s = "abc 好 def";
let i = 4;

什么是获取该字符后的索引的最佳方法,以便我可以切片字符串并获取abc 好?在代码中:
let end = find_end(s, i);
assert_eq!("abc 好", &s[0..end]);

(注意,+1 不起作用,因为它假设字符只有 1 个字节长。)
我目前有以下内容:
fn find_end(s: &str, i: usize) -> usize {
    i + s[i..].chars().next().unwrap().len_utf8()
}

但是我在想,如果有更好的方法呢?
2个回答

7
您可以使用char_indices来获取下一个索引,而不是在字符上使用len_utf8,尽管这对于最后一个字符有特殊情况。
我建议使用方便的str::is_char_boundary()方法。这里是使用它的一个实现:
fn find_end(s: &str, i: usize) -> usize {
    assert!(i < s.len());
    let mut end = i+1;
    while !s.is_char_boundary(end) {
        end += 1;
    }
    end
}

Playground链接

通常情况下,我会让这个函数返回Option<usize>以防止在s的结尾处调用它,但是现在我只是做了一个断言。

在许多情况下,与其显式调用find_end,使用char_indices进行迭代可能更合理,因为它会给您每个字符的索引;尽管如果您想知道当前字符的结尾,这可能有点麻烦。


1
感谢您的回答!在我的问题中,我没有提到过,但我也曾经使用过 is_char_boundary。使用 char_indices,如果您停在一个字符并希望获取下一个索引,则可以使用 i + c.len_utf8(),所以这也是一个好主意! - robinst

1
作为@ChrisEmerson答案的补充,以下是如何实现一个find_end函数,该函数搜索字符第一次出现的结尾。 Playground
fn find_end<'s>(s: &'s str, p: char) -> Option<usize> {
    let mut indices = s.char_indices();
    let mut found = false;
    for (_, v) in &mut indices {
        if v == p {
            found = true;
            break;
        }
    }
    if found {
        Some(indices.next()
                    .map_or_else(|| s.len(), |(i, _)| i))
    } else {
        None
    }
}

尽管它避免了字节边界循环,但仍不是非常优雅。理想情况下,一个迭代器方法可以简化按条件遍历的操作。

我有点惊讶,似乎没有“next_char_boundary”方法! - Chris Emerson
同样感谢!使用 next() 的缺点是,它仅在当前字符后面还有另一个字符时才起作用。 - robinst
@ChrisEmerson 是的,一个 next_char_boundary 方法会很完美。 - robinst
@robinst 最后的字符可以很容易地处理。我已经更新了函数。 - E net4

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