Start learning free

LESSON 61 OF 348 · STRINGS I

String Find in Kotlin: indexOf and lastIndexOf

Lesson Read the full explanation

In Java, you can find the index of a substring using indexOf():

s.indexOf(sub)           // returns index of first occurrence, or -1 if not found
s.lastIndexOf(sub)       // returns index of last occurrence
s.indexOf(sub, fromIdx)  // search starting from index `fromIdx`

Here are some examples:

val sentence = "Hello World"
val idx = sentence.indexOf("World")
println(idx)  // 6

println(sentence.indexOf("xyz"))  // -1  (not found)

The index returned is the position of the first character of the found substring.


Assignment
Follow the Coding Tutorial and find the index of "World" in sentence!


Hint
Use sentence.indexOf("World") and assign the result to idx.

STEP 1 OF 1
    Ctrl + Enter to check

    KOTLIN · STRINGS I

    String Find in Kotlin, explained

    Finding text inside a string

    Often you need to know where a piece of text appears in a string. Kotlin strings answer with indexOf, which returns the index of the first character of the first match, or -1 when the text is not there.

    val sentence = "Hello World"
    
    println(sentence.indexOf("World")) // 6
    println(sentence.indexOf("xyz"))   // -1
    

    The match "World" starts at the W, which is at index 6 (Hello takes indexes 0 to 4, the space is 5). The index points to the first character of the match, not the last.

    The value -1 is a signal, not a position. Valid indexes are never negative, so it is safe to use as "not found". Always compare against it before you use the result as an index.

    The three common forms

    val s = "Hello World"
    
    println(s.indexOf("o"))     // 4   first match
    println(s.lastIndexOf("o")) // 7   last match
    println(s.indexOf("o", 5))  // 7   first match at index 5 or later
    
    • indexOf(sub) scans from the start and returns the first match.
    • lastIndexOf(sub) scans from the end and returns the start index of the last match.
    • indexOf(sub, startIndex) begins the search at startIndex. Searching again from the previous match plus one is how you find every occurrence.

    You can search for a single Char as well as a String: s.indexOf('o') gives the same answer as s.indexOf("o").

    Case matters

    The search is case-sensitive by default. The lowercase "world" is not in "Hello World":

    val s = "Hello World"
    
    println(s.indexOf("world"))                    // -1
    println(s.indexOf("world", ignoreCase = true)) // 6
    

    Kotlin's indexOf has an ignoreCase parameter for this. It is a named argument, so write it with its name. Passing it as the second argument without the name would mix it up with the start index.

    The exercise

    The lesson provides a sentence and asks for one new variable:

    1. Decide what to search for. The text is "World", passed as the argument to indexOf.
    2. Store the result. It is an Int, and it never changes afterwards, so it is declared with val and named idx.
            val sentence = "Hello World"
    
            val idx = sentence.indexOf("World")
    

    Kotlin infers the type of idx as Int from the value, so no annotation is needed. Its value is 6.

    Finding every occurrence

    To visit all the matches, search again from just after each one you find. The loop stops when indexOf returns -1:

    val text = "banana"
    var pos = text.indexOf("ana")
    
    while (pos != -1) {
        println(pos)
        pos = text.indexOf("ana", pos + 1)
    }
    

    This prints 1 and then 3. The two matches share the a at index 3, and starting at pos + 1 finds both. Starting at pos + "ana".length would skip the overlapping one. Here pos is a var because it changes on every pass.

    The same loop works for counting matches: add one to a counter on each pass. Keep the loop condition and the update together, so the search always moves forward and cannot repeat the same match forever.

    Using the result safely

    A found index is often used straight away, for example to cut the text after the match with substring. That is where the -1 becomes dangerous: with no match, the next step would receive a negative index. Check first:

    val sentence = "Hello World"
    val idx = sentence.indexOf("World")
    
    if (idx != -1) {
        println(sentence.substring(idx)) // World
    } else {
        println("not found")
    }
    

    If you only need a yes-or-no answer, contains says it more directly: sentence.contains("World") is true. startsWith and endsWith do the same for the two ends of the string.

    Common mistakes

    • Treating -1 as a real index. Passing it on to substring or to [ ] throws an exception.
    • Forgetting the case. A search for "world" fails on "Hello World" unless you ask to ignore case.
    • Expecting the end of the match. The index is where the match starts. The end is idx + sub.length.
    • Expecting every match. indexOf returns only the first one. Use a loop with the start-index form, or lastIndexOf for the final one.
    • Discarding the result. Calling sentence.indexOf("World") without storing or printing it computes the number and throws it away.

    Key takeaways

    • s.indexOf(sub) returns the index of the first match, or -1.
    • s.lastIndexOf(sub) finds the last match; s.indexOf(sub, from) starts the search at from.
    • The search is case-sensitive unless you pass ignoreCase = true.
    • Check for -1 before using the index.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free