最近开始学习GO语言,并做了一些编程练习。有道题要输入带空格的字符串,这在C/C++中很容易实现,但GO中好像并不那么容易。学过C/C++的可能都知道,在C中可以使用gets()函数,在C++可以使用getline()函数来实现输入带空格的字符串。那我们可能要问在GO中有没有类似的函数?答案是否定的。
在GO中除了fmt和os包,我们还可以使用bufio来实现带缓存输入和输出。
我们要怎样读取用户从键盘(控制台)输入的数据?输入是指从键盘或其它标准输入(os.Stdin)读取数据。
使用fmt包里的Scan_或Sscan_系列函数输入
package main
import "fmt"
var (
firstName, lastName string
str1, str2, str3 string
num int
str = "We / love / Go / 1314"
format = "%s / %s / %s / %d"
)
func main() {
fmt.Println("Please input your full name: ")
// 使用Scan输入
fmt.Scan(&firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("Please again input your full name: ")
// 使用Scanln输入
fmt.Scanln(&firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("Please again input your full name: ")
// 使用Scanf输入
fmt.Scanf("%s %s", &firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName)
fmt.Println("From the str we read: ")
// 使用Sscanf读取
fmt.Sscanf(str, format, &str1, &str2, &str3, &num)
fmt.Println(str1, str2, str3, num)
}
若输入为:
xiao hua
xiao ming
xiao hong
则输出为:
Please input your full name:
xiao hua
Hi xiao hua!
Please again input your full name:
xiao ming
Hi xiao ming!
Please again input your full name:
xiao hong
Hi xiao hong!
From the str we read:
We love Go 1314
Scan()函数原型为:
func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
}
Scan从标准输入扫描文本,将成功读取的空白分隔的值保存进成功传递给本函数的参数。换行视为空白。返回成功扫描的条目个数和遇到的任何错误。如果读取的条目比提供的参数少,会返回一个错误报告原因。
Scanln()函数原型为:
func Scanln(a ...interface{}) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
Scanln类似于Scan,但会在换行符处停止扫描,在最后一个条目后必须有换行符或EOF。
Scanf()函数原型为:
func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
Scanf从标准输入扫描文本,根据format参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数。返回成功扫描的条目个数和遇到的任何错误。
输入中的换行符必须与格式中的换行符匹配。
Sscanf()函数原型为:
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf((*stringReader)(&str), format, a...)
}
Sscanf从字符串str扫描文本,根据format参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数。返回成功扫描的条目个数和遇到的任何错误。
输入中的换行符必须与格式中的换行符匹配。
Scan与Scanln方法的区别:
- Scan函数会识别空格左右的内容,哪怕换行符存在也不会影响Scan对内容的获取。
- Scanln函数会识别空格左右的内容,但是一旦遇到换行符就会立即结束,不论后续还是否存在需要输入的内容。
使用bufio包里带缓冲的Reader实现带空格字符串的输入
package main
import (
"bufio"
"fmt"
"os"
)
//var inputReader *bufio.Reader
//var input string
//var err error
func main() {
inputReader := bufio.NewReader(os.Stdin) // 使用了自动类型推导,不需要var关键字声明
//inputReader = bufio.NewReader(os.Stdin)
fmt.Println("Please input your name: ")
//input, err = inputReader.ReadString('\n')
input, err := inputReader.ReadString('\n')
if err == nil {
fmt.Printf("Your name is: %s\n", input)
}
}
若输入为:
xiao hua
则输出为:
Please input your name:
xiao hua
Your name is: xiao hua
上例中,inputReader是个指针,它指向一个bufio类的Reader,然后在main函数里,通过bufio.NewReader(os.Stdin)
创建了一个buffer Reader,并联接到inputReader这个变量。
bufio.NewReader()函数原型为:
func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}
任何符合io.Reader接口的对象法都可以作为bufio.NewReader()里的参数,并返回一个新的带缓冲的io.Reader,os.Stdin符合这个条件。这个带缓冲的Reader有一个方法ReadString(delim byte), 这个方法会一直读数据,直到遇到了指定的终止符(delim byte)才结束输入,终止符将成为输入的一部分,一起放到buffer里。
RearString()函数原型为:
func (b *Reader) ReadString(delim byte) (string, error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err
}
ReadString返回值是读到的字符串及nil。如果在读到结束时没有发现指定的结束符(delim byte),将返回一个 err != nil。在上面的例子中,我们从键盘输入直到键入“\n”才结束。屏幕是标准输出os.Stdout,错误信息被写到os.Stderr。大多情况下,os.Stderr等同os.Stdout。
一般情况下,在GO的代码里省略了变量声明,而直接使用”:=“进行自动类型推导,如:
inputReader := bufio.NewReader(os.Stdin)
input, err := inputReader.ReadString('\n')
总结
GO中Scan_或Sscan_系列函数与C中的scan_系统函数的用法相似,学过C的人可以很快学会这些函数的使用。但要实现带空格字符串的输入,则要使用bufio包里带缓冲的Reader和os包里的os.Stdin。
个人主页: