Làm thế nào để đọc từ đầu vào tiêu chuẩn trong giao diện điều khiển?


270

Tôi muốn đọc đầu vào tiêu chuẩn từ dòng lệnh, nhưng những nỗ lực của tôi đã kết thúc khi chương trình thoát ra trước khi tôi được nhắc nhập. Tôi đang tìm kiếm tương đương với Console.ReadLine () trong C #.

Đây là những gì tôi hiện có:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print("Enter text: ")
    text, _ := reader.ReadString('\n')
    fmt.Println(text)

    fmt.Println("Enter text: ")
    text2 := ""
    fmt.Scanln(text2)
    fmt.Println(text2)

    ln := ""
    fmt.Sscanln("%v", ln)
    fmt.Println(ln)
}

Mã này có vẻ đúng. Vì tò mò, bạn có đang chạy cái này trên Sân chơi không? Sân chơi Go không cho phép đầu vào stdin vì lý do mạng.
Tuyến tínhZoetrope

Không bao giờ, nó có vẻ là một vấn đề tinh tế mà bạn cần một con trỏ (xem câu trả lời của tôi). Mặc dù tôi không chắc vấn đề với phương thức bufio.NewReader là gì vì nó hoạt động với tôi.
Tuyến tínhZoetrope


8
Không trộn bufiobộ đệm của bất kỳ trình đọc nào (ví dụ bufio.NewReader(os.Stdin)) với các lần đọc trực tiếp từ trình đọc gạch chân (ví dụ: fmt.Scanln(x)đọc trực tiếp từ os.Stdin). Bộ đệm có thể đọc tùy ý xa về phía trước. (Trong trường hợp cụ thể này, sau này nên fmt.Fscanln(reader,x)đọc từ cùng một bộ đệm).
Dave C

Tôi không nhận được fmt.Sscanlntác phẩm, nó trở thành "% v" sau khi chạy
Beeno Tung

Câu trả lời:


294

Tôi không chắc có gì sai với khối

reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Println(text)

Vì nó hoạt động trên máy của tôi. Tuy nhiên, đối với khối tiếp theo, bạn cần một con trỏ tới các biến bạn đang gán đầu vào. Hãy thử thay thế fmt.Scanln(text2)bằng fmt.Scanln(&text2). Đừng sử dụng Sscanln, vì nó phân tích một chuỗi đã có trong bộ nhớ thay vì từ stdin. Nếu bạn muốn làm một cái gì đó giống như những gì bạn đang cố gắng làm, hãy thay thế nó bằngfmt.Scanf("%s", &ln)

Nếu điều này vẫn không hoạt động, thủ phạm của bạn có thể là một số cài đặt hệ thống kỳ lạ hoặc một IDE lỗi.


2
Là những người được cho là trích dẫn duy nhất? ReadString('\n')hay ReadString("\n")?
425nesp

8
@ 425nesp có, đó là đồng hồ đo, là một byte đơn. golang.org/pkg/bufio/#Reader.ReadString
linearZoetrope

3
Câu trả lời hay, nhưng điều này không thành công khi tôi thử sử dụng các phím backspace, v.v.
kumarharsh 16/2/2017

4
Quá nhiều để Golang đọc một dòng từ tệp qua đầu đọc rdđến biến snhưif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Chỉ chia sẻ một điều thú vị (Tôi là người mới bắt đầu Golang): \ n phải ở trong dấu ngoặc đơn (đừng cố sử dụng dấu ngoặc kép). Hoặc nếu không, nó sẽ tái tạo điều này:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz

124

bạn cũng có thể thử:

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

if scanner.Err() != nil {
    // handle error.
}

6
Bạn có thể xóa "cho {}" nếu bạn chỉ muốn một đầu vào một dòng.
dùng2707671

3
nếu có một vòng lặp for {}, làm thế nào để đi ra từ vòng lặp khi bạn nhập? Có một nhân vật đặc biệt sẽ làm cho vòng lặp dừng lại? - Cảm ơn
Madhan Ganesh

2
@Madhan Scanner.Scan () trả về giá trị bool để chỉ ra thoát khỏi vòng lặp for hay không.
Helin Wang

