如何将字符串截断为最多 N 个字符?
How can I truncate a string to have at most N characters?
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
s 并收集到 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");
}
然而,这感觉非常沉重。
确保你阅读并理解 :
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 中,每个代码点都映射到可变数量的字节。没有 O(1)
算法将“6 个字符”转换为 "N bytes",因此标准库不会对您隐藏它。
您可以使用 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");
}
这也是 returns 一个切片,如果需要,您可以选择将其移动到新的分配中,或者就地改变 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.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
s 并收集到 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");
}
然而,这感觉非常沉重。
确保你阅读并理解
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 中,每个代码点都映射到可变数量的字节。没有 O(1)
算法将“6 个字符”转换为 "N bytes",因此标准库不会对您隐藏它。
您可以使用 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");
}
这也是 returns 一个切片,如果需要,您可以选择将其移动到新的分配中,或者就地改变 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, "");
}