Bagaimana cara membaca dari input standar di konsol?


270

Saya ingin membaca input standar dari baris perintah, tetapi upaya saya telah berakhir dengan program yang keluar sebelum saya diminta untuk input. Saya mencari yang setara dengan Console.ReadLine () di C #.

Inilah yang saat ini saya miliki:

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

Kode ini terlihat benar. Karena penasaran, apakah Anda menjalankan ini di Playground? Go Playground tidak mengizinkan input stdin karena alasan jaringan.
LinearZoetrope

Nevermind, sepertinya ada masalah kecil di mana Anda membutuhkan pointer (lihat jawaban saya). Meskipun saya tidak yakin apa masalah dengan bufio.NewReader metode karena ini bekerja untuk saya.
LinearZoetrope


8
Jangan mencampur bufiobuffering dari pembaca mana pun (mis. bufio.NewReader(os.Stdin)) Dengan membaca langsung dari pembaca garis bawah (mis. fmt.Scanln(x)Langsung membaca dari os.Stdin). Buffering dapat membaca secara sewenang-wenang jauh di depan. (Dalam kasus khusus ini nanti harus fmt.Fscanln(reader,x)membaca dari buffer yang sama).
Dave C

Saya tidak mendapatkan fmt.Sscanlnkarya, itu menjadi "% v" setelah berjalan
Beeno Tung

Jawaban:


295

Saya tidak yakin apa yang salah dengan blok itu

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

Saat ini bekerja pada mesin saya. Namun, untuk blok berikutnya Anda memerlukan pointer ke variabel yang Anda tetapkan inputnya. Coba ganti fmt.Scanln(text2)dengan fmt.Scanln(&text2). Jangan gunakan Sscanln, karena mem-parsing sebuah string yang sudah ada dalam memori, bukan dari stdin. Jika Anda ingin melakukan sesuatu seperti apa yang Anda coba lakukan, gantikan denganfmt.Scanf("%s", &ln)

Jika ini masih tidak berhasil, pelakunya mungkin beberapa pengaturan sistem aneh atau IDE kereta.


2
Apakah itu seharusnya kutipan tunggal? ReadString('\n')atau ReadString("\n")?
425nesp

8
@ 425nesp ya, itu delimeter, yang merupakan satu byte. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Jawaban yang bagus, tetapi ini gagal ketika saya mencoba menggunakan backspace, dll kunci
kumarharsh

4
Begitu banyak untuk Golang untuk membaca baris dari file melalui pembaca rdke variabel ssebagaiif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Hanya berbagi hal yang menarik (saya seorang pemula Golang): \ n harus berada di dalam tanda kutip tunggal (jangan mencoba menggunakan tanda kutip ganda). Atau yang lain, itu akan mereproduksi ini:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz

124

Anda juga dapat mencoba:

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

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

6
Anda dapat menghapus "untuk {}" jika Anda hanya ingin satu input satu baris.
user2707671

3
jika ada untuk {} loop, bagaimana keluar dari loop saat Anda memasukkan? Apakah ada karakter khusus yang akan membuat loop berhenti? - Terima kasih
Madhan Ganesh

2
@Madhan scanner.Scan () mengembalikan nilai bool untuk mengindikasikan keluar dari for loop atau tidak.
Helin Wang

5
Anda akan mendapatkan kesalahan ini bufio.Scanner: token terlalu lama Jika input Anda lebih besar dari 64 * 1024 byte. Juga jangan lupa tambahkan di fmt.Println(scanner.Err())bawah for loop.
Yuvaraj Loganathan

Bagaimana jika saya memasukkan "abc \ n ^ D", string yang diharapkan adalah "abc \ n" tetapi mengembalikan "abc".
Shivendra Mishra

96

Saya pikir cara yang lebih standar untuk melakukan ini adalah:

package main

import "fmt"

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

Lihatlah scangodoc: http://godoc.org/fmt#Scan

Memindai teks pindaian yang dibaca dari input standar, menyimpan nilai yang dipisahkan ruang secara berurutan ke dalam argumen yang berurutan. Baris baru dihitung sebagai ruang.

Scanln mirip dengan Scan, tetapi berhenti memindai pada baris baru dan setelah item akhir harus ada baris baru atau EOF.


10
Ini sepertinya tidak menyukai spasi di string input.
Hairy Chris

