2013-02-01 31 views
5

这是当前困扰着我的一个问题。当从用户获取输入,我想使用一个循环来询问用户重试,直到他们进入有效输入:如何在fmt.Scanf()之后刷新Stdin?

// 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)  
} 

运行上面的,如果用户输入有效输入,没有任何问题:

请输入的整数:


退出代码0,过程正常退出。

但尝试输入一个字符串呢?

请输入一个整数: 是什么?
对不起,输入无效。请输入一个整数:
对不起,输入无效。请输入一个整数:
对不起......

等等,它一直循环字符,直到字符串耗尽。 即使输入单个字符循环两次,我假设它分析换行符。

无论如何,必须有一种方法来刷新Stdin的Go?

P.S.在没有这种功能的情况下,您将如何解决它以提供相同的功能?我甚至没有在那...

回答

3

我会解决这个问题,直到每次失败后行结束。这将清除文本的其余部分。

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) 
} 
+0

这是一个很好的解决方法。谢谢! –

+0

只使用'Scanln',它被记录为消耗空白并阅读直到换行。 –

1

我知道这已经回答了,但是这是我的实现:

func flush (reader *bufio.Reader) { 
    var i int 
    for i = 0; i < reader.Buffered(); i++ { 
     reader.ReadByte() 
    } 
} 

这应该在任何情况下工作,包括那些在那里“stdin.ReadString(‘\ n’)”不能用过的。

1

唤醒老问题不好吗?

我更喜欢使用fmt.Scanln,因为A)它不需要导入另一个库(例如reader),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的情况下,读取在第一个非数字字节之后停止,而不是“扫描行”似乎很奇怪。

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) 
} 
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 
} 

基本的想法是始终缓冲从标准输入读取。扫描时遇到错误,只需放弃缓冲区内容即可。这样你开始为下一次扫描使用一个空缓冲区。

或者,您可以在扫描之前丢弃缓冲区,因此用户在此之前的任何杂散输入都不会被拾取。

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 
} 
相关问题