The bytes and string packages have a number of useful helpers to work with and convert between strings and byte types. They allow the creation of buffers that work with a number of common I/O interfaces.
Using the bytes and strings packages
Getting ready
Refer to the Getting ready section's steps in the Using the common I/O interfaces recipe.
How to do it...
These steps cover writing and running your application:
- From your terminal/console application, create a new directory called chapter1/bytestrings.
- Navigate to this directory.
- Copy tests from https://github.com/agtorre/go-cookbook/tree/master/chapter1/bytesstrings, or use this as an exercise to write some of your own code!
- Create a file called buffer.go with the following contents:
package bytestrings
import (
"bytes"
"io"
"io/ioutil"
)
// Buffer demonstrates some tricks for initializing bytes
//Buffers
// These buffers implement an io.Reader interface
func Buffer(rawString string) *bytes.Buffer {
// we'll start with a string encoded into raw bytes
rawBytes := []byte(rawString)
// there are a number of ways to create a buffer from
// the raw bytes or from the original string
var b = new(bytes.Buffer)
b.Write(rawBytes)
// alternatively
b = bytes.NewBuffer(rawBytes)
// and avoiding the intial byte array altogether
b = bytes.NewBufferString(rawString)
return b
}
// ToString is an example of taking an io.Reader and consuming
// it all, then returning a string
func toString(r io.Reader) (string, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return "", err
}
return string(b), nil
}
- Create a file called bytes.go with the following contents:
package bytestrings
import (
"bufio"
"bytes"
"fmt"
)
// WorkWithBuffer will make use of the buffer created by the
// Buffer function
func WorkWithBuffer() error {
rawString := "it's easy to encode unicode into a byte
array"
b := Buffer(rawString)
// we can quickly convert a buffer back into byes with
// b.Bytes() or a string with b.String()
fmt.Println(b.String())
// because this is an io Reader we can make use of
// generic io reader functions such as
s, err := toString(b)
if err != nil {
return err
}
fmt.Println(s)
// we can also take our bytes and create a bytes reader
// these readers implement io.Reader, io.ReaderAt,
// io.WriterTo, io.Seeker, io.ByteScanner, and
// io.RuneScanner interfaces
reader := bytes.NewReader([]byte(rawString))
// we can also plug it into a scanner that allows
// buffered reading and tokenzation
scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanWords)
// iterate over all of the scan events
for scanner.Scan() {
fmt.Print(scanner.Text())
}
return nil
}
- Create a file called string.go with the following contents:
package bytestrings
import (
"fmt"
"io"
"os"
"strings"
)
// SearchString shows a number of methods
// for searching a string
func SearchString() {
s := "this is a test"
// returns true because s contains
// the word this
fmt.Println(strings.Contains(s, "this"))
// returns true because s contains the letter a
// would also match if it contained b or c
fmt.Println(strings.ContainsAny(s, "abc"))
// returns true because s starts with this
fmt.Println(strings.HasPrefix(s, "this"))
// returns true because s ends with this
fmt.Println(strings.HasSuffix(s, "test"))
}
// ModifyString modifies a string in a number of ways
func ModifyString() {
s := "simple string"
// prints [simple string]
fmt.Println(strings.Split(s, " "))
// prints "Simple String"
fmt.Println(strings.Title(s))
// prints "simple string"; all trailing and
// leading white space is removed
s = " simple string "
fmt.Println(strings.TrimSpace(s))
}
// StringReader demonstrates how to create
// an io.Reader interface quickly with a string
func StringReader() {
s := "simple stringn"
r := strings.NewReader(s)
// prints s on Stdout
io.Copy(os.Stdout, r)
}
- Create a new directory named example.
- Navigate to example.
- Create a main.go file with the following contents and ensure that you modify the interfaces imported to use the path you set up in step 2:
package main
import "github.com/agtorre/go-cookbook/chapter1/bytestrings"
func main() {
err := bytestrings.WorkWithBuffer()
if err != nil {
panic(err)
}
// each of these print to stdout
bytestrings.SearchString()
bytestrings.ModifyString()
bytestrings.StringReader()
}
- Run go run main.go.
- You may also run these:
go build
./example
You should see the following output:
$ go run main.go
it's easy to encode unicode into a byte array ??
it's easy to encode unicode into a byte array ??
it'seasytoencodeunicodeintoabytearray??true
true
true
true
[simple string]
Simple String
simple string
simple string
- If you copied or wrote your own tests, go up one directory and run go test, and ensure all tests pass.
How it works...
The bytes library provides a number of convenience functions when working with data. A buffer, for example, is far more flexible than an array of bytes when working with stream processing libraries or methods. Once you've created a buffer, it can be used to satisfy an io.Reader interface so you can take advantage of ioutil functions to manipulate the data. For steaming applications, you'd probably want to use a buffer and a scanner. The bufio package comes in handy for these cases. Sometimes, using an array or slice is more appropriate for smaller datasets or when you have a lot of memory on your machine.
Go provides a lot of flexibility in converting between interfaces with these basic types--it's relatively simple to convert between strings and bytes. When working with strings, the strings package provides a number of convenience functions to work with, search, and manipulate strings. In some cases, a good regular expression may be appropriate, but most of the time, the strings and strconv packages are sufficient. The strings package allows you to make a string look like a title, split it into an array, or trim whitespace. It also provides a Reader interface of its own that can be used instead of the bytes package reader type.