String 如何更改rust中字符串中特定索引处的字符?
我试图更改字符串中特定索引处的单个字符,但我不知道如何更改。例如,我如何将“hello world”中的第4个字符更改为“x”,使其成为“HellXO world”?在Rust中表示字符串的标准方法是将连续的字节范围编码为UTF-8字符串。UTF-8码点的长度可以是1到4字节,因此通常不能简单地用另一个替换一个UTF-8码点,因为长度可能会改变。您也不能执行简单的指针算法来索引到第n个字符的RustString 如何更改rust中字符串中特定索引处的字符?,string,rust,char,String,Rust,Char,我试图更改字符串中特定索引处的单个字符,但我不知道如何更改。例如,我如何将“hello world”中的第4个字符更改为“x”,使其成为“HellXO world”?在Rust中表示字符串的标准方法是将连续的字节范围编码为UTF-8字符串。UTF-8码点的长度可以是1到4字节,因此通常不能简单地用另一个替换一个UTF-8码点,因为长度可能会改变。您也不能执行简单的指针算法来索引到第n个字符的Rust字符串,因为代码点编码的长度可以是1到4个字节 因此,一种安全但缓慢的方法是这样的,迭代源字符串的
字符串,因为代码点编码的长度可以是1到4个字节
因此,一种安全但缓慢的方法是这样的,迭代源字符串的字符,替换所需的字符,然后创建一个新字符串:
fn replace_nth_char(s: &str, idx: usize, newchar: char) -> String {
s.chars().enumerate().map(|(i,c)| if i == idx { newchar } else { c }).collect()
}
但是,如果我们手动确保新旧字符都是单字节ascii,那么我们可以在O(1)中实现
fn replace_nth_char_safe(s: &str, idx: usize, newchar: char) -> String {
s.chars().enumerate().map(|(i,c)| if i == idx { newchar } else { c }).collect()
}
fn replace_nth_char_ascii(s: &mut str, idx: usize, newchar: char) {
let s_bytes: &mut [u8] = unsafe { s.as_bytes_mut() };
assert!(idx < s_bytes.len());
assert!(s_bytes[idx].is_ascii());
assert!(newchar.is_ascii());
// we've made sure this is safe.
s_bytes[idx] = newchar as u8;
}
fn main() {
let s = replace_nth_char_safe("Hello, world!", 3, 'x');
assert_eq!(s, "Helxo, world!");
let mut s = String::from("Hello, world!");
replace_nth_char_ascii(&mut s, 3, 'x');
assert_eq!(s, "Helxo, world!");
}
fn替换字符安全(s:&str,idx:usize,newchar:char)->String{
s、 chars().enumerate().map(|(i,c)| if i==idx{newchar}else{c}).collect()
}
fn替换字符ascii(s:&mut str,idx:usize,newchar:char){
设s_bytes:&mut[u8]=safe{s.as_bytes_mut()};
断言!(idx
请记住,replace\n\u char\u ascii
中的idx
参数不是字符索引,而是字节索引。如果字符串前面有任何多字节字符,则字节索引和字符索引将不对应。最简单的方法是使用如下方法:
让mut hello=String::from(“hello world”);
您好。替换_范围(3..4,“x”);
普林顿!(“你好:{}”,你好);
输出:hello:helxo-world
()
请注意,如果要替换的范围不在UTF-8码点边界上开始和结束,这将导致死机。例如,这会引起恐慌:
让mut hello2=String::from(“helldo do do do you seeking?OP很有可能适合字节索引,在这种情况下,String::replace_range
是String
本身提供的合适工具。@user4815162342看起来你是对的,String::replace_range()
(将其委托给Vec::splice
)可以替换O(1)中的范围。我能看到的唯一缺点是它使用&str
参数作为替换,我认为这需要一个静态定义的常量替换或分配。我没有研究源代码,但我希望它在需要时重新分配,或者在传递的替换与范围大小相同的情况下进行更改。我查看了它。它是安全高效的库代码,它只在需要时分配和洗牌数据。也许答案应该提到String::replace_range
,最好在顶部。它简单、安全(从生锈的意义上讲),高效,几乎可以肯定是OP所追求的解决方案。