The most useful string functions in GO
The concept of a string exists in all languages and Golang is not the exception.
In this blog, I’m going to show the most useful concepts and functions to work with strings in Golang.
Most of the examples will contain tests, you may be more used to using the Assert keyword to perform checking, but the authors of The Go Programming Language make some good arguments for Go’s style over Assertions
Data type
In Golang, String is a data type, it is not a struct or class. It does not have methods or functions.
Slice of bytes
Different from other languages such as Java, in Golang the strings are not an array of characters, instead, they are an array of bytes that represent UTF-8 encodings. That means you are able to use any kind of human language by default. I am going to show the differences
func TestStringSliceBytesUTF8(t *testing.T) {
got := "Hello 世界 🦊"
expected := "\x48\x65\x6c\x6c\x6f\x20\xe4\xb8\x96\xe7\x95\x8c\x20\xf0\x9f\xa6\x8a"
if got != expected {
t.Errorf("expected %s got %s", expected, got)
}
}
Immutable
The main difference between string and slice of bytes in GO is the way they are handled in memory. Strings are immutable, you are not able to modify them. If you want to add a new element, you have to create another string.
Package strings
String has no methods to split or get the length, instead, Golang gives up the strings package to manipulate
Golang initializing strings
Basically, you have two ways to create a string.
From string literal
func TestStringLiteral(t *testing.T) { got := "Go is Awesome!" if got != "Go is Awesome!" { t.Errorf("expected %s got %s", "Go is Awesome!", got) } }
From string multiline
func TestStringMultiline(t *testing.T) { got := ` { "state":"Awesome", "data":[ { "language":"Go" } ] }` expect := "\n" + "\t{\n" + "\t\t\"state\":\"Awesome\",\n" + "\t\t\"data\":[\n" + "\t\t {\n" + "\t\t\t \"language\":\"Go\"\n" + "\t\t }\n" + "\t\t]\n" + "\t }" if got != expect { t.Errorf("expected %s got %s", expect, got) } }
String length
The length of a string can be obtained using the standard function len(s)
func TestStringLength(t *testing.T) { s := "golang" if len(s) != 6 { t.Error("Error", s) } }
It is important to remember that a string is an array of bytes, the function len(s) is going to return the amount of bytes used. So for non-ASCII characters you are going to obtain something like that:
func TestStringLength(t *testing.T) { s := "вишня" if len(s) != 10 { t.Error("Error", len(s)) } s = "🐺🦊🦝" if len(s) != 12 { t.Error("Error", len(s)) } }
Get an element of string
You have to see a string as an array of bytes, so in order to get an element by index do this:
func TestStringElementAt(t *testing.T) { myString := "Go is Awesome!" //at index 0, it is a byte b := myString[0] //convert byte to rune, rune is a character got := rune(b) expect := 'G' if got != expect { t.Errorf("expect %c got %c", expect, b) } }
the result is a byte, you need to convert it to a character using rune type. Here is more information about rune type https://golangbyexample.com/understanding-rune-in-golang/
Iterate over a string
The same, you have to see a string as an array of bytes, simply you are able to iterate it
func TestStringIterationWithRange(t *testing.T) { nameString := "omar barra" for _, v := range namestring { fmt.Printf("%q\n", v) } }
Equal String
Go does not provide a function or method to compare two strings, it is not necessary in golang. You can use the operators == or != directly.
func TestStringEqualsCaseSensitive(t *testing.T) { got := "Go is Awesome!" expect := "Go is Awesome!" if got != expect { t.Errorf("expected %s got %s", expect, got) } if got == "other text" { t.Errorf("expected %s got %s", expect, got) } }
Fortunately, Go offers you a function for case-insensitive equality, which is strings.EqualFold, there we go
func TestStringEqualsCaseInsensitive(t *testing.T) { got := "Go is Awesome!" expect := "go is awesome!" if !strings.EqualFold(got, expect) { t.Errorf("expected %s got %s", expect, got) } }
String concatenation
Simply do this
func TestStringConcat(t *testing.T) { result := "First" + "Second" if result != "FirstSecond" { t.Error("Error", result) } }
Remember you are creating a new string and you are allocating a new portion of memory.
strings.Builder
In some use cases, you have to concatenate a variable list of strings. When you have a variable list of strings the most appropriate way to concatenate is using string.Builder. This structure gives you the function to concatenate strings and avoid wasting memory unnecessarily.
func TestStringBuilder(t *testing.T) { words := []string{"First", "Second", "Third"} var builder strings.Builder for _, w := range words { builder.WriteString(w) } result := builder.String() if result != "FirstSecondThird" { t.Error("Error", result) } }
IsBlank
This function is quite useful and many languages, for example, Java provides one. However, Go does not. Here are two ways to do that
func TestStringIsBlank(t *testing.T) { myString := "\n\n\t\t" //is blank first option if strings.TrimSpace(myString) != "" { t.Error("Error ", myString) } //is blank second option if len(strings.TrimSpace(myString)) != 0 { t.Error("Error ", myString) } }
Removing characters from a string
Sometimes, you need to remove one or more characters from a string. The Go way to do it is:
func TestStringRemovingSpace(t *testing.T) { myString := "I am Programmer" r := strings.Replace(myString, " ", "", -1) if r != "IamProgrammer" { t.Error("Error", r) } }
This function will replace every space in the string with “”.
A most readily way to do it is using strings.ReplaceAll introduced in GO 1.13
func TestStringRemovingSpace(t *testing.T) { myString := "I am Programmer" r := strings.ReplaceAll(myString, " ", "") if r != "IamProgrammer" { t.Error("Error", r) } }
Summing up
Golang’s main goal is to be as simple and powerful as possible. In that way, Go provides the most necessary function to work with string avoiding fancy things such as a function to compare string, function to check string blank.
In this article, I do not cover how to join or split a string, string formatting and other useful functions such as strings.Trim, strings.Prefix, strings.Sufix. but you can find those examples and more in my repository
https://github.com/obarra-dev/poc-golang/blob/master/go-115/string_test.go
Thanks, see you in the next episode.