Konsoldaki standart girişten nasıl okunur?


270

Komut satırından standart girdiyi okumak istiyorum, ancak giriş istenmeden önce programdan çıkma girişimim sona erdi. C # Console.ReadLine () eşdeğerini arıyorum .

Şu anda sahip olduğum şey bu:

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

Bu kod doğru görünüyor. Meraktan, bunu Oyun alanında mı çalıştırıyorsunuz? Go Playground, ağ oluşturma nedeniyle stdin girişine izin vermez.
LinearZoetrope

Boşver, bir işaretçiye ihtiyaç duyduğunuz ince bir sorun gibi görünüyor (cevabımı görün). Bufio.NewReader yöntemi ile sorunun ne olduğundan emin değilim ama benim için çalışıyor.
LinearZoetrope


8
Karıştırmayın bufioherhangi okuyucu (örneğin bir ara belleğe bufio.NewReader(os.Stdin)doğrudan birlikte) (örn altı çizili kısım okuyucudan okur fmt.Scanln(x)doğrudan gelen okur os.Stdin). Arabelleğe alma, keyfi olarak çok ileride okuyabilir. (Bu özel durumda daha sonra fmt.Fscanln(reader,x)aynı arabellekten okunmalıdır).
Dave C

İş alamadım fmt.Sscanln,
koştuktan

Yanıtlar:


294

Blokta neyin yanlış olduğundan emin değilim

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

Makinemde çalıştığı gibi. Ancak, sonraki blok için, girdiyi atadığınız değişkenlere bir işaretçi gerekir. Değiştirmeyi deneyin fmt.Scanln(text2)ile fmt.Scanln(&text2). Kullanmayın Sscanln, çünkü stdin yerine zaten bellekte olan bir dizeyi ayrıştırır. Yapmaya çalıştığınız gibi bir şey yapmak istiyorsanız,fmt.Scanf("%s", &ln)

Bu hala işe yaramazsa, suçluunuz bazı garip sistem ayarları veya buggy IDE olabilir.


2
Bunların tek tırnak olması mı gerekiyor? ReadString('\n')veya ReadString("\n")?
425nesp

8
@ 425nesp evet, bu tek bir bayt olan sınırlayıcıdır. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
İyi cevap, ama backspace, vb anahtarlarını kullanmayı denediğimde başarısız oluyor
kumarharsh

4
Golang'ın dosyadan okuyucuya rddeğişken solarak bir satır okuması için çok fazlaif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Sadece ilginç bir şey paylaşıyorum (ben bir Golang acemiyim): \ n tek tırnak içinde olmalıdır (çift tırnak kullanmaya çalışmayın). Aksi takdirde, bunu cannot use "\n" (type string) as type byte in argument to reader.ReadString
çoğaltacaktır

124

deneyebilirsiniz:

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

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

6
Yalnızca bir satırlık bir giriş istiyorsanız "{}" için kaldırabilirsiniz.
user2707671

3
for {} döngüsü varsa, girdiğinizde döngüden nasıl çıkılır? Döngünün durmasını sağlayacak özel bir karakter var mı? - Teşekkürler
Madhan Ganesh

2
@Madhan scanner.Scan () for döngüsünden çıkılıp çıkılmayacağını belirtmek için bool değerini döndürür.
Helin Wang

5
Tarayıcı: simge çok uzun Girişiniz 64 * 1024 bayttan büyükse, bu hatayı alırsınız . Ayrıca fmt.Println(scanner.Err())for döngüsünün altına eklemeyi de unutmayın .
Yuvaraj Loganathan

"Abc \ n ^ D" girersem beklenen dize "abc \ n" olur, ancak "abc" döndürür.
Shivendra Mishra

96

Bunu yapmak için daha standart bir yol olacağını düşünüyorum:

package main

import "fmt"

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

scanGodoc'a bir göz atın : http://godoc.org/fmt#Scan

Tara, standart girdiden okunan metni tarar ve art arda boşlukla ayrılmış değerleri ardışık bağımsız değişkenlere kaydeder. Yeni satırlar boşluk olarak sayılır.

Scanln Scan'e benzer, ancak yeni satırda taramayı durdurur ve son öğeden sonra yeni satır veya EOF olmalıdır.


10
Bu, giriş dizesindeki boşluklardan hoşlanmıyor gibi görünüyor.
Kıllı Chris

3
@HairyChris evet bu garip. stops scanning at a newline and after the final item there must be a newline or EOF
Belgede

6
Bunun için bir hata açıldı: github.com/golang/go/issues/5703 WorkingAsIntended olarak kapandı. Ayrıca bkz: stackoverflow.com/questions/24005899/… ve groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Pek çok insanın bununla ilgili sorunları var gibi görünüyor. Dokümantasyon değişikliği mi gerekiyor? Ayrıca, son bağlantıdan: "Scan ve Scanln ayrıştırma ve bunun gibi şeyler içindir, bu yüzden stdin'den tek bir metin satırı almak amacı bozar."
user2707671

Bana göre, fmt.Scan'ın benzer işlevlerinden herhangi birinde bufio gibi boşluklarla iyi oynamaması gerçekten kafa karıştırıcı.
FilBot3

3
Aynı sorun, boşluklar fmt.Scanlnve fmt.Scangeçerli 2016 go sürümü (go sürümü go1.6.2 linux / amd64) kullanılırken de aynıdır.
Chiheb Nexus

30

Konsoldan girdi toplamak için her zaman bufio.NewScanner'ı kullanmayı deneyin . Diğerlerinin de belirttiği gibi, işi yapmanın birden çok yolu vardır, ancak Tarayıcı aslında işi yapmayı amaçlamaktadır. Dave Cheney neden bufio yerine Tarayıcı kullanmanız gerektiğini açıklıyor.Okuyucunun ReadLine'ı.

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

İşte sorunuz için kod pasajı cevabı

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

Girişleri programlı olarak toplamak istemiyorsanız, bu satırları ekleyin

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

Yukarıdaki programın çıktısı:

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

Yukarıdaki program kullanıcı girişini toplar ve bunları bir diziye kaydeder. Ayrıca bu akışı özel bir karakterle kırabiliriz. Tarayıcı, özel bir işlev kullanarak bölme, farklı G / Ç akışları (Stdin, String) vb. Tarama gibi gelişmiş kullanım için API sağlar.


Bu kabul edilen cevap olmalı. Sadece daha doğru bir cevap değil, aynı zamanda daha kaliteli.
Daniel Farrell

11

Boşluk içeren bir girdiyi işleyebilen bir döngü içindeki birden çok girdiyi okumanın başka bir yolu:

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

Çıktı:

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
Belki sadece iç "q" kontrolünde bir mola kullanabilir ve hepsini sonsuz bir döngüye sarabilirsiniz. Bu arada harika bir cevap!
tebanep

2
Görünüşe göre for döngüsündeki koşulludan da kurtulabilirsiniz.
irbanana

6

Partiye geç kaldım. Ama bir astardan ne haber:

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

ve komut satırına giriş girildikten sonra ctrl + d (EOT) tuşlarına basın.


Çünkü os.Stdin'bitmiyor' hepsini okumak imkansız. Bir süre beklemiş olabilirsiniz ...
gypsydave5

2
ctrl + d yani eot tuşlarına basın.
Shivendra Mishra

3
Evet, bu işe yarar - bana e-posta yazmamı hatırlatıyor mail.
gypsydave5

5

Bu kodu deneyin: -

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

3
Scanf()Dize beyaz boşluk kabul etmiyor gibi görünüyor
Eslam

4

Ayrıca şu şekilde yapılabilir: -

package main
import "fmt"     

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

3

Birkaç istenen değerde net bir şekilde okuyun:

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

İşte bir koşu:

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

2
Ayrıca dizelerden beri güzel bir yol.TrimSpace '\ n' kaldırır. Ve okuyucuya inanıyorum.ReadString ('\ n') de platformlar arası.
user2707671

Ben çoğu zaman bunu @Naren Yellavula cevap olarak daha iyi bufio.NewScanner neden olduğu yönündeki varsayılan olarak n \ kaldırmak istediğinizi tahmin edersiniz
John BALVIN Arias

2

Taramak istediğiniz varlığa bir işaretçi sağlamanız gerekir, şöyle:

fmt.scan(&text2)

0

Benim durumumda, programı beklemiyordum çünkü watcherprogramı otomatik olarak çalıştırmak için komut kullanıyordum . Programı manuel olarak çalıştırmak go run main.go"Metin girin" ve sonuçta konsola yazdırmakla sonuçlandı.

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

2
Scan*Ailenin sınırlaması, bir boşluk (örn. Boşluk) ayırıcısını okumasıdır.
George Tseres
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.