String.truncate(usize)
的预期方法失败是因为它不考虑 Unicode 字符(考虑到 Rust 将字符串视为 Unicode,这令人困惑)。
let mut s = "ボルテックス".to_string();
s.truncate(4);
thread '' panicked at 'assertion failed: self.is_char_boundary(new_len)'
此外,truncate
会修改原始字符串,这并不总是需要的。
我想出的最好办法是转换为 char
并收集到 String
。
fn truncate(s: String, max_width: usize) -> String {
s.chars().take(max_width).collect()
}
例如
fn main() {
assert_eq!(truncate("ボルテックス".to_string(), 0), "");
assert_eq!(truncate("ボルテックス".to_string(), 4), "ボルテッ");
assert_eq!(truncate("ボルテックス".to_string(), 100), "ボルテックス");
assert_eq!(truncate("hello".to_string(), 4), "hell");
}
然而,这感觉非常沉重。
最佳答案
确保您阅读并理解delnan's point :
Unicode is freaking complicated. Are you sure you want
char
(which corresponds to code points) as unit and not grapheme clusters?
此答案的其余部分假设您有充分的理由使用 char
而不是字素。
which is baffling considering Rust treats strings as Unicode
这是不正确的; Rust 将字符串视为 UTF-8。在 UTF-8 中,每个代码点都映射到可变数量的字节。没有将“6 个字符”转换为“N 个字节”的 O(1)
算法,因此标准库不会向您隐藏这一点。
您可以使用 char_indices
逐个字符地遍历字符串并获取该字符的字节索引:
fn truncate(s: &str, max_chars: usize) -> &str {
match s.char_indices().nth(max_chars) {
None => s,
Some((idx, _)) => &s[..idx],
}
}
fn main() {
assert_eq!(truncate("ボルテックス", 0), "");
assert_eq!(truncate("ボルテックス", 4), "ボルテッ");
assert_eq!(truncate("ボルテックス", 100), "ボルテックス");
assert_eq!(truncate("hello", 4), "hell");
}
这也会返回一个切片,如果需要,您可以选择将其移入新分配,或者就地改变 String
:
// May not be as efficient as inlining the code...
fn truncate_in_place(s: &mut String, max_chars: usize) {
let bytes = truncate(&s, max_chars).len();
s.truncate(bytes);
}
fn main() {
let mut s = "ボルテックス".to_string();
truncate_in_place(&mut s, 0);
assert_eq!(s, "");
}
关于string - 如何将字符串截断为最多 N 个字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38461429/