How to find in a substring starting at a specific index in Rust?
Asked Answered
A

2

6

Is there a find function in Rust's standard library which searches for a substring starting at a given index in the string? Just like indexOf in JavaScript.

Ardeb answered 19/2, 2021 at 6:53 Comment(1)
This is similar to Find a string starting from given index, but I find the answers there unsatisfactory because they get bogged down by OP's specific case.Devotee
D
11

You would use str::find on a substr and then add the offset back:

let s = "foobarfoo";
let index: Option<usize> = s[4..].find("foo").map(|i| i + 4);
println!("{:?}", index);
Some(6)
Devotee answered 19/2, 2021 at 7:31 Comment(4)
While this is fine for ascii text, there are a few issues with this if s contains general unicode - since s[x..] is the slice starting at byte x, not the x^th character.Tawnytawnya
@MichaelAnderson True, but to avoid that it depends on what 4 means: first four bytes? first four unicode-scalar-values? first four graphemes? Those all have different answers. If we found 4 by first finding the first b, then we already know its unicode-byte-aligned. Its also worth pointing out that String.prototype.indexOf and std::string::find give different results when unicode is involved.Devotee
Those things may all give different answers, and that is fine. However s[4..] can panic - which is not usually the answer you want. I think if you just treat both as bytes then you at least avoid the panic.Tawnytawnya
@MichaelAnderson, I think, 4 here is sum of the position of first occurence and length of searched string so it should always be correct position unicode char. kmdreko, it would be good if you replace magic 4 with such computation here to make it clear for new rust users.Swingletree
A
6

I can think of two ways:

Use the .get() method to safely get a slice of an ASCII string and then apply .find to that.

let s = "foobarfoo";
let res = s.get(4..).and_then(|s| s.find("foo").map(|i| i + 4));

Use match_indices to iterate over matches and their indices and then find_map the one that matches the first condition.

let s = "foobarfoo";
let res = s.match_indices("foo").find_map(|(i, _)| (i >= 4).then(|| i));
  • Both methods will return Some(6).
  • If the index is greater or equal to the length of the string you will get None.
Aideaidedecamp answered 19/2, 2021 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.