Finding where a substring starts
To locate text inside a string, call indexOf. It returns the index of the first character of the first match, counting from 0, or -1 when the text isn't there:
val sentence = "Hello World"
println(sentence.indexOf("World")) // 6
println(sentence.indexOf("xyz")) // -1
"World" starts at the W, which is index 6 because Hello takes indexes 0 to 4 and the space is index 5. Like every Scala String method of this kind, indexOf comes from Java, so it works the same on the JVM.
The variants
s.indexOf(sub)finds the first occurrence.s.lastIndexOf(sub)finds the last occurrence.s.indexOf(sub, from)starts searching at indexfrom.- The argument can also be a single
Char, such ass.indexOf('W').
With a string that repeats a letter, the difference is easy to see:
val s = "Hello World"
println(s.indexOf("o")) // 4
println(s.indexOf("o", 5)) // 7
println(s.lastIndexOf("o")) // 7
The first o is at index 4. Starting the search at index 5 skips it and finds the second one at 7, which is also what lastIndexOf returns.
The exercise, step by step
The lesson gives you val sentence = "Hello World" and asks for the position of "World":
- Declare a new
valnamedidxbelow the sentence. - Assign it the result of
sentence.indexOf("World"). The method returns anInt, soidxis anIntand holds 6.
val sentence = "Hello World"
val idx = sentence.indexOf("World")
Gotchas
- Case matters.
"Hello World".indexOf("world")is-1. To ignore case, convert both sides first, for examplesentence.toLowerCase.indexOf("world"), which gives 6. - Check for -1.
-1is a normal return value, not an error. If you use it as an index, as ins.substring(s.indexOf("x")), you get an exception instead of a clean "not found". - Only the start is returned. To get the matched text you need the length of the match as well, for example
s.substring(i, i + sub.length). - Empty search text.
"Hello".indexOf("")is 0, because the empty string matches at the very start. - Just a yes or no. If you only need to know whether the text occurs,
s.contains("World")returns aBooleanand reads better than comparing with-1.
Using the index
An index from indexOf is a normal string index, so it combines with substring to cut text around a match:
val space = sentence.indexOf(" ")
println(sentence.substring(0, space)) // Hello
println(sentence.substring(space + 1)) // World
Finding every occurrence
A single call finds only one match. To find all of them, use the from argument and restart just past each hit. In "Hello World", the letter l appears at indexes 2, 3 and 9. s.indexOf("l") gives 2, s.indexOf("l", 3) gives 3, and s.indexOf("l", 4) gives 9. A loop repeats this until the result is -1, which signals that no more matches remain. If from is past the end of the string, the answer is simply -1.
Searching works on characters of any kind, including spaces, so s.indexOf(" ") is a quick way to find the end of a first word.
Reading the result
The return value carries two kinds of information. A number from 0 upward is a position. The special value -1 means "absent", and it can never be a real index, which is why Java chose it. A typical guard looks like if (idx != -1) ... else ..., or if (idx >= 0). For the lesson's sentence the guard passes, because 6 is a valid index.
Key takeaways
indexOfreturns the first matching index, or-1.lastIndexOfsearches for the last match, and the second argument ofindexOfsets where to start.- Searches are case-sensitive.
- Always handle the
-1result before using the index.
