61 Star 341 Fork 415

infraboard / go-course

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
fmt_in.md 4.87 KB
一键复制 编辑 原始数据 按行查看 历史
Mr.Yu 提交于 2021-06-06 08:42 . 补充作业

字符串格式化

Go语言用于控制文本输入和输出格式的库是fmt

格式化输入

fmt包中提供了3类读取输入的函数:

  • Scan家族:从标准输入os.Stdin中读取数据,包括Scan()、Scanf()、Scanln()
  • SScan家族:从字符串中读取数据,包括Sscan()、Sscanf()、Sscanln()
  • Fscan家族:从io.Reader中读取数据,包括Fscan()、Fscanf()、Fscanln()

其中:

  • Scanln、Sscanln、Fscanln在遇到换行符的时候停止
  • Scan、Sscan、Fscan将换行符当作空格处理
  • Scanf、Sscanf、Fscanf根据给定的format格式读取,就像Printf一样

这3家族的函数都返回读取的记录数量,并会设置报错信息,例如读取的记录数量不足、超出或者类型转换失败等

以下是他们的定义:

go doc fmt | grep -Ei "func [FS]*Scan"
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)
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)
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)

因为还没介绍io.Reader,所以Fscan家族的函数暂且略过,但用法和另外两家族的scan类函数是一样的

Scan家族

Scan家族函数从标准输入读取数据时,以空格做为分隔符分隔标准输入的内容,并将分隔后的各个记录保存到给定的变量中。

Scan

输入数据时可以换行输入,Scan()会将换行符作为空格进行处理,直到读取到了2个记录之后自动终止读取操作

func Scan() {
	fmt.Print("请输入你的姓名和年龄: ")
	fmt.Scan(&name, &age)
	fmt.Printf("姓名: %s 年龄: %d", name, age)
	fmt.Println()
}

注意 只能使用空格作为分隔符, 行号相当于空格

Scanln

使用说明: 遇到换行符或EOF的时候终止读取

例如,使用Scanln函数等待用户输入数据,或从管道中读取数据。下面的代码将等待用户输入,且将读取的内容分别保存到name变量和age变量中:

func Scanln() {
	var (
		name string
		age  uint
	)
	fmt.Print("请输入你的姓名和名字, 以空格分隔: ")
	fmt.Scanln(&name, &age)
	fmt.Printf("姓名: %s 年龄: %d", name, age)
	fmt.Println()
}

因为Scanln()遇到换行符或EOF的时候终止读取,所以在输入的时候只要按下回车键就会结束读取

Scanf

Scanf 和 Scanln一样, 也是遇到换行符或EOF的时候终止读取, 只是Scanf只定了字符串格式,比如

func Scanf() {
	var (
		name string
		age  uint
	)
	fmt.Print("请输入你的姓名和年龄, 以 :分隔: ")
	fmt.Scanf("%s : %d", &name, &age)
	fmt.Printf("姓名: %s 年龄: %d", name, age)
	fmt.Println()
}

总结

由于Scanf可以自定义分隔符和输入格式, 灵活性上优于 其他2个,因此以Scanf使用较多

SScan家族

Sscan家族的函数用于从给定字符串中读取数据,用法和Scan家族类似, 只是输入不再是标准输入了,方便内部使用

Sscan

input := "andy 30"
fmt.Sscan(input, &name, &age)
fmt.Println(name, age)

如果我们多给参数将自动忽略:

input := "andy 30 40"
fmt.Sscan(input, &name, &age)
fmt.Println(name, age)

Scanln

相比于Sscan而已, 我们以行作为结束符, 因此如果我们提前换行,那么这次scan结束

input := "andy \n 30 40"
fmt.Sscanln(input, &name, &age)
fmt.Println(name, age)

Sscanf

和Scanf一样,格式完全自己定义, 灵活性自己把握

input := "andy : 50"
fmt.Sscanf(input, "%s : %d", &name, &age)
fmt.Println(name, age)

返回

我们讲Scan 和 Sscan时都没有处理函数返回, 返回值都是读取的参数的个数和错误

// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why

由于没讲函数,这里可以简单看个例子:

input := "andy : err"
ret, err := fmt.Sscanf(input, "%s : %d", &name, &age)
fmt.Println(ret, err)

扩展

我们刚才从 标准输入中读取了数据用于Scan, 现在我们可以从IO流中读取数据再配合Sscan 就完成了基于网络的Scan

这里采用bufio从标准输入读取数据, 真实案例你可以从Socket读取数据 发送过来

fmt.Print("请输入你的姓名和年龄, 以空格分隔: ")
stdin := bufio.NewReader(os.Stdin)
line, _, err := stdin.ReadLine()
if err != nil {
    panic(err)
}
n, err := fmt.Sscanln(string(line), &name, &age)
if err != nil {
    panic(err)
}
fmt.Printf("read number of items: %d", n)
fmt.Println()
fmt.Printf("姓名: %s 年龄: %d", name, age)
fmt.Println()

作业

Go
1
https://gitee.com/infraboard/go-course.git
git@gitee.com:infraboard/go-course.git
infraboard
go-course
go-course
master

搜索帮助