2013-02-01 67 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 
} 
相關問題