stringstrconvfmtbufio

1. 字符串操作

对字符串的操作无论在什么语言里都是很重要的,因此在基本数据类型中介绍过字符串之后,这里仍然专门拿出一篇来介绍关于字符串的处理。

+
1
2
3
4
5
s := "hel" + "lo,"
s += "world!"
fmt.Println(s) 
//Output: 
//hello, world!
+stringsstrconv

1.1 判断包含关系

HasPrefixsprefix
1
strings.HasPrefix(s, prefix string) bool
HasSuffixssuffix
1
strings.HasSuffix(s, suffix string) bool

示例如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import (
	"fmt"
	"strings"
)

func main() {
	var str string = "This is an example of a string"
	fmt.Printf("T/F? Does the string \"%s\" have prefix %s? ", str, "Th")
	fmt.Printf("%t\n", strings.HasPrefix(str, "Th"))
}
//Output:
//T/F? Does the string "This is an example of a string" have prefix Th? true
Containsssubstr
1
strings.Contains(s, substr string) bool

1.2 获取子字符串的位置

Indexstrsstrsstr
1
strings.Index(s, str string) int
LastIndexstrsstrsstr
1
strings.LastIndex(s, str string) int

如果需要查询非 ASCII 编码的字符在父字符串中的位置,使用以下函数来对字符进行定位:

1
strings.IndexRune(s string, r rune) int

示例如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"fmt"
	"strings"
)

func main() {
	var str string = "Hi, I'm Marc, Hi."

	fmt.Printf("The position of \"Marc\" is: ")
	fmt.Printf("%d\n", strings.Index(str, "Marc"))

	fmt.Printf("The position of the first instance of \"Hi\" is: ")
	fmt.Printf("%d\n", strings.Index(str, "Hi"))
	fmt.Printf("The position of the last instance of \"Hi\" is: ")
	fmt.Printf("%d\n", strings.LastIndex(str, "Hi"))

	fmt.Printf("The position of \"Burger\" is: ")
	fmt.Printf("%d\n", strings.Index(str, "Burger"))
}
/*Output:
The position of "Marc" is: 8
The position of the first instance of "Hi" is: 0
The position of the last instance of "Hi" is: 14
The position of "Burger" is: -1
*/

1.3 统计出现次数

Countstrs
1
strings.Count(s, str string) int

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"fmt"
	"strings"
)

func main() {
	var str string = "Hello, how is it going, Hugo?"
	var manyG = "gggggggggg"

	fmt.Printf("Number of H's in %s is: ", str)
	fmt.Printf("%d\n", strings.Count(str, "H"))

	fmt.Printf("Number of double g's in %s is: ", manyG)
	fmt.Printf("%d\n", strings.Count(manyG, "gg"))
}
/*Output:
Number of H's in Hello, how is it going, Hugo? is: 2
Number of double g’s in gggggggggg is: 5
*/

1.4 替换与重复

Replacestrnoldnewn = -1oldnew
1
strings.Replace(str, old, new, n) string
Repeatcounts
1
strings.Repeat(s, count int) string

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
	"strings"
)

func main() {
	var origS string = "Hi there! "
	var newS string

	newS = strings.Repeat(origS, 3)
	fmt.Printf("The new repeated string is: %s\n", newS)
}
//Output:
//The new repeated string is: Hi there! Hi there! Hi there!

1.5 大小写转换

ToLower
1
strings.ToLower(s) string
ToUpper
1
strings.ToUpper(s) string

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"fmt"
	"strings"
)

func main() {
	var orig string = "Hey, how are you George?"
	var lower string
	var upper string

	fmt.Printf("The original string is: %s\n", orig)
	lower = strings.ToLower(orig)
	fmt.Printf("The lowercase string is: %s\n", lower)
	upper = strings.ToUpper(orig)
	fmt.Printf("The uppercase string is: %s\n", upper)
}
/*Output:
The original string is: Hey, how are you George?
The lowercase string is: hey, how are you george?
The uppercase string is: HEY, HOW ARE YOU GEORGE?
*/

1.6 修剪与分割

strings.TrimSpace(s)
strings.Trim(s, "cut")cut
TrimLeftTrimRight
strings.Fields(s)
strings.Split(s, sep)

因为这 2 个函数都会返回 slice,所以习惯使用 for-range 循环来对其进行处理

1.7 拼接

Join
1
strings.Join(sl []string, sep string) string

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
	"fmt"
	"strings"
)

func main() {
	str := "The quick brown fox jumps over the lazy dog"
	sl := strings.Fields(str)
	fmt.Printf("Splitted in slice: %v\n", sl)
	for _, val := range sl {
		fmt.Printf("%s - ", val)
	}
	fmt.Println()
	str2 := "GO1|The ABC of Go|25"
	sl2 := strings.Split(str2, "|")
	fmt.Printf("Splitted in slice: %v\n", sl2)
	for _, val := range sl2 {
		fmt.Printf("%s - ", val)
	}
	fmt.Println()
	str3 := strings.Join(sl2,";")
	fmt.Printf("sl2 joined by ;: %s\n", str3)
}
/*Output:
Splitted in slice: [The quick brown fox jumps over the lazy dog]
The - quick - brown - fox - jumps - over - the - lazy - dog -
Splitted in slice: [GO1 The ABC of Go 25]
GO1 - The ABC of Go - 25 -
sl2 joined by ;: GO1;The ABC of Go;25
*/

2. 输入输出

编写程序进行数据的读写必不可少,一般会用到fmt, os和bufio三个包,下面对一些读写方式进行总结。

2.1 读取用户输入

用户输入来自三种:标准输入,字符串,io.Reader类型

来自标准输入

读取用户输入一般指的是读取用户的键盘(控制台)输入,定义为标准输入os.Stdin,最常用的方法是使用fmt包提供的Scan开头的函数。

1
2
3
func Scan(a ...interface{}) (n int, err error)
func Scanf(format string, a ...interface{}) (n int, err error)
func Scanln(a ...interface{}) (n int, err error)

Scan从标准输入扫描文本,将成功读取的空白分隔的值传递给函数的参数。换行视为空白。返回成功扫描的条目个数和遇到的任何错误。如果读取的条目比提供的参数少,会返回一个错误报告原因。

Scanf从标准输入扫描文本,根据format 参数指定的格式将成功读取的空白分隔的值传递给函数的参数。返回成功扫描的条目个数和遇到的任何错误。

Scanln类似Scan,但会在换行时才停止扫描。最后一个条目后必须有换行或者到达结束位置。

一个示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main
import "fmt"

var firstName, lastName string

func main() {
   fmt.Println("Please enter your full name: ")
   fmt.Scanln(&firstName, &lastName)
   // fmt.Scanf("%s %s", &firstName, &lastName)
}

来自字符串

读取来自字符串的输入一般使用fmt包中SScan开头的函数

1
2
3
func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)

SScan开头的函数基本和Scan相似,唯一的不同是多了第一个参数str,代表从字符串str扫描文本。一个示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import "fmt"

func main() {
	var name string
	var age int
	n, err := fmt.Sscanf("Kim is 22 years old", "%s is %d years old", &name, &age)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%d: %s, %d\n", n, name, age)

}
//Output
2: Kim, 22

来自io.Reader类型

主要是使用Fscan开头的函数

1
2
3
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)

同样,与Scan的不同是第一个参数r是io.Reader类型,示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"fmt"
	"os"
	"strings"
)

func main() {
	var (
		i int
		b bool
		s string
	)
	r := strings.NewReader("5 true gophers") //返回一个io.Reader类型
	n, err := fmt.Fscanf(r, "%d %t %s", &i, &b, &s)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fscanf: %v\n", err)
	}
	fmt.Println(i, b, s)
	fmt.Println(n)
}

5 true gophers
3

2.2 输出指定内容

输出和读取输入基本是是相反的,各函数原型如下:

1
2
3
4
5
6
7
8
9
func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)

示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"fmt"
	"io"
	"os"
)


func main() {
	const name, age = "Kim", 22
	fmt.Printf("%s is %d years old.\n", name, age)
    
	s := fmt.Sprintf("%s is %d years old.\n", name, age)
	io.WriteString(os.Stdout, s) // Ignoring error for simplicity.
	
    n, err := fmt.Fprintf(os.Stdout, "%s is %d years old.\n", name, age)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fprintf: %v\n", err)
	}
	fmt.Printf("%d bytes written.\n", n)
}
//Output
Kim is 22 years old.
Kim is 22 years old.
Kim is 22 years old.
21 bytes written.

2.3 使用bufio包

使用fmt进行读写,读写次数比较多时,时间耗费极大。go提供了一个bufio包,使用该包可以大幅提高文件读写效率。

bufio包原理

介绍来自茹姐-GO语言基础进阶教程:bufio包。io操作本身的效率并不低,低的是频繁的访问本地磁盘的文件。所以bufio就提供了缓冲区(分配一块内存),读和写都先在缓冲区中,最后再读写文件,来降低访问本地磁盘的次数,从而提高效率。

https://pic3.zhimg.com/80/v2-eafcc5129ec4afd2ed89cecc5824c57e_hd.jpg

读入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main
import (
    "fmt"
    "bufio"
    "os"
)

func main() {
    inputReader := bufio.NewReader(os.Stdin)
    fmt.Println("Please enter some input: ")
    input, err := inputReader.ReadString('\n')
    if err == nil {
        fmt.Printf("The input was: %s\n", input)
    }
}

bufio.NewReader()func NewReader(rd io.Reader) *Reader
inputReaderbufio.ReaderinputReader := bufio.NewReader(os.Stdin)ReadString(delim byte)delimdelim

写出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

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

func main() { 
     w1 := bufio.NewWriter(os.Stdout)

     for i:=1;i<=1000;i++{
        w1.WriteString(fmt.Sprintf("%d:hello",i))
     }
     w1.Flush()
}

2.4 文件读写

主要是使用os.Open函数打开文件,以及defer关键字和close方法在程序结束时关闭文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

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

func main() {
    inputFile, inputError := os.Open("input.dat")
    if inputError != nil {
        fmt.Printf("An error occurred on opening the inputfile\n" +
            "Does the file exist?\n" +
            "Have you got acces to it?\n")
        return // exit the function on error
    }
    defer inputFile.Close()

    inputReader := bufio.NewReader(inputFile)
    for {
        inputString, readerError := inputReader.ReadString('\n')
        fmt.Printf("The input was: %s", inputString)
        if readerError == io.EOF {
            return
        }      
    }
}

未完待续…