Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Get index of first occurrence of any of range of values in string

I’m trying to find the index of the first vowel in a string (English/ASCII only). I need to extract this index to use it later on (returned in this example). This works:

let s = String::from("cats");

let vowels = ['a', 'e', 'i', 'o', 'u'];

for v in vowels {
    let index = s.to_lowercase().find(v);
    if let Some(i) = index {
        return i;
    }
    break;
}

This works fine, but I feel like there should be a more concise way to do this. Every oneliner I try returns a bool that there was a match or an iterator in vowels rather than the index in the string, s. Help?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Use the .position() method on an iterator:

let string = "cats".to_owned();
let vowels = ['a', 'e', 'i', 'o', 'u'];

if let Some(index) = string.chars().position(|c| vowels.contains(&c)) {
    println!("found first vowel at position: {}", index);
}

Note that this inverts your iteration since your original code would return the first "a" in the string even if there were other vowels before it.


I’d also be remiss if I didn’t point out the distinction between character index vs byte index. If you’re using ASCII text only then there’s no difference, but if you want to be unicode aware and want "the vowel is the nth character", then you’ll want to use .char_indices() and .find() instead:

let string = "ćats".to_owned(); // ć is a multi-byte character
let vowels = ['a', 'e', 'i', 'o', 'u'];

if let Some(index) = string.chars().position(|c| vowels.contains(&c)) {
    println!("found first vowel at character: {}", index);
}

if let Some((index, _)) = string.char_indices().find(|(i, c)| vowels.contains(&c)) {
    println!("found first vowel at byte offset: {}", index);
}
found first vowel at character: 1
found first vowel at byte offset: 2

What you want depends on how you’ll use the index. You’d want the byte offset if you were to index into the string later (e.g. get all characters before the vowel: &string[..index]).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading