Skip to main content

Golang Refresher :: fmt & strings

Guangzhou, China

Environment

Visual Studio Code

Install the Go extension und use the VS Code command line (F1) to go: install/update tools and install everything that is offered:

Go Websockets

The Go Standard Library

fmt :: String formatting and Printing

The fmt Package implements formatted I/O with functions analogous to C's printf and scanf. The format 'verbs' are derived from C's but are simpler.

package main

import "fmt"

func main() {

// Print a string
fmt.Print("a string")

// Print a string with newline
fmt.Println("a string followed by a newline")

// Print string with values
const fortytwo = 42
const answer = "answer"
const everything = "everything"
fmt.Println("The", answer, "to", everything, "is", fortytwo)

// Print a slice
items := []int{33, 66, 99, 666}
length, err := fmt.Println(items)
fmt.Println(length, err)

}

Run the file with:

go run ./main.go

a stringa string followed by a newline
The answer to everything is 42
[33 66 99 666]
15 <nil>

Printf and Sprintf

Print data with the help of formatting verbs - e.g. :

General:
%vthe value in a default format. when printing structs, the plus flag (%+v) adds field names
%#va Go-syntax representation of the value
%Ta Go-syntax representation of the type of the value
%%a literal percent sign; consumes no value
Boolean:
%tthe word true or false
Integer:
%bbase 2
%cthe character represented by the corresponding Unicode code point
%dbase 10
%obase 8
%Obase 8 with 0o prefix
%qa single-quoted character literal safely escaped with Go syntax.
%xbase 16, with lower-case letters for a-f
%Xbase 16, with upper-case letters for A-F
%UUnicode format: U+1234; same as "U+%04X"
Floating-point and complex constituents:
%bdecimalless scientific notation with exponent a power of two, in the manner of strconv.FormatFloat with the 'b' format, e.g. -123456p-78
%escientific notation, e.g. -1.234456e+78
%Escientific notation, e.g. -1.234456E+78
%fdecimal point but no exponent, e.g. 123.456
%Fsynonym for %f
%g%e for large exponents, %f otherwise. Precision is discussed below.
%G%E for large exponents, %F otherwise
%xhexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20
%Xupper-case hexadecimal notation, e.g. -0X1.23ABCP+20
String and slice of bytes (treated equivalently with these verbs):
%sthe uninterpreted bytes of the string or slice
%qa double-quoted string safely escaped with Go syntax
%xbase 16, lower-case, two characters per byte
%Xbase 16, upper-case, two characters per byte
Slice:
%paddress of 0th element in base 16 notation, with leading 0x
Pointer:
%pbase 16 notation, with leading 0x

The %b, %d, %o, %x and %X verbs also work with pointers, formatting the value exactly as if it were an integer.

package main

import "fmt"

type circle struct {
radius int
border int
}

func main() {

x := 26
f := 337.99

// Formatting
// decimal
fmt.Printf("%d\n", x)
// hexadecimal
fmt.Printf("%x\n", x)

// Booleans
fmt.Printf("%t\n", x > 10)

// Floats
fmt.Printf("%f\n", f)
fmt.Printf("%e\n", f)

// Explicit argument indexes
fmt.Printf("%d %d\n", 69, 119)
fmt.Printf("%[2]d %[1]d\n", 69, 119)

// Explicit argument indexes with repeated values
fmt.Printf("%d %d %#[1]o %#[2]x\n", 69, 119)

// Print in default format
c := circle {
radius: 456,
border: 2,
}

fmt.Printf("%v\n", c)
fmt.Printf("%+v\n", c)
fmt.Printf("%T\n", c)

// Use SprintF to return value as string
s := fmt.Sprintf("%d %d", 69, 119)
fmt.Println(s)
fmt.Printf("%T\n", s)

}
go run ./main.go

26
1a
true
337.990000
3.379900e+02
69 119
119 69
69 119 0105 0x77
{456 2}
{radius:456 border:2}
main.circle
69 119
string
package main

import "fmt"

func main() {

f := 997.123

// Decimal precision (e.g. 2 decimal points)
fmt.Printf("%.2f\n", f)

// Max width (e.g. 15 spaces) and default precision (this will just
// add empty spaces in front to make lists look pretty)
fmt.Printf("%15f\n", f)

// Padding and precision
fmt.Printf("%15.2f\n", f)

// Add a character in front, e.g. a `+`
fmt.Printf("%+15.3f\n", f)

// Padding with zeros instead of empty spaces
fmt.Printf("%015.4f\n", f)

}
go run .\formatting.go

997.12
997.123000
997.12
+997.123
0000000997.1230

Stdin

Reading and printing user inputs:

package main

import (
"bufio"
"fmt"
"os"
)

func main() {

reader := bufio.NewReader(os.Stdin)
s, _ := reader.ReadString('\n')
fmt.Println(s)

}
go run .\main.go
hello world
hello world

strings|strconv|unicode :: Manipulating string and text content

Package strings implements simple functions to manipulate UTF-8 encoded strings.

strings - Basics

package main

import (
"fmt"
"strings"
)

func main() {

s:= "This string is never gonna give you up, never gonna let you down..."

// Print length of a string
fmt.Println(len(s))

// Iteration
for _, ch := range s {
fmt.Print(string(ch), "-")
}
fmt.Println()

// Operators
fmt.Println("Sapporro" < "Asahi")
fmt.Println("Tomcat" > "Hornet")
fmt.Println("rick" == "Rick")
fmt.Println("rick" != "Rick")

// Compare
compare_01 := strings.Compare("Sapporro", "Asahi")
fmt.Println(compare_01)
compare_02 := strings.Compare("Sapporro", "Sapporro")
fmt.Println(compare_02)

// Unicode case-folding
fmt.Println(strings.EqualFold("中國", "台灣"))
fmt.Println(strings.EqualFold("台灣", "台灣"))

// Character cases
s1 := strings.ToUpper(s)
s2 := strings.ToLower(s)
s3 := strings.Title(s)
fmt.Println(s1, s2, s3)

}
go run .\main.go

67
T-h-i-s- -s-t-r-i-n-g- -i-s- -n-e-v-e-r- -g-o-n-n-a- -g-i-v-e- -y-o-u- -u-p-,- -n-e-v-e-r- -g-o-n-n-a- -l-e-t- -y-o-u- -d-o-w-n-.-.-.-
false
true
false
true
1
0
false
true
THIS STRING IS NEVER GONNA GIVE YOU UP, NEVER GONNA LET YOU DOWN... this string is never gonna give you up, never gonna let you down... This
String Is Never Gonna Give You Up, Never Gonna Let You Down...
package main

import (
"fmt"
"strings"
)

func main() {

s:= "This string is never gonna give you up, never gonna let you down..."
vowels := "aeiouAEIOU"

fname := "textfile.txt"
fname2 := "imagefile.png"

// Contains a sub-string
fmt.Println(strings.Contains(s, "gonna"))

// ContainsAny of these characters
fmt.Println(strings.ContainsAny(s, "xyzi"))

// Find offset of first instance of substring
fmt.Println(strings.Index(s, "give"))
fmt.Println(strings.Index(s, "rick"))

// Find offset of first instance of any of a set of characters
fmt.Println(strings.IndexAny(s, vowels))
fmt.Println(strings.IndexAny("xyzs", vowels))

// Check if strings starts/ends with a substring
fmt.Println(strings.HasSuffix(fname, "txt"))
fmt.Println(strings.HasPrefix(fname2, "image"))

// Count non-overlapping instances of a substring
fmt.Println(strings.Count(s, "gonna"))
fmt.Println(strings.Count(s, "is"))

}
go run .\main.go
true
true
27
-1
2
-1
true
true
2
2

strings - Manipulations

package main

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

func main() {

s1 := "This string is never gonna give you up"
s2 := []string{"one", "two", "three", "four"}
s3 := "Never gonna give, never gonna give. Give you up!"

// Split into substrings
sub1 := strings.Split(s1, "never")
fmt.Printf("%q\n", sub1)

// Split string around whitespaces
result := strings.Fields(s1)
fmt.Printf("%q\n", result)

// Split around punctuation
f := func(c rune) bool {
return unicode.IsPunct(c)
}
result2 := strings.FieldsFunc(s3, f)
fmt.Printf("%q\n", result2)

// Join substrings
result3 := strings.Join(s2, "-")
fmt.Println(result3)

// Replace substring
rep := strings.NewReplacer(",", " |", ".", " |", "!", " |")
result4 := rep.Replace(s3)
fmt.Println(result4)
}
go run .\main.go

["This string is " " gonna give you up"]
["This" "string" "is" "never" "gonna" "give" "you" "up"]
["Never gonna give" " never gonna give" " Give you up"]
one-two-three-four
Never gonna give | never gonna give | Give you up |

strings - Mapping

package main

import (
"fmt"
"strings"
)

func main() {
// Become a secret agent by encoding your messages
s:= "This string is never gonna give you up, never gonna let you down..."
// As a cypher push every character `+2`
shift := 2

// Mapping function
transform := func (r rune) rune {
switch {

// if character is uppercase
case r >= 'A' && r <= 'Z':
// get ASCII base code of character and add value of `shift`
value := int('A') + (int(r) - int('A') + shift)
// if you hit 91 (which equals 'Z')
if value > 91 {
// subtract 26 to start from the beginning 'A'
value -= 26
// if you hit the lower threshold
} else if value < 65 {
// add 26
value += 26
}
return rune(value)

// if character is lowercase
case r >= 'a' && r <= 'z':
// get base code of character and add value of `shift`
value := int('a') + (int(r) - int('a') + shift)
// if you hit 91 (which equals 'z')
if value > 122 {
// subtract 26 to start from the beginning 'a'
value -= 26
// if you hit the lower threshold
} else if value < 97 {
// add 26
value += 26
}
return rune(value)
}
return r
}

// Encode message
encode := strings.Map(transform, s)
fmt.Println(encode)

// Encode message
shift = -shift
decode := strings.Map(transform, encode)
fmt.Println(decode)

}
go run .\main.go

