2013-02-01 3 views
5

ここに私の悩みがあります。ユーザからの入力を取得する場合、私は、彼らが有効な入力入力するまで再試行するようにユーザーに依頼するループを採用したい:ユーザーが有効な入力を入力した場合、上記を実行するGoで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:整数を入力してください。

代わりに文字列を入力してください。

整数を入力してください。 何ですか?
申し訳ありませんが、無効な入力です。整数を入力してください:
申し訳ありませんが、無効な入力です。整数を入力してください:
申し訳ありません...

など、文字が使い果たされるまで文字を繰り返し続けます。 1文字を2回入力するだけでも、改行を解析すると仮定します。

とにかく、GoでStdinをフラッシュする方法が必要ですか?

P.S.このような機能がない場合、同等の機能を提供するためにはどうすれば対処できますか?私もそれで失敗しました...

答えて

3

私は、各失敗の後に行の最後まで読んでこれを修正します。これにより、残りのテキストがクリアされます。

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

これは「stdin.ReadString( 『\ nは』)」することはできませんものも含め、すべての状況で動作するはずです:私は、これはすでに回答されているが、これは私の実装だった知っている

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

古い質問を起こすのは悪いですか?

A)別のライブラリ(リーダーなど)をインポートする必要がなく、B)明示的なforループを含まないため、fmt.Scanlnを使用することをお勧めします。

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 
} 

基本的な考え方は、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 
} 
関連する問題