Indexes start at zero
Every character in a string has a numbered position, its index. Kotlin counts from zero, so the first character is at index 0, the second at index 1, and so on. You read a character by writing the string's name followed by the index in square brackets:
val message = "Hello world!"
var c = message[0]
println(c) // H
c = message[1]
println(c) // e
println(message[6]) // w
The brackets are a shorthand for the string's get function: message[6] is the same as message.get(6). Most of the time you'll use the brackets.
Whitespace counts
Every character between the quotes is part of the string, including spaces. In "Hello world!", the space sits at index 5, between o at index 4 and w at index 6:
val message = "Hello world!"
println("${message[4]}${message[5]}${message[6]}")
o w
The ${...} parts are string templates, which put the value of an expression into the text. Here each one inserts a single character.
What you get back is a Char
Indexing a string doesn't give you a one-character string. It gives you a Char, a separate type for a single character. A Char literal is written with single quotes, as in 'a', while a string uses double quotes, as in "a". The difference matters as soon as you do arithmetic on the result:
val fruit = "Avocado"
val c = fruit[1] // 'v'
println(c + 1) // w
println(c.code) // 118
println(c.toString() + "x") // vx
Adding an integer to a Char gives the character that many places further along in the character table, so 'v' + 1 is 'w'. The property code is the character's numeric value. To join a Char to text, turn it into a string first with toString(), or use a template.
Printing a Char with println shows the character itself, so no conversion is needed to print it.
Counting from the end
The last index is always one less than the length, because counting starts at 0. In "Avocado" there are 7 characters, so the indexes run from 0 to 6, and the last character is fruit[6]. Using the length keeps the code correct for any string:
val fruit = "Avocado"
println(fruit[fruit.length - 1]) // o
println(fruit.last()) // o
println(fruit.first()) // A
println(fruit.lastIndex) // 6
Kotlin has no negative indexes. There is no fruit[-1] to ask for the last character.
Visiting every character
Later you'll often want every index in turn. The property indices gives exactly the valid ones, from 0 up to the last, so a loop never goes out of range:
val fruit = "Avocado"
for (i in fruit.indices) {
println("$i: ${fruit[i]}")
}
This prints seven lines, from 0: A to 6: o. When the position doesn't matter, a loop can take the characters directly: for (ch in fruit) gives each Char in order, and comparing one to a character literal such as 'o' finds the two letters o in this word.
Gotchas
Going past the end
An index that doesn't exist makes the program stop with an exception. For "Avocado", both fruit[7] and fruit[-1] throw a StringIndexOutOfBoundsException, and the message reads Index 7 out of bounds for length 7 (or Index -1 ...). If the index may be invalid, fruit.getOrNull(10) returns null instead of throwing, and fruit.getOrElse(10) { '?' } returns the fallback you give it.
Strings can't be changed in place
You can read a character by index, but you can't assign to one. The line fruit[0] = 'a' doesn't compile: the compiler reports no 'set' operator method providing array access. To get a modified text, build a new string.
The exercise, step by step
The starting code defines val fruit = "Avocado".
- Print the first character. Use index
0:println(fruit[0]). It printsA. - Print the last character. The string has 7 characters, so the last index is
6:println(fruit[6]). It printso.
val fruit = "Avocado"
println(fruit[0])
println(fruit[6])
The output:
A
o
The two lines fruit[fruit.length - 1] and fruit.last() would give the same o.
Common mistakes
- Starting at 1.
fruit[1]is the second character,v. - Using the length as an index.
fruit[fruit.length]is one past the end and throws. - Using parentheses.
fruit(0)is not valid; indexing uses square brackets. - Mixing up
'a'and"a". Single quotes make aCharand double quotes make aString, and the two are not interchangeable.
Key takeaways
- Indexes start at 0, and spaces have indexes too.
text[i]gives aChar.- The last index is
length - 1, also available aslastIndex;last()returns the last character directly. - An index out of range throws an exception, and strings can't be modified by index.