String::remove¶
Level: reference · for working programmers
One line: Removes the char starting at a byte offset and returns it — panics if the offset is out of range or inside a character.
Stable since 1.0.0.
The index is a byte offset, and it must be the start of a character. "héllo".remove(1) returns 'é' and removes both of its bytes; remove(2) panics.
O(n), because everything after the removed character shifts down. Removing in a loop over an index is therefore quadratic, and it is also usually wrong: after each removal the offsets have changed. retain is the linear, correct way to remove characters by a rule.
Unlike pop there is no Option — an out-of-range index is a panic, not a None. Check with is_char_boundary first if the offset came from outside.
Example¶
string_remove.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let mut s = String::from("héllo");
println!("removed {:?}, left {:?}", s.remove(1), s);
// The offset must start a character.
let mut t = String::from("héllo");
println!("boundary at 2? {}", t.is_char_boundary(2));
println!("removed {:?}", t.remove(0));
// Removing by rule: retain is linear and does not need offsets.
let mut vowels = String::from("programming");
vowels.retain(|c| !"aeiou".contains(c));
println!("{vowels:?}");
// The same by hand is quadratic AND needs care with shifting offsets.
let mut manual = String::from("programming");
let mut i = 0;
while i < manual.len() {
if "aeiou".contains(manual[i..].chars().next().unwrap()) {
manual.remove(i);
} else {
i += manual[i..].chars().next().unwrap().len_utf8();
}
}
println!("{manual:?}");
}
Verified output of string_remove.rs — regenerated by tools/run_examples.py, never hand-typed.
See also¶
String::retain— removing by a rule, in one linear passString::pop— removing from the end, O(1) and no panicString::drain— removing a whole range and seeing what wentString::replace_range— removing a range and putting something back
String::remove in the standard library ↗
Po polsku¶
Indeks w remove to przesunięcie w bajtach, a nie numer znaku, i musi trafiać dokładnie w początek znaku — dla polskiego tekstu jest to pole minowe: "żaba" zajmuje 5 bajtów, więc remove(0) usuwa 'ż', ale remove(1) kończy się paniką z komunikatem start byte index 1 is not a char boundary; it is inside 'ż' (bytes 0..2 of string). Inaczej niż pop, metoda nie zwraca Option — zły indeks to panika, nie None — więc gdy przesunięcie przychodzi skądinąd, sprawdź je wcześniej przez is_char_boundary (strona pokazuje boundary at 2? false dla "héllo"). Druga pułapka jest algorytmiczna: koszt to O(n), bo reszta łańcucha znaków musi się przesunąć, a usuwanie w pętli po indeksie wychodzi przez to kwadratowe i zwykle jeszcze błędne, bo po każdym usunięciu przesunięcia są już inne — do usuwania „według reguły” służy retain, jednoprzebiegowe i wolne od indeksów; w przykładzie obie wersje dają "prgrmmng", ale tylko jedną warto pisać.
Szukaj po polsku: przesunięcie w bajtach · granica znaku · usuwanie znaków według reguły · rust String remove is not a char boundary · rust retain vs remove