3
@ DairyChris ya ini aneh. Dalam dokumen itu tertulis bahwa stops scanning at a newline and after the final item there must be a newline or EOFtidak yakin mengapa ruang "memecahnya" ... saya kira itu adalah bug
karantan

6
Ada bug yang dibuka untuk ini: github.com/golang/go/issues/5703 Itu ditutup sebagai WorkingAsIntended. Lihat juga: stackoverflow.com/questions/24005899/… dan groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Tampaknya banyak orang memiliki masalah dengan hal ini. Diperlukan perubahan dokumentasi? Juga, dari tautan terakhir itu: "Pindai dan Scanln adalah untuk penguraian dan hal-hal seperti itu, jadi hanya mendapatkan satu baris teks dari stdin akan mengalahkan tujuannya."
user2707671

Bagi saya, itu benar-benar membingungkan bahwa fmt.Scan di salah satu fungsi yang serupa tidak cocok dengan ruang seperti bufio.NewReader tidak.
FilBot3

3
Masalah yang sama dengan spasi tetap saat menggunakan fmt.Scanlndan fmt.Scandengan versi go 2016 saat ini (go version go1.6.2 linux / amd64).
Chiheb Nexus

30

Selalu mencoba menggunakan bufio.NewScanner untuk mengumpulkan input dari konsol. Seperti yang disebutkan lainnya, ada beberapa cara untuk melakukan pekerjaan itu tetapi Pemindai pada awalnya dimaksudkan untuk melakukan pekerjaan itu. Dave Cheney menjelaskan mengapa Anda harus menggunakan Scanner alih-alih bufio.Reader's ReadLine.

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

Ini jawaban potongan kode untuk pertanyaan Anda

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

Jika Anda tidak ingin mengumpulkan input secara terprogram, cukup tambahkan baris ini

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

Output dari program di atas adalah:

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

Program di atas mengumpulkan input pengguna dan menyimpannya ke sebuah array. Kita juga dapat memutus aliran itu dengan karakter khusus. Pemindai menyediakan API untuk penggunaan tingkat lanjut seperti pemisahan menggunakan fungsi kustom, dll., Memindai berbagai jenis aliran I / O (Stdin, String) dll.


Ini harus menjadi jawaban yang diterima. Tidak hanya itu jawaban yang lebih akurat tetapi juga memiliki kualitas yang lebih baik.
Daniel Farrell

11

Cara lain untuk membaca banyak input dalam satu loop yang dapat menangani input dengan spasi:

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

Keluaran:

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
Anda mungkin bisa menggunakan jeda di "q" cek dalam dan membungkus semuanya dalam loop tak terbatas. Omong-omong jawaban yang bagus!
tebanep

2
Sepertinya Anda juga dapat menyingkirkan persyaratan di loop for sekarang juga.
irbanana

6

Saya terlambat ke pesta. Tapi bagaimana dengan satu liner:

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

dan tekan ctrl + d (EOT) setelah input dimasukkan pada baris perintah.


Karena os.Stdintidak 'berakhir' tidak mungkin untuk membaca semuanya. Anda mungkin menunggu beberapa saat ...
gypsydave5

2
tekan ctrl + d yaitu eot.
Shivendra Mishra

3
Ya, itu akan melakukannya - mengingatkan saya menulis email dengan mail.
gypsydave5

5

Coba kode ini: -

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

3
Sepertinya Scanf()tidak menerima spasi putih dalam string
Eslam

4

Bisa juga dilakukan seperti ini: -

package main
import "fmt"     

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

3

Dibaca dengan bersih dalam pasangan, nilai yang diminta:

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

Inilah yang dijalankan:

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

2
Juga cara yang bagus sejak strings.TrimSpace menghapus '\ n'. Dan saya percaya reader.ReadString ('\ n') juga lintas platform.
user2707671

Saya akan menebak bahwa sebagian besar waktu Anda ingin menghapus \ n secara default, itu sebabnya lebih baik bufio.NewScanner sebagai jawaban @Naren Yellavula
John Balvin Arias

2

Anda perlu memberikan pointer ke var yang ingin Anda pindai, seperti:

fmt.scan(&text2)

0

Dalam kasus saya, program tidak menunggu karena saya menggunakan watcherperintah untuk menjalankan program secara otomatis. Menjalankan program secara manual go run main.gomenghasilkan "Masukkan teks" dan akhirnya mencetak ke konsol.

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

2
Batasan Scan*keluarga adalah bahwa mereka membaca hingga pemisah spasi (misalnya spasi).
George Tseres
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.