How to remove last character from &str

The output should be like this:

fn main() {
    assert_eq!("abc".remove_last(), "ab");
    assert_eq!("abd".remove_last(), "ab");
}

You can get the index e.g. with .char_indices().next_back(); then you can slice up the string. Note that a decision would need to be made what you want to do on an empty string. (Your code example suggests that it's not returning something like Option<&str>. The implementation below just returns the full empty string and doesn't panic.) If you want method syntax like your example, you can use an extension trait.

trait StrExt {
    fn remove_last(&self) -> &str;
}

impl StrExt for str {
    fn remove_last(&self) -> &str {
        match self.char_indices().next_back() {
            Some((i, _)) => &self[..i],
            None => self,
        }
    }
}

fn main() {
    assert_eq!("abc".remove_last(), "ab");
    assert_eq!("abd".remove_last(), "ab");
}

(playground)

Note that the notion of "character" is not necessarily clear. A string in Rust is a (utf8-encoded) sequence of unicode scalar values. Dropping the last char like the function above does removes just a single scalar value, which might be only part of what you might consider a character. For example characters with accents or emoji can be encoded using multiple unicode scalar values, i.e. consisting of multiple chars. If you want a more "practical"/language-agnostic notion of character, you could use the concept of "grapheme clusters" provided by the unicode-segmentation crate. E.g.

use unicode_segmentation::UnicodeSegmentation;

trait StrExt {
    fn remove_last(&self) -> &str;
}

impl StrExt for str {
    fn remove_last(&self) -> &str {
        match self.grapheme_indices(true).next_back() {
            Some((i, _)) => &self[..i],
            None => self,
        }
    }
}

fn main() {
    assert_eq!("abc".remove_last(), "ab");
    assert_eq!("abd".remove_last(), "ab");
}

(playground)

3 Likes

Similar idea, different underlying implementation.

trait RemoveLast {
    fn remove_last(&self) -> &Self;
}

impl RemoveLast for str {
    fn remove_last(&self) -> &Self {
        self.strip_suffix(|_: char| true).unwrap_or(self)
    }
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.