I have a string with the value "Program", and I want to find the index of character 'g' in that string.
-
There are different kinds of indices into a String, because there are a number of levels at which you can count. Counting bytes gives the byte index (byte where a character starts), counting graphemes gives a grapheme index, counting code points gives a code point index.hkBst– hkBst2022-03-17 13:22:49 +00:00Commented Mar 17, 2022 at 13:22
4 Answers
Although a little more convoluted than I would like, another solution is to use the Chars iterator and its position() function:
"Program".chars().position(|c| c == 'g').unwrap()
find used in the accepted solution returns the byte offset and not necessarily the index of the character. It works fine with basic ASCII strings, such as the one in the question, and while it will return a value when used with multi-byte Unicode strings, treating the resulting value as a character index will cause problems.
This works:
let my_string = "Program";
let g_index = my_string.find("g"); // 3
let g: String = my_string.chars().skip(g_index).take(1).collect();
assert_eq!("g", g); // g is "g"
This does not work:
let my_string = "プログラマーズ";
let g_index = my_string.find("グ"); // 6
let g: String = my_string.chars().skip(g_index).take(1).collect();
assert_eq!("グ", g); // g is "ズ"
1 Comment
chars().skip(), it should be used to slice: let g: String = my_string[g_index..].chars().take(1).collect(); and that works fine no matter what kind of characters you use.You are looking for the find method for String. To find the index of 'g' in "Program" you can do
"Program".find('g')
1 Comment
"πx".find("x") returns byte index 2 not char index 1!If your word has several g's you could use enumerate to find all indices:
"ඞggregate"
.chars()
.enumerate()
.filter(|(_, c)| *c == 'g')
.map(|(i, _)| i)
.collect::<Vec<_>>(); // [1, 2, 5]
If the string contains ASCII characters only:
"aggregate"
.bytes()
.enumerate()
.filter(|(_, b)| *b == b'g')
.map(|(i, _)| i)
.collect::<Vec<_>>(); // [1, 2, 5]
Comments
Finding a character that satisfies some condition and then using its byte index works like this:
fn example(s: &str) -> Option<char> {
// find (the byte index of) some character satisfying some condition
if let Some(byte_index) = s
.char_indices()
.find_map(|(p, c)| c.is_numeric().then_some(p))
{
// split the string there for further processing
let (_first, last): (&str, &str) = s.split_at(byte_index);
// the character that we found
let found_char: char = last.chars().next().unwrap();
Some(found_char)
} else {
// no such character
None
}
}
1 Comment
str::char_indices returns character index, not byte index. Character can be encoded with multiple bytes in both utf-8 and utf-16