5
Bạn sẽ gặp lỗi này bufio.Scanner: mã thông báo quá lâu Nếu đầu vào của bạn lớn hơn 64 * 1024 byte. Cũng đừng quên thêm fmt.Println(scanner.Err())bên dưới vòng lặp for.
Yuvaraj Loganathan

Điều gì xảy ra nếu tôi nhập "abc \ n ^ D", chuỗi dự kiến ​​là "abc \ n" nhưng nó trả về "abc".
Shivendra Mishra

96

Tôi nghĩ rằng một cách tiêu chuẩn hơn để làm điều này sẽ là:

package main

import "fmt"

func main() {
    fmt.Print("Enter text: ")
    var input string
    fmt.Scanln(&input)
    fmt.Print(input)
}

Hãy nhìn vào vị scanthần: http://godoc.org/fmt#Scan

Quét quét văn bản đọc từ đầu vào tiêu chuẩn, lưu trữ các giá trị được phân tách không gian liên tiếp thành các đối số liên tiếp. Dòng mới được tính là không gian.

Scanln tương tự như Scan, nhưng dừng quét ở một dòng mới và sau mục cuối cùng phải có một dòng mới hoặc EOF.


10
Điều này dường như không thích khoảng trắng trong chuỗi đầu vào.
Hairy Chris

3
@HerryChris vâng, điều này thật lạ. Trong tài liệu có nói rằng stops scanning at a newline and after the final item there must be a newline or EOFkhông chắc tại sao không gian "phá vỡ" nó ... Tôi đoán đó là một lỗi
karantan

6
Có một lỗi được mở cho điều này: github.com/golang/go/issues/5703 Nó đã bị đóng khi WorkAsIntends. Xem thêm: stackoverflow.com/questions/24005899/...groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Có vẻ rất nhiều người có vấn đề với điều này. Thay đổi tài liệu cần thiết? Ngoài ra, từ liên kết cuối cùng đó: "Quét và Quét là để phân tích cú pháp và những thứ tương tự, vì vậy chỉ cần lấy một dòng văn bản từ stdin sẽ đánh bại mục đích."
dùng2707671

Đối với tôi, thật khó hiểu khi fmt.Scan trong bất kỳ chức năng tương tự nào của nó không chơi tốt với các không gian như bufio.NewReader.
FilBot3

3
Vấn đề tương tự với các khoảng trắng vẫn còn trong khi sử dụng fmt.Scanlnfmt.Scanvới phiên bản go 2016 hiện tại (phiên bản go1.6.2 linux / amd64).
Chiheb Nexus

30

Luôn cố gắng sử dụng bufio.NewScanner để thu thập dữ liệu đầu vào từ bàn điều khiển. Như những người khác đã đề cập, có nhiều cách để thực hiện công việc nhưng Scanner ban đầu được dự định để thực hiện công việc. Dave Cheney giải thích lý do tại sao bạn nên sử dụng Máy quét thay vì bufio.Reader ReadLine.

https://twitter.com/davecheney/status/604837853344989184?lang=vi

Đây là câu trả lời đoạn mã cho câu hỏi của bạn

package main

import (
    "bufio"
    "fmt"
    "os"
)

/*
 Three ways of taking input
   1. fmt.Scanln(&input)
   2. reader.ReadString()
   3. scanner.Scan()

   Here we recommend using bufio.NewScanner
*/

func main() {
    // To create dynamic array
    arr := make([]string, 0)
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("Enter Text: ")
        // Scans a line from Stdin(Console)
        scanner.Scan()
        // Holds the string that scanned
        text := scanner.Text()
        if len(text) != 0 {
            fmt.Println(text)
            arr = append(arr, text)
        } else {
            break
        }

    }
    // Use collected inputs
    fmt.Println(arr)
}

Nếu bạn không muốn thu thập các đầu vào theo chương trình, chỉ cần thêm các dòng này

   scanner := bufio.NewScanner(os.Stdin)
   scanner.Scan()
   text := scanner.Text()
   fmt.Println(text)

Đầu ra của chương trình trên sẽ là:

Enter Text: Bob
Bob
Enter Text: Alice
Alice
Enter Text:
[Bob Alice]

Chương trình trên thu thập đầu vào của người dùng và lưu chúng vào một mảng. Chúng ta cũng có thể phá vỡ dòng chảy đó với một nhân vật đặc biệt. Trình quét cung cấp API để sử dụng nâng cao như chia tách bằng chức năng tùy chỉnh, v.v., quét các loại luồng I / O khác nhau (Stdin, String), v.v.


Đây phải là câu trả lời được chấp nhận. Đây không chỉ là một câu trả lời chính xác hơn mà còn có chất lượng tốt hơn.
Daniel Farrell

11

Một cách khác để đọc nhiều đầu vào trong một vòng lặp có thể xử lý đầu vào có khoảng trắng:

package main
import (
    "fmt"
    "bufio"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    var text string
    for text != "q" {  // break the loop if text == "q"
        fmt.Print("Enter your text: ")
        scanner.Scan()
        text = scanner.Text()
        if text != "q" {
            fmt.Println("Your text was: ", text)
        }
    }
}

Đầu ra:

Enter your text: Hello world!
Your text was:  Hello world!
Enter your text: Go is awesome!
Your text was:  Go is awesome!
Enter your text: q

2
Bạn có thể chỉ cần sử dụng một dấu ngắt trong kiểm tra "q" bên trong và bọc tất cả trong một vòng lặp vô hạn. Bằng cách này, câu trả lời tuyệt vời!
tebanep

2
Có vẻ như bây giờ bạn cũng có thể thoát khỏi điều kiện trong vòng lặp for.
irbanana

6

Tôi đến bữa tiệc muộn. Nhưng làm thế nào về một lót:

data, err := ioutil.ReadAll(os.Stdin)

và nhấn ctrl + d (EOT) sau khi nhập vào dòng lệnh.


Bởi vì os.Stdinkhông 'kết thúc' nên không thể đọc hết. Bạn có thể đợi một lúc ...
gypsydave5

2
nhấn ctrl + d tức là eot.
Shivendra Mishra

3
Vâng, đó là làm điều đó - nhắc nhở tôi viết email với mail.
gypsydave5

5

Hãy thử mã này: -

var input string
func main() {
      fmt.Print("Enter Your Name=")
      fmt.Scanf("%s",&input)
      fmt.Println("Hello "+input)
      }

3
Có vẻ như Scanf()không chấp nhận khoảng trắng trong chuỗi
Eslam 17/03/2017

4

Cũng có thể được thực hiện như thế này: -

package main
import "fmt"     

func main(){
    var myname string
fmt.Scanf("%s", &myname)           
fmt.Println("Hello", myname)       
}

3

Đọc sạch trong một vài giá trị được nhắc:

// Create a single reader which can be called multiple times
reader := bufio.NewReader(os.Stdin)
// Prompt and read
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Print("Enter More text: ")
text2, _ := reader.ReadString('\n')
// Trim whitespace and print
fmt.Printf("Text1: \"%s\", Text2: \"%s\"\n",
    strings.TrimSpace(text), strings.TrimSpace(text2))

Đây là một hoạt động:

Enter text: Jim
Enter More text: Susie
Text1: "Jim", Text2: "Susie"

2
Cũng là một cách hay vì chuỗi.TrimSpace xóa '\ n'. Và tôi tin rằng reader.ReadString ('\ n') cũng là nền tảng chéo.
dùng2707671

Tôi sẽ đoán rằng hầu hết thời gian bạn muốn xóa \ n theo mặc định, đó là lý do tại sao nó tốt hơn bufio.NewScanner như @Naren Yellavula trả lời
John Balvin Arias

2

Bạn cần cung cấp một con trỏ tới var bạn muốn quét, như vậy:

fmt.scan(&text2)

0

Trong trường hợp của tôi, chương trình không chờ đợi vì tôi đang sử dụng watcherlệnh để tự động chạy chương trình. Chạy thủ công chương trình go run main.godẫn đến "Nhập văn bản" và cuối cùng in ra bàn điều khiển.

fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)

2
Hạn chế của Scan*gia đình là họ đọc đến một dấu phân cách khoảng trắng (ví dụ: khoảng trắng).
George Tseres
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.