这是一个困扰我的问题。当从用户那里获得输入时,我想使用一个循环来要求用户重试,直到他们输入有效的输入:
// user_input.go
package main
import (
"fmt"
)
func main() {
fmt.Println("Please enter an integer: ")
var userI int
for {
_, err := fmt.Scanf("%d", &userI)
if err == nil {
break
}
fmt.Println("Sorry, invalid input. Please enter an integer: ")
}
fmt.Println(userI)
}
运行上述操作,如果用户输入有效输入,则没问题:
请输入一个整数:
3
3
退出代码0,进程正常退出。
但是尝试输入一个字符串呢?
请输入一个整数:
什么?
对不起,输入无效。请输入一个整数:
对不起,输入无效。请输入一个整数:
遗憾... 的
等等,它会逐个字符循环,直到字符串耗尽为止。 即使输入单个字符循环两次,我也会假设它解析换行符。
无论如何,必须有一种方法在Go中冲洗Stdin?
P.S。如果没有这样的功能,您将如何解决它以提供相同的功能?我甚至都失败了......
答案 0 :(得分:4)
我会通过阅读直到每次失败后的行结束来解决这个问题。这将清除文本的其余部分。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
stdin := bufio.NewReader(os.Stdin)
fmt.Println("Please enter an integer: ")
var userI int
for {
_, err := fmt.Fscan(stdin, &userI)
if err == nil {
break
}
stdin.ReadString('\n')
fmt.Println("Sorry, invalid input. Please enter an integer: ")
}
fmt.Println(userI)
}
答案 1 :(得分:2)
唤醒旧问题是不是很糟糕?
我更喜欢使用fmt.Scanln
,因为A)它不需要导入另一个库(例如读者)和B)它不涉及显式的for循环。
func someFunc() {
fmt.Printf("Please enter an integer: ")
// Read in an integer
var i int
_, err := fmt.Scanln(&i)
if err != nil {
fmt.Printf("Error: %s", err.Error())
// If int read fails, read as string and forget
var discard string
fmt.Scanln(&discard)
return
}
fmt.Printf("Input contained %d", i)
}
然而,似乎应该有一个更优雅的解决方案。特别是在fmt.Scanln的情况下,读取在第一个非数字字节之后停止而不是“扫描线”似乎很奇怪。
答案 2 :(得分:1)
我知道这已经得到了回答,但这是我的实施:
func flush (reader *bufio.Reader) {
var i int
for i = 0; i < reader.Buffered(); i++ {
reader.ReadByte()
}
}
这应该适用于所有情况,包括不能使用“stdin.ReadString('\ n')”的情况。
答案 3 :(得分:1)
我遇到了类似的问题,无法获得用户输入但是以稍微不同的方式解决了它。添加到线程以防其他人发现这个有用:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// Get first word from stdin
func getFirstWord() (string) {
input := bufio.NewScanner(os.Stdin)
input.Scan()
ans := strings.Fields(input.Text())
if len(ans) == 0 {
return ""
} else {
return ans[0]
}
}
func main() {
fmt.Printf("Would you like to play a game?\n> ")
ans := getFirstWord()
fmt.Printf("Your answer: %s\n", ans)
}
答案 4 :(得分:0)
很抱歉重新开始这项工作,但我今天遇到了这个问题,希望通过使用新的标准库功能来改进现有的答案。
import (
"bufio"
"fmt"
"os"
)
func discardBuffer(r *bufio.Reader) {
r.Discard(r.Buffered())
}
stdin := bufio.NewReader(os.Stdin)
var i int
for true {
if _, err := fmt.Fscanln(stdin, &i); err != nil {
discardBuffer(stdin)
// Handle error, display message, etc.
continue
}
// Do your other value checks and validations
break
}
基本思想是始终从stdin缓冲读取。扫描时遇到错误,只需丢弃缓冲区内容。这样你就可以开始使用空缓冲区进行下一次扫描。
或者,您可以在扫描之前丢弃缓冲区,因此用户之前的任何杂散输入都不会被拾取。
func fscanln(r *bufio.Reader, a ...interface{}) error {
r.Discard(r.Buffered())
_, err := fmt.Fscanln(r, a...)
return err
}
stdin := bufio.NewReader(os.Stdin)
var i int
if err := fscanln(stdin, &i); err != nil {
// Handle error
}
答案 5 :(得分:0)
我使用这个片段来过滤不必要的前导空格/换行
in := bufio.NewReader(os.Stdin)
result, err = in.ReadString('\n')
for len(strings.TrimSpace(result)) == 0 {
result, err = in.ReadString('\n')
}