Start learning free

LESSON 62 OF 338 · STRINGS I

String Find in Go: strings.Index and Friends

Lesson Read the full explanation

In Go, you can find the index of a substring using strings.Index():

strings.Index(s, sub)          // returns index of first occurrence, or -1 if not found
strings.LastIndex(s, sub)      // returns index of last occurrence
strings.Index(s[start:], sub)  // search starting from index `start`

Here are some examples:

sentence := "Hello World"
idx := strings.Index(sentence, "World")
fmt.Println(idx)  // 6

if strings.Index(sentence, "xyz") == -1 {
    fmt.Println("not found")
}

The index returned is the position of the first character of the found substring. Returns -1 if not found.


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


Hint
Use strings.Index(sentence, "World") and assign the result to idx.

STEP 1 OF 1
    Ctrl + Enter to check

    GO · STRINGS I

    String Find in Go, explained

    Finding a substring

    Go strings have no methods, so searching is done with functions from the strings package. strings.Index(s, sub) returns the byte index where sub first appears in s, or -1 if it doesn't appear at all. The index is the position of the first character of the match.

    sentence := "Hello World"
    idx := strings.Index(sentence, "World")
    fmt.Println(idx) // 6
    
    if strings.Index(sentence, "xyz") == -1 {
        fmt.Println("not found")
    }
    

    In "Hello World", the letters of Hello take indexes 0 to 4, the space is at index 5, and World starts at index 6. A Go file that calls strings.Index needs import "strings".

    Exercise step by step

    1. Start from the given variable. sentence already holds "Hello World".
    2. Declare idx with :=. This creates a new variable and gives it the type of the value on the right, which is int.
    3. Call strings.Index(sentence, "World"). The string to search comes first and the text to look for comes second. Mixing up the order searches for the wrong thing.

    The solution in Go

    sentence := "Hello World"
    
    idx := strings.Index(sentence, "World")
    

    After this line, idx is 6.

    Related functions

    The same package has a few more search functions that you will meet often:

    • strings.LastIndex(s, sub) returns the index of the last occurrence. strings.LastIndex("go gopher", "go") is 3, while strings.Index on the same text gives 0.
    • strings.Contains(s, sub) returns a bool. Use it when you only need to know whether the text is there, not where.
    • strings.Index(s[start:], sub) searches from a starting position. The returned index is relative to the slice, so add start to get the position in the original string.
    sentence := "Hello World"
    fmt.Println(strings.Index(sentence[3:], "o")) // 1
    

    The slice sentence[3:] is "lo World", where the first o is at index 1. In the original string it is at index 4, which is 3 + 1.

    Gotchas

    • Test for -1, not for zero. Index 0 is a valid result, meaning the text starts the string. Writing if idx doesn't compile anyway, because Go has no truthiness for numbers. Compare with -1 explicitly.
    • Only the first match. strings.Index stops at the first occurrence. To find every match, loop and search again from after the previous one.
    • Case matters. strings.Index("Hello World", "world") is -1, because w and W differ. Convert both strings with strings.ToLower first for a case-insensitive search.
    • Byte positions. The index counts bytes, not characters. In "héllo", strings.Index("héllo", "l") is 3, because é takes two bytes. For ASCII text the two counts agree.
    • The empty string. Searching for "" returns 0, since an empty string matches at the start of any string.
    • An unused variable is an error. If you declare idx and never use it in a full program, Go refuses to compile. Print it or use it.

    Finding every occurrence

    strings.Index reports only the first match, but you can find all of them by searching again from just after each hit. Because the index of a search on a slice is relative to that slice, add the offset back each time:

    text := "banana"
    start := 0
    for {
        i := strings.Index(text[start:], "an")
        if i == -1 {
            break
        }
        fmt.Println(start + i)
        start += i + 1
    }
    

    This prints the positions of the two matches:

    1
    3
    

    The loop moves start one place past each match, so overlapping matches are found too. Go has no while keyword; a for with no condition runs until break. If you only need the number of matches, strings.Count(text, "an") counts non-overlapping ones directly.

    When you only need a yes or no

    If the position doesn't matter, a boolean function reads better than comparing an index with -1. strings.Contains(s, sub) says whether the text appears anywhere. strings.HasPrefix(s, "Hello") and strings.HasSuffix(s, "World") check only the start or the end of the string, and both are true for "Hello World". Reach for Index when the position itself is what you need, for example to slice the text before or after a match.

    Key takeaways

    • strings.Index(s, sub) returns the byte index of the first match, or -1.
    • strings.LastIndex finds the last match, and strings.Contains answers yes or no.
    • Always compare the result with -1 before using it as an index.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free