[Pre-PR] `Path::strip_prefix` counterpart in `str`

It would be useful to have a str::strip_prefix implementation that something similar to the following (unoptimized, incorrect) function:

impl str {
    fn strip_prefix(&'a self, pat: P) -> Option<&'a str>
    where P: Pattern {
        if self.starts_with(pat) {
            Some(&self[self.find(pat) + pat.len()..])
        } else {
            None
        }
    }
}

Did I miss something similar in libstd?

4 Likes

trim_start_matches?

Actually, I suppose that's slightly different, in that it removes repeated copies of the prefix, whereas strip_prefix doesn't.

If self.starts_with(pat), then wouldn't self.find(pat) always return Some(0)? (And also, you can't add Some(0) and pat.len().) I think you want just &self[pat.len()..].

That aside, I think I would suggest something like trim_start_matches_n, with a count n (pass 1 to get the behavior of your strip_prefix), analogous to replacen. And if we have trim_start_matches_n, we would also want trim_end_matches_n.

1 Like

Yes, it's just some incorrect pseudocode to illustrate what the function is doing.

strip_prefix returns an Option so that you can handle the lack of prefix directly. What would be the return type of trim_start_matches_n?

Yeah, I'd really like strip_prefix/suffix. I don't want to use trim_matches:

  • most of the time I have one specific prefix/suffix to remove, not a number of them.
  • often lack of prefix/suffix is an error that I'd like to handle.

e.g. if I want to trim lib prefix from libfoo.a filename, I shouldn't be breaking liblibby.a. If I have some microsyntax like keyword:value, then:

if let Some(value) = s.strip_prefix("keyword:") 

is more efficient and more robust than if s.starts_with() followed by trim_start_matches.

3 Likes

Ah, I see! Yes, the return value you propose seems useful, and in that case trim_start_matches_n seems like an overgeneralization.

strip_prefix makes sense to me. As would strip_suffix.

Another question: Should the function really accept a Pattern? Or does an AsRef<str> suffice?

I have wanted exactly that several times already, e.g. to strip a trailing newline. So, yes, please. :slight_smile:

Ideally, the case where a lack of prefix/suffix is not an error (but we just want to continue with the unmodified string) should be ergonomically provided by the same API as well.

The function takes the str by reference, so an if let Some + else could allow continuing the logic with the original string.

PR opened: https://github.com/rust-lang/rust/pull/66735