Skip to content

String::remove

String methods · Strings

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.

pub fn remove(&mut self, idx: usize) -> char

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.

removed 'é', left "hllo"
boundary at 2? false
removed 'h'
"prgrmmng"
"prgrmmng"

See also

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