Golang Refresher :: fmt & strings
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:
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.
Print and Println
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: | |
---|---|
%v | the value in a default format. when printing structs, the plus flag (%+v) adds field names |
%#v | a Go-syntax representation of the value |
%T | a Go-syntax representation of the type of the value |
%% | a literal percent sign; consumes no value |
Boolean: | |
---|---|
%t | the word true or false |
Integer: | |
---|---|
%b | base 2 |
%c | the character represented by the corresponding Unicode code point |
%d | base 10 |
%o | base 8 |
%O | base 8 with 0o prefix |
%q | a single-quoted character literal safely escaped with Go syntax. |
%x | base 16, with lower-case letters for a-f |
%X | base 16, with upper-case letters for A-F |
%U | Unicode format: U+1234; same as "U+%04X" |
Floating-point and complex constituents: | |
---|---|
%b | decimalless scientific notation with exponent a power of two, in the manner of strconv.FormatFloat with the 'b' format, e.g. -123456p-78 |
%e | scientific notation, e.g. -1.234456e+78 |
%E | scientific notation, e.g. -1.234456E+78 |
%f | decimal point but no exponent, e.g. 123.456 |
%F | synonym for %f |
%g | %e for large exponents, %f otherwise. Precision is discussed below. |
%G | %E for large exponents, %F otherwise |
%x | hexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20 |
%X | upper-case hexadecimal notation, e.g. -0X1.23ABCP+20 |
String and slice of bytes (treated equivalently with these verbs): | |
---|---|
%s | the uninterpreted bytes of the string or slice |
%q | a double-quoted string safely escaped with Go syntax |
%x | base 16, lower-case, two characters per byte |
%X | base 16, upper-case, two characters per byte |
Slice: | |
---|---|
%p | address of 0th element in base 16 notation, with leading 0x |
Pointer: | |
---|---|
%p | base 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...
strings - Search
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