Menu

Golang Strings: Split, Join, Contains, Replace and More

Working with strings in Go: the strings package (Split, Join, Contains, Replace, Fields, TrimSpace, ToUpper), building strings efficiently with strings.Builder, multiline raw strings, immutability, and why len counts bytes.

This page includes runnable editors - edit, run, and see output instantly.

A Go string is an immutable sequence of bytes, normally UTF-8 text. The operators work on the string itself (+, ==, <, indexing, slicing), and everything else lives in the standard strings package.

Splitting Strings

FunctionSplits onNotes
Split(s, sep)every sepkeeps empty parts; Split("", ",") returns [""], one empty string
SplitN(s, sep, n)at most n partsthe last part holds the rest
SplitAfter(s, sep)every sepkeeps the separator on each part
Fields(s)runs of whitespacenever returns empty parts
FieldsFunc(s, f)characters where f is truecustom separators
Cut(s, sep)the first sep onlyreturns before, after, found (Go 1.18)

The Split("", ",") case catches people: an empty input gives a slice of length 1, not 0. When splitting user input, Fields or a check for s == "" first avoids a phantom empty element.

strings.Cut is the cleanest way to split key=value, user@host and similar pairs. Go 1.24 also added iterator versions, strings.SplitSeq and strings.FieldsSeq, which yield parts one at a time without building a slice.

Searching

FunctionReturns
Contains(s, sub)true if sub appears in s
ContainsAny(s, chars)true if any character of chars appears
HasPrefix(s, p) / HasSuffix(s, p)true if s starts or ends with p
Index(s, sub)byte position of the first match, or -1
LastIndex(s, sub)byte position of the last match, or -1
Count(s, sub)number of non-overlapping matches
EqualFold(a, b)case-insensitive equality

Every search is case-sensitive except EqualFold. To search case-insensitively, lowercase both sides or use EqualFold for whole-string comparisons.

Transforming

One trap: Trim, TrimLeft and TrimRight take a set of characters, not a prefix. strings.TrimLeft("abcab", "ab") removes every leading a and b and returns "cab". To remove an exact prefix or suffix, use TrimPrefix and TrimSuffix.

Concatenation and strings.Builder

+ joins strings, and fmt.Sprintf formats values into one. Both allocate a new string each time, because strings are immutable. That is fine for a handful of operations and slow in a loop, where each += copies everything built so far. Use strings.Builder instead:

A zero strings.Builder is ready to use. It implements io.Writer, so fmt.Fprintf writes into it directly. Call b.Grow(n) first if you know roughly how big the result will be. Do not copy a Builder after writing to it; pass a pointer.

Multiline and Raw Strings

Go has two kinds of string literal:

Double-quoted strings process escapes (\n, \t, \", \\, \u00e9) and must fit on one line. Backquoted raw strings take everything literally, including newlines, which makes them the way to write multiline strings, regular expressions, JSON and Windows paths. A raw string cannot contain a backquote, and carriage returns inside it are dropped. Note that the query above starts with a newline, since the literal begins right after the opening backquote.

Length, Indexing and Substrings

len(s) is the number of bytes. s[i] is a byte, and s[i:j] is a substring by byte positions:

ï and é take two bytes each, so the string is 12 bytes and 10 characters. Slicing by bytes is safe as long as the positions come from strings.Index or similar, which return byte offsets on character boundaries. To take "the first n characters", convert to []rune first. Runes and bytes explains UTF-8 in depth.

Strings Are Immutable

You cannot change a byte in place: s[0] = 'H' is a compile error (cannot assign to s[0] (neither addressable nor a map index expression)). Every function in strings returns a new string. To edit, convert to []byte or []rune, change the slice, and convert back:

b := []byte("hello")
b[0] = 'H'
s := string(b) // "Hello"

Immutability is also why substrings are cheap: s[2:5] shares memory with s instead of copying it. The flip side is that a small substring of a huge string keeps the whole huge string alive. Use strings.Clone (Go 1.20) when you keep a short piece of a large input.

Comparing Strings

== and != compare content, and <, > compare byte by byte, which is alphabetical for ASCII. strings.Compare exists but is rarely needed; slices.Sort on a []string uses <. For locale-aware sorting of non-English text, use golang.org/x/text/collate.

Converting Other Types

Numbers become strings with strconv.Itoa, strconv.FormatFloat or fmt.Sprintf, and strings become numbers with strconv.Atoi and strconv.ParseFloat. Do not write string(42): it produces the character with code point 42, "*". The type conversion page has the full table.

Frequently Asked Questions

How do I split a string in Go?

Use strings.Split(s, sep): strings.Split("a,b,c", ",") returns ["a" "b" "c"]. To split on any run of whitespace and drop empty parts, use strings.Fields(s). strings.SplitN limits the number of parts, and strings.Cut splits once around the first separator.

How do I write a multiline string in Go?

Use a raw string literal in backquotes:

query := `SELECT id, name
FROM users
WHERE active = true`

Everything between the backquotes is taken literally, including newlines and backslashes. A raw string cannot contain a backquote.

How do I check if a string contains a substring in Go?

strings.Contains(s, substr) returns a bool. Related functions: strings.HasPrefix, strings.HasSuffix, strings.Index (position or -1), strings.ContainsAny (any of a set of characters), and strings.EqualFold for case-insensitive equality.

What is the fastest way to concatenate strings in Go?

For a few strings, + is fine. When building a string in a loop, use strings.Builder: call WriteString repeatedly and String() once at the end. Repeated += in a loop copies the whole string each time, so it gets slow as the string grows. To join a slice with a separator, use strings.Join.

Why does len return the wrong length for my string?

len(s) returns the number of bytes, not characters. Go strings are UTF-8, where characters outside ASCII take 2 to 4 bytes, so len("héllo") is 6. Use utf8.RuneCountInString(s) for the number of Unicode code points.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED