简体   繁体   English

如何更改 rust 中字符串中特定索引处的字符?

[英]How do I change characters at a specific index within a string in rust?

I am trying to change a single character at a specific index in a string, but I do not know how to in rust.我正在尝试更改字符串中特定索引处的单个字符,但我不知道如何在 rust 中更改。 For example, how would I change the 4th character in "hello world" to 'x', so that it would be "helxo world"?例如,如何将“hello world”中的第 4 个字符更改为“x”,这样它就变成了“helxo world”?

The easiest way is to use the replace_range() method like this:最简单的方法是像这样使用replace_range()方法:

let mut hello = String::from("hello world");
hello.replace_range(3..4,"x");
println!("hello: {}", hello);

Output: hello: helxo world ( Playground ) Output: hello: helxo world游乐场

Please note that this will panic if the range to be replaced does not start and end on UTF-8 codepoint boundaries.请注意,如果要替换的范围不在 UTF-8 代码点边界上开始和结束,则会出现恐慌。 Eg this will panic:例如这会恐慌:

let mut hello2 = String::from("hell😀 world");
hello2.replace_range(4..5,"x"); // panics because 😀 needs more than one byte in UTF-8

If you want to replace the nth UTF-8 code point, you have to do something like this:如果要替换第 n 个 UTF-8 代码点,则必须执行以下操作:

pub fn main() {
    let mut hello = String::from("hell😀 world");
    hello.replace_range(
        hello
            .char_indices()
            .nth(4)
            .map(|(pos, ch)| (pos..pos + ch.len_utf8()))
            .unwrap(),
        "x",
    );
    println!("hello: {}", hello);
}

( Playground ) 游乐场

The standard way of representing a string in Rust is as a contiguous range of bytes encoded as a UTF-8 string.在 Rust 中表示字符串的标准方法是编码为 UTF-8 字符串的连续字节范围。 UTF-8 codepoints can be from one to 4 bytes long, so generally you can't simply replace one UTF-8 codepoint with another because the length might change. UTF-8 代码点的长度可以是 1 到 4 个字节,因此通常不能简单地将一个 UTF-8 代码点替换为另一个代码点,因为长度可能会改变。 You also can't do simple pointer arithmetic to index into a Rust String to the nth character, because again codepoint encodings can be from 1 to 4 bytes long.您也不能进行简单的指针运算来索引 Rust String到第 n 个字符,因为代码点编码的长度可以是 1 到 4 个字节。

So one safe but slow way to do it would be like this, iterating through the characters of the source string, replacing the one you want, then creating a new string:因此,一种安全但缓慢的方法是这样的,遍历源字符串的字符,替换您想要的字符,然后创建一个新字符串:

fn replace_nth_char(s: &str, idx: usize, newchar: char) -> String {
    s.chars().enumerate().map(|(i,c)| if i == idx { newchar } else { c }).collect()
}

But we can do it in O(1) if we manually make sure the old and new character are single-byte ascii.但是如果我们手动确保旧字符和新字符是单字节 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!");
}

Keep in mind that idx parameter in replace_nth_char_ascii is not a character index, but instead a byte index.请记住, replace_nth_char_ascii中的idx参数不是字符索引,而是字节索引。 If there are any multibyte characters earlier in the string, then the byte index and the character index will not correspond.如果字符串前面有任何多字节字符,则字节索引和字符索引将不对应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM