Strings revisited: the strings package
You have been using strings.ToUpper and strings.ToLower since the Packages lesson. They come from the strings package, Go's standard-library toolbox for everyday string manipulation. This lesson tours the ten or so operations you will reach for constantly.
Case transformation
strings.ToUpper("hello") // "HELLO"
strings.ToLower("HELLO") // "hello"
The rest of this lesson covers the operations you have not met yet.
Contains, HasPrefix, HasSuffix
Three boolean checks for "is this piece in the string":
strings.Contains("hello world", "world") // true
strings.Contains("hello world", "goodbye") // false
strings.HasPrefix("main.go", "main") // true
strings.HasSuffix("main.go", ".go") // true
Contains looks anywhere; HasPrefix and HasSuffix are specific to the start and the end. File-extension and URL-scheme checks usually reach for one of the last two.
TrimSpace (and friends)
Strip leading and trailing whitespace:
strings.TrimSpace(" hello \n") // "hello"
The strings package has more surgical trims (TrimLeft, TrimRight, Trim, TrimPrefix, TrimSuffix) when you need to strip a specific string or set of characters. For the everyday "clean up user input" case, TrimSpace is enough.
Split, Join, Fields
Split a string into pieces, glue pieces back together, or split on any whitespace:
parts := strings.Split("a,b,c", ",") // ["a", "b", "c"]
joined := strings.Join(parts, " | ") // "a | b | c"
Split returns a []string of pieces. Join does the reverse: takes a slice and a separator, returns a string. Use them as a pair when you want to normalise or transform separators.
strings.Fields(" hello world foo") // ["hello", "world", "foo"]
Fields is a specialised Split that treats any run of whitespace as a single separator and drops leading/trailing whitespace. That is what you want for tokenising a line of free-form text, because you do not have to filter empty strings out of the result.
Replace and ReplaceAll
Replace occurrences of a substring:
strings.ReplaceAll("banana", "a", "o") // "bonono"
strings.Replace("banana", "a", "o", 2) // "bonona" (only the first 2)
ReplaceAll replaces every occurrence. Replace takes a count if you want to cap it; a negative count also means "replace all".
Count
How many times does a substring appear:
strings.Count("banana", "a") // 3
strings.Count("banana", "na") // 2
Handy for quick stats on a piece of text.
A small pipeline
Here is one program that chains several of the operations above. It lowercases a line, splits it into tokens on whitespace, and counts how many tokens start with the letter g:
line := "Go is great, Rust is fast, Generics help"
lower := strings.ToLower(line)
tokens := strings.Fields(lower)
goish := 0
for _, t := range tokens {
if strings.HasPrefix(t, "g") {
goish++
}
}
fmt.Println(goish) // 3 (go, great, generics)
Each step does one small thing; the complexity is in how the steps combine, not in any single function.
Starter declares sentence := "The quick brown fox jumps over the lazy dog". In main:
- Split
sentenceinto words withstrings.Fields. Print the number of words (the length of the resulting slice). - Print the sentence lowercased with
strings.ToLower. - Print the result of
strings.Contains(sentence, "fox").fmt.Printlnwill print it astrueorfalse.
Expected output:
9
the quick brown fox jumps over the lazy dog
true
9 the quick brown fox jumps over the lazy dog true