Vjku uvtkpi ku pgxgt iqppc ikxg aqw wr, pgxgt iqppc ngv aqw fqyp...
This string is never gonna give you up, never gonna let you down...

strings - Builder

package main

import (
"fmt"
"strings"
)

func main() {

var sb strings.Builder

// Provide content
sb.WriteString("This string is never gonna give you up \n")
sb.WriteString("Never gonna let you down \n")
sb.WriteString("Never gonna say goodbye \n")
sb.WriteString("Never gonna tell a lie and hurt you \n")

// Concatenate string
fmt.Println(sb.String())

// Get length of build string
fmt.Println("Builder size:", sb.Len())

// Builder capacity
fmt.Println("Capacity:", sb.Cap())

// Add capacity of 1k to reserve space
sb.Grow(1024)
fmt.Println("Capacity:", sb.Cap())

// Reset content of builder
sb.Reset()
fmt.Println("After reset")
fmt.Println("Capacity:", sb.Cap())
fmt.Println("Builder Size:", sb.Len())
}
go run .\main.go
This string is never gonna give you up
Never gonna let you down
Never gonna say goodbye
Never gonna tell a lie and hurt you

Builder size: 128
Capacity: 192
Capacity: 1408
After reset
Capacity: 0
Builder Size: 0

strconv - Parse

Package strconv implements conversions to and from string representations of basic data types.

package main

import (
"fmt"
"strconv"
)

func main() {

str := "101"
num := 100


// Converting int into string
// The string function does NOT convert an int into a string!
newstr1 := string(str)
fmt.Println("The first string is:", newstr1)
fmt.Printf("%T\n", newstr1)
newstr2 := string(num)
fmt.Println("This is not the string I expected:", newstr2)
fmt.Printf("%T\n", newstr2)
// To transform the int use:
newstr3 := strconv.Itoa(num)
fmt.Println("The second string is:", newstr3)
fmt.Printf("%T\n", newstr3)


// Convert string to int
newstr4, err := strconv.Atoi(str)
if (err != nil) {
fmt.Println(err.Error())
}
fmt.Println("This is now an integer:", newstr4)
fmt.Printf("%T\n", newstr4)


// Parsing strings into different data types
b, _ := strconv.ParseBool("true")
fmt.Println(b)
fmt.Printf("%T\n", b)
f, _ := strconv.ParseFloat("3.14159", 64)
fmt.Println(f)
fmt.Printf("%T\n", f)
i, _ := strconv.ParseInt("-42", 10, 64)
fmt.Println(i)
fmt.Printf("%T\n", i)
u, _ := strconv.ParseUint("42", 10, 64)
fmt.Println(u)
fmt.Printf("%T\n", u)

// Format converts values into strings
s1 := strconv.FormatBool(true)
fmt.Println(s1)
fmt.Printf("%T\n", s1)
s2 := strconv.FormatFloat(3.1415, 'E', -1, 64)
fmt.Println(s2)
fmt.Printf("%T\n", s2)
s3 := strconv.FormatInt(-42, 10)
fmt.Println(s3)
fmt.Printf("%T\n", s3)
s4 := strconv.FormatUint(42, 10)
fmt.Println(s4)
fmt.Printf("%T\n", s4)
}
go run .\main.go

The first string is: 101
string
This is not the string I expected: d
string
The second string is: 100
string
This is now an integer: 101
int
true
bool
3.14159
float64
-42
int64
42
uint64
true
string
3.1415E+00
string
-42
string
42
string

unicode

Package unicode provides data and functions to test some properties of Unicode code points.

package main

import (
"fmt"
"unicode"
)

func main() {

const s = "This 'string' is *never* gonna give you up, *never* gonna let you down..."

punctCount := 0
lowerCount, upperCount := 0, 0
spaceCount := 0
hexdigitCount :=0

// Count unicode characters:
for _, ch := range s {
if unicode.IsPunct(ch) {
punctCount++
}
if unicode.IsLower(ch) {
lowerCount++
}
if unicode.IsUpper(ch) {
upperCount++
}
if unicode.IsSpace(ch) {
spaceCount++
}
if unicode.Is(unicode.Hex_Digit, ch) {
hexdigitCount++
}
}

fmt.Println("Punctuations", punctCount)
fmt.Println("Lower Chars", lowerCount)
fmt.Println("Upper Chars", upperCount)
fmt.Println("Space Chars", spaceCount)
fmt.Println("HexDigital Chars", hexdigitCount)
}
go run .\main.go

Punctuations 10
Lower Chars 50
Upper Chars 1
Space Chars 12
HexDigital Chars 9