This isn't the exact use case, but it is basically what I am trying to do:
let mut username = "John_Smith";
println!("original username: {}",username);
username.set_char_at(4,'.'); // <------------- The part I don't know how to do
println!("new username: {}",username);
I can't figure out how to do this in constant time and using no additional space. I know I could use "replace" but replace is O(n). I could make a vector of the characters but that would require additional space.
I think you could create another variable that is a pointer using something like as_mut_slice, but this is deemed unsafe. Is there a safe way to replace a character in a string in constant time and space?
As of Rust 1.27 you can now use
String::replace_range
:(playground)
replace_range
won't work with&mut str
. If the size of the range and the size of the replacement string aren't the same, it has to be able to resize the underlyingString
, so&mut String
is required. But in the case you ask about (replacing a single-byte character with another single-byte character) its memory usage and time complexity are both O(1).There is a similar method on
Vec
,Vec::splice
. The primary difference between them is thatsplice
returns an iterator that yields the removed items.If you want to handle only ASCII there is separate type for that:
There are some missing pieces (like
into_ascii
for&str
) but it does what you want. Current implementaion ofto_/into_ascii
fails if input string is invalidascii
. There isto_ascii_opt
(old naming of methods that might fail) but will probably be renamed toto_ascii
in the future (and failing method removed or renamed).In general ? For any pair of characters ? It's impossible.
A string is not an array. It may be implemented as an array, in some limited contexts.
Rust supports Unicode, which brings some challenges:
In order to represent this, a Rust string is (for now) a UTF-8 bytes sequence:
and therefore, the very notion of "replacing character i" brings a few challenges:
i
is between the indexi
and the end of the string, it requires reading the string from the beginning to know exactly where though, which is O(N)In general ? It's impossible.
In a particular and very specific case where the byte index is known and the byte encoding is known coincide length-wise, it is doable by directly modifying the byte sequence return by
as_mut_bytes
which is duly markedunsafe
since you may inadvertently corrupt the string (remember, this bytes sequence must be a UTF-8 sequence).