Split a string in Go: strings.Split, Fields, Cut, and SplitN

Tech reviewed: Deepak Prasad
Split a string in Go: strings.Split, Fields, Cut, and SplitN

If you are searching for golang split string, golang string split, strings split golang, or go split string, the core API is strings.Split from the standard library. Go stores text as UTF-8; splitting follows the rules in package strings. When I put this guide together I ran each listing with go run on Go 1.22 (Linux) so the printed slices here match what you should see locally.

Tested on: Go 1.22 on 64-bit Linux; program listings were executed with the stock go toolchain while this page was revised.

Quick answer: use strings.Split(s, sep). It returns a []string of the parts between each non-overlapping instance of sep.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "red,green,blue"

	parts := strings.Split(text, ",")

	fmt.Println(parts)
}
Output

Output:

text
[red green blue]

Split a String in Go Using strings.Split

Basic strings.Split example

strings.Split(s, sep string) []string returns subslices of s separated by sep. The separator is not included in the elements (unless you switch to SplitAfter).

Split a string by comma, space, or custom separator

Use any non-empty string as sep: comma, |, a multi-character delimiter, and so on. If sep is not in s, you get a one-element slice holding the whole string (see mistakes).

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	fmt.Printf("%q\n", strings.Split("a|b|c", "|"))
	fmt.Printf("%q\n", strings.Split("one two", " "))
}
Output

Split a String by Whitespace

Use strings.Fields for spaces, tabs, and newlines

Many tutorials start with strings.Split(text, " "). That only splits on a single ASCII space, so double spaces create empty strings. For real whitespace (spaces, tabs, newlines), strings.Fields is usually what you want: it splits on runs of characters for which unicode.IsSpace is true, trims leading and trailing space, and merges internal gaps.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "  go   linux\tcloud\nexample  "

	words := strings.Fields(text)

	fmt.Println(words)
}
Output

Output:

text
[go linux cloud example]

Split a String into Limited Parts

Use strings.SplitN to limit the number of results

strings.SplitN is documented to return at most n substrings when n > 0; the last element holds anything that was not split yet. That fits values like name=value-with=equals or key=value.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "name=golinuxcloud=linux"

	parts := strings.SplitN(text, "=", 2)

	fmt.Println(parts)
}
Output

Output:

text
[name golinuxcloud=linux]

The official docs also steer you toward strings.Cut when you only need the first separator.

Split only at the first separator using strings.Cut

strings.Cut splits s at the first instance of sep, returning before, after, and found. There is no slice allocation for the two-part case.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "USER=deepak"

	key, value, found := strings.Cut(text, "=")

	fmt.Println("found:", found)
	fmt.Println("key:", key)
	fmt.Println("value:", value)
}
Output

Output:

text
found: true
key: USER
value: deepak

Split and Clean the Result

Remove empty values after splitting

After Split, you may want to drop empty strings (for example from trailing commas).

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "go,,linux,,cloud"

	raw := strings.Split(text, ",")

	var cleaned []string
	for _, item := range raw {
		if item != "" {
			cleaned = append(cleaned, item)
		}
	}

	fmt.Println(cleaned)
}
Output

Output:

text
[go linux cloud]

Trim spaces from split values

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	text := "go, linux, cloud"

	raw := strings.Split(text, ",")

	for i, item := range raw {
		raw[i] = strings.TrimSpace(item)
	}

	fmt.Println(raw)
}
Output

Output:

text
[go linux cloud]

To join again, use strings.Join.


Split Strings in Common Scenarios

Split CSV-like comma-separated values

For a simple line with no quoted commas, Split is fine:

go
line := "alice,bob,carol"
cols := strings.Split(line, ",")

Split file paths, URLs, and key-value pairs

go
pathname := "/var/log/nginx/access.log"
segments := strings.Split(pathname, "/") // leading "/" produces an empty first element

u := "https://example.com:8443/v1/api"
scheme, rest, ok := strings.Cut(u, "://")

hostPort, pathOnly, _ := strings.Cut(rest, "/")

kv := "theme=dark"
key, val, _ := strings.Cut(kv, "=")

For real path logic, path/filepath is often safer than manual splitting.

Split environment variables like PATH

PATH uses the OS list separator; on Unix it is :. Split on that rune as a string:

go
pathEnv := "/usr/bin:/bin"
dirs := strings.Split(pathEnv, ":")

On Windows, use filepath.SplitList so you respect the platform separator.

Split host:port-like strings

go
addr := "db.internal:5432"
host, port, ok := strings.Cut(addr, ":")

Split command output into lines

go
out := "line one\nline two\n"
lines := strings.Split(strings.TrimSuffix(out, "\n"), "\n")

Or use bufio.Scanner for streaming.

Split log lines into fields

Use Fields when columns are whitespace-separated; use Split or SplitN when you have a fixed delimiter.

Split file extensions or path-like strings

strings.Split("archive.tar.gz", ".") yields ["archive", "tar", "gz"]. If you only care about the suffix after the last dot, strings.LastIndex or path/filepath.Ext is usually clearer than splitting the whole name.

Split only the first separator

Prefer Cut for two-part splits; use SplitN(..., 2) when you specifically want a slice with the remainder in the last slot.


strings.Split vs strings.SplitN

Split keeps splitting until the end. SplitN stops after n-1 separators so you get at most n pieces.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "a,b,c,d"
	fmt.Printf("%q\n", strings.Split(s, ","))
	fmt.Printf("%q\n", strings.SplitN(s, ",", 3))
}
Output

Output:

text
["a" "b" "c" "d"]
["a" "b" "c,d"]

strings.Split vs strings.Fields

Split uses an exact sep string. Fields uses Unicode space rules and never emits empty tokens between spaces.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "  hello   world  "
	fmt.Printf("%q\n", strings.Split(s, " "))
	fmt.Printf("%q\n", strings.Fields(s))
}
Output

Output:

text
["" "" "hello" "" "" "world" "" ""]
["hello" "world"]

strings.Split vs strings.Cut

Cut handles only the first separator and returns two strings plus found. Split always returns a slice and scans the whole string.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "key=value=extra"
	before, after, ok := strings.Cut(s, "=")
	fmt.Println("Cut:", before, after, ok)
	fmt.Printf("%q\n", strings.Split(s, "="))
}
Output

Output:

text
Cut: key value=extra true
["key" "value" "extra"]

strings.Split vs regexp.Split

regexp.Split cuts where a pattern matches—for example multiple spaces or mixed delimiters. The n parameter behaves as documented: negative means no limit, zero returns nil, positive caps substrings with the rest in the last element.

go
package main

import (
	"fmt"
	"regexp"
	"strings"
)

func main() {
	s := "  hello   world  "
	re := regexp.MustCompile(`\s+`)
	fmt.Printf("%q\n", strings.Split(s, " "))
	fmt.Printf("%q\n", re.Split(s, -1))
}
Output

Output:

text
["" "" "hello" "" "" "world" "" ""]
["" "hello" "world" ""]

When the delimiter is fixed text, strings.Split is simpler and faster than compiling a regex.

strings.FieldsFunc

strings.FieldsFunc sits between plain Fields and a regex: split where a function of rune returns true (for example “any digit”).

go
package main

import (
	"fmt"
	"strings"
	"unicode"
)

func main() {
	s := "a1b2c3"
	fmt.Printf("%q\n", strings.FieldsFunc(s, unicode.IsDigit))
}
Output

Output:

text
["a" "b" "c"]

strings.SplitAfter

strings.SplitAfter keeps the separator on the left segment, which helps when the delimiter is part of the field text you want to preserve.

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	fmt.Printf("%q\n", strings.SplitAfter("red,green,", ","))
}
Output

Output:

text
["red," "green," ""]

Common Mistakes with strings.Split

Separator not found returns a slice with one item

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	parts := strings.Split("golinuxcloud", ",")

	fmt.Println(parts)
	fmt.Println(len(parts))
}
Output

Output:

text
[golinuxcloud]
1

Split does not return an empty slice when the separator is missing; you get the original string as the only element.

Empty separator splits by UTF-8 sequence

go
package main

import (
	"fmt"
	"strings"
)

func main() {
	parts := strings.Split("go", "")

	fmt.Println(parts)
}
Output

Output:

text
[g o]

strings.Split is not a CSV parser

This looks tempting:

go
line := `alice,"linux,cloud",admin`
parts := strings.Split(line, ",")

Quoted commas break the model. For real CSV, use encoding/csv with a Reader.


Go String Split Cheat Sheet

Which split function should you use?

Goal Use Example
Split by comma or custom separator strings.Split strings.Split(s, ",")
Split by whitespace strings.Fields strings.Fields(s)
Split into limited parts strings.SplitN strings.SplitN(s, ":", 2)
Split only once strings.Cut before, after, found := strings.Cut(s, "=")
Keep separator after each part strings.SplitAfter strings.SplitAfter(s, ",")
Split using regex regexp.Split re.Split(s, -1)
Trim spaces after split strings.TrimSpace Per element in a loop
Join split values again strings.Join strings.Join(parts, ",")

References


Frequently Asked Questions

1. What is the difference between strings.Split and strings.SplitAfter?

Split removes the separator from the result; SplitAfter keeps each separator attached to the substring before it.

2. What does strings.Split(s, "") do?

It splits between every UTF-8 code point in valid UTF-8. For rune iteration, range over the string is usually clearer.

3. When should I use strings.Fields instead of strings.Split?

Use Fields when you want any whitespace run as a delimiter with trimming and collapsing; Split with a single space does not do that.

4. When should I use strings.Cut instead of SplitN?

Cut is ideal when you only need to split once on the first separator and want two parts plus a found bool; SplitN is better when you need n-way splitting with the remainder in the last element.

5. How does regexp.Split use its n argument?

n less than zero returns all substrings; n zero returns nil; n positive caps how many substrings, with the remainder in the last element.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops …

  • Deep Learning with TensorFlow
  • Machine Learning with Python
  • Go (programming language)
  • Python (programming language)
  • Java (programming language)
  • MongoDB