2013-02-01 23 views
5

Đây là một vấn đề đang làm tôi lo lắng vào lúc này. Khi nhận được thông tin từ người sử dụng, tôi muốn sử dụng một vòng lặp để yêu cầu người dùng thử lại cho đến khi họ nhập vào hợp lệ:Làm thế nào để tuôn ra Stdin sau khi fmt.Scanf() trong Go?

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

Chạy trên, nếu người dùng nhập vào hợp lệ, không có vấn đề:

Vui lòng nhập một số nguyên:


thoát mã 0, quá trình thoát bình thường.

Nhưng thử nhập chuỗi thay vào đó?

Vui lòng nhập số nguyên: cái gì?
Rất tiếc, mục nhập không hợp lệ. Vui lòng nhập một số nguyên:
Rất tiếc, mục nhập không hợp lệ. Vui lòng nhập số nguyên:
Xin lỗi ...

Vv và giữ ký tự lặp theo ký tự cho đến khi chuỗi hết. Ngay cả khi nhập một chuỗi ký tự đơn hai lần, tôi giả định khi nó phân tích cú pháp dòng mới.

Dù sao thì, phải có cách để xả Stdin trong Go?

P.S. Trong trường hợp không có tính năng như vậy, bạn sẽ làm việc xung quanh nó như thế nào để cung cấp chức năng tương đương? Tôi đã thất bại ngay cả lúc đó ...

Trả lời

3

Tôi sẽ sửa lỗi này bằng cách đọc cho đến cuối dòng sau mỗi lần thất bại. Điều này xóa phần còn lại của văn bả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

Đây là giải pháp tốt. Cảm ơn! –

+0

Chỉ sử dụng 'Scanln' được ghi lại là không gian trắng và đọc cho đến khi dòng mới. –

1

Tôi biết điều này đã được trả lời nhưng điều này là thực hiện của tôi:

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

này nên hoạt động trong mọi tình huống, kể cả những nơi "stdin.ReadString ('\ n')" không thể đã sử dụng.

1

Thật tệ khi đánh thức một câu hỏi cũ?

Tôi thích sử dụng fmt.Scanln vì A) không yêu cầu nhập thư viện khác (ví dụ: trình đọc) và B) nó không liên quan đến vòng lặp rõ ràng.

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

Tuy nhiên, có vẻ như cần phải có giải pháp thanh lịch hơn. Đặc biệt trong trường hợp của fmt.Scanln có vẻ kỳ lạ khi đọc dừng sau byte đầu tiên không phải là số thay vì "quét dòng".

1

Tôi đã gặp sự cố tương tự để nhận dữ liệu nhập của người dùng nhưng đã giải quyết vấn đề theo cách hơi khác. Thêm vào thread trong trường hợp ai đó tìm thấy này hữu ích:

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

Xin lỗi vì đào này trở lại, nhưng tôi chạy vào ngày hôm nay và muốn cải thiện trên các câu trả lời hiện tại bằng cách sử dụng chức năng thư viện tiêu chuẩn mới.

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 
} 

Ý tưởng cơ bản là luôn đệm bộ đọc của bạn từ tiêu chuẩn. Khi bạn gặp phải lỗi khi quét, chỉ cần loại bỏ nội dung bộ đệm. Bằng cách đó bạn bắt đầu với một bộ đệm trống cho lần quét tiếp theo của bạn.

Hoặc, bạn có thể loại bỏ bộ đệm trước khi quét, vì vậy mọi đầu vào đi lạc của người dùng trước đó sẽ không được chọn.

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 
} 
Các vấn đề liên quan