Wie lese ich von der Standardeingabe in der Konsole?


270

Ich möchte die Standardeingabe über die Befehlszeile lesen, aber meine Versuche wurden mit dem Beenden des Programms beendet, bevor ich zur Eingabe aufgefordert werde. Ich suche das Äquivalent von Console.ReadLine () in C #.

Folgendes habe ich derzeit:

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

Dieser Code sieht korrekt aus. Laufen Sie das aus Neugier auf dem Spielplatz? Der Go Playground erlaubt aus Netzwerkgründen keine Standardeingabe.
LinearZoetrope

Egal, es scheint ein subtiles Problem zu sein, bei dem Sie einen Zeiger brauchten (siehe meine Antwort). Obwohl ich nicht sicher bin, was das Problem mit der bufio.NewReader-Methode ist, da sie für mich funktioniert.
LinearZoetrope


8
Mischen Sie die bufioPufferung eines Lesegeräts (z. B. bufio.NewReader(os.Stdin)) nicht mit direkten Lesevorgängen vom unterstrichenen Lesegerät (z. B. fmt.Scanln(x)direkten Lesevorgängen von os.Stdin). Die Pufferung kann beliebig weit voraus gelesen werden. (In diesem speziellen Fall sollte das fmt.Fscanln(reader,x)letztere aus demselben Puffer gelesen werden).
Dave C

Ich bekomme keine fmt.SscanlnArbeiten, es wird "% v" nach dem Laufen
Beeno Tung

Antworten:


294

Ich bin mir nicht sicher, was mit dem Block los ist

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

Wie es auf meiner Maschine funktioniert. Für den nächsten Block benötigen Sie jedoch einen Zeiger auf die Variablen, denen Sie die Eingabe zuweisen. Versuchen Sie es fmt.Scanln(text2)durch fmt.Scanln(&text2). Nicht verwenden Sscanln, da eine Zeichenfolge analysiert wird, die sich bereits im Speicher befindet, anstatt von stdin. Wenn Sie so etwas wie das tun möchten, was Sie versucht haben, ersetzen Sie es durchfmt.Scanf("%s", &ln)

Wenn dies immer noch nicht funktioniert, liegt Ihr Schuldiger möglicherweise an seltsamen Systemeinstellungen oder einer fehlerhaften IDE.


2
Sollen das einfache Anführungszeichen sein? ReadString('\n')oder ReadString("\n")?
425nesp

8
@ 425nesp ja, das ist der Delimeter, der ein einzelnes Byte ist. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Gute Antwort, aber dies schlägt fehl, wenn ich versuche,
Rücktaste

4
So viel zu Golang, um eine Zeile von Datei über Reader rdzu Variable zu lesen salsif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Teilen Sie einfach eine interessante Sache (ich bin ein Golang-Anfänger): \ n muss in einfachen Anführungszeichen stehen (versuchen Sie nicht, doppelte Anführungszeichen zu verwenden). Oder es wird dies reproduzieren:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz

124

Sie können auch versuchen:

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

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

6
Sie können das "für {}" entfernen, wenn Sie nur eine einzeilige Eingabe wünschen.
user2707671

3
Wenn es eine for {} -Schleife gibt, wie kann man bei der Eingabe aus der Schleife herauskommen? Gibt es ein Sonderzeichen, mit dem die Schleife gestoppt wird? - Danke
Madhan Ganesh

2
@Madhan scanner.Scan () gibt den Bool-Wert zurück, um anzuzeigen, dass die for-Schleife beendet wird oder nicht.
Helin Wang

5
Sie erhalten diesen Fehler bufio.Scanner: Token zu lang Wenn Ihre Eingabe größer als 64 * 1024 Bytes ist. Vergessen Sie auch nicht, fmt.Println(scanner.Err())unter der for-Schleife hinzuzufügen .
Yuvaraj Loganathan

Was passiert, wenn ich "abc \ n ^ D" eingebe? Die erwartete Zeichenfolge lautet "abc \ n", gibt aber "abc" zurück.
Shivendra Mishra

96

Ich denke, ein normaler Weg, dies zu tun, wäre:

package main

import "fmt"

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

Schauen Sie sich den scanGodoc an: http://godoc.org/fmt#Scan

Scan scannt den von der Standardeingabe gelesenen Text und speichert aufeinanderfolgende durch Leerzeichen getrennte Werte in aufeinanderfolgenden Argumenten. Zeilenumbrüche gelten als Leerzeichen.

Scanln ähnelt Scan, stoppt jedoch das Scannen an einer neuen Zeile und nach dem letzten Element muss eine neue Zeile oder EOF vorhanden sein.


10
Dies scheint keine Leerzeichen in der Eingabezeichenfolge zu mögen.
Hairy Chris

3
@HairyChris ja das ist seltsam. In der Dokumentation heißt es, dass stops scanning at a newline and after the final item there must be a newline or EOFich nicht sicher bin, warum der Weltraum es "kaputt macht" ... Ich denke, es ist ein Fehler
Karantan

6
Hierfür wurde ein Fehler geöffnet: github.com/golang/go/issues/5703 Es wurde als WorkingAsIntended geschlossen. Siehe auch: stackoverflow.com/questions/24005899/… und groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Es scheint, dass viele Leute Probleme damit haben. Dokumentationsänderung erforderlich? Außerdem aus diesem letzten Link: "Scan und Scanln dienen zum Parsen und dergleichen. Wenn Sie also nur eine einzige Textzeile von stdin erhalten, wird der Zweck zunichte gemacht."
user2707671

Für mich ist es wirklich verwirrend, dass fmt.Scan in einer seiner ähnlichen Funktionen nicht gut mit Leerzeichen spielt, wie es der bufio.NewReader tut.
FilBot3

3
Das gleiche Problem mit Leerzeichen bleibt während der Verwendung fmt.Scanlnund fmt.Scanmit der aktuellen 2016 go-Version (go-Version go1.6.2 linux / amd64) bestehen.
Chiheb Nexus

30

Versuchen Sie immer, den bufio.NewScanner zum Sammeln von Eingaben von der Konsole zu verwenden. Wie bereits erwähnt, gibt es mehrere Möglichkeiten, die Aufgabe zu erledigen, aber Scanner ist ursprünglich für die Ausführung der Aufgabe vorgesehen. Dave Cheney erklärt, warum Sie Scanner anstelle von bufio.Reader's ReadLine verwenden sollten.

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

Hier ist die Code-Snippet-Antwort für Ihre Frage

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

Wenn Sie die Eingaben nicht programmgesteuert erfassen möchten, fügen Sie einfach diese Zeilen hinzu

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

Die Ausgabe des obigen Programms lautet:

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

Das obige Programm sammelt die Benutzereingaben und speichert sie in einem Array. Wir können diesen Fluss auch mit einem besonderen Charakter unterbrechen. Der Scanner bietet eine API für die erweiterte Verwendung wie das Aufteilen mithilfe einer benutzerdefinierten Funktion usw., das Scannen verschiedener Arten von E / A-Streams (Stdin, String) usw.


Dies sollte die akzeptierte Antwort sein. Es ist nicht nur eine genauere Antwort, sondern auch von besserer Qualität.
Daniel Farrell

11

Eine andere Möglichkeit, mehrere Eingaben innerhalb einer Schleife zu lesen, die eine Eingabe mit Leerzeichen verarbeiten kann:

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

Ausgabe:

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
Sie könnten vielleicht einfach eine Pause in der inneren "q" -Prüfung verwenden und alles in eine Endlosschleife einwickeln. Tolle Antwort übrigens!
Tebanep

2
Sieht so aus, als könnten Sie jetzt auch die Bedingung in der for-Schleife entfernen.
Irbanana

6

Ich bin zu spät zur Party. Aber wie wäre es mit einem Liner:

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

und drücken Sie Strg + d (EOT), sobald die Eingabe in die Befehlszeile eingegeben wurde.


Weil os.Stdines nicht "endet", ist es unmöglich, alles zu lesen. Sie könnten eine Weile warten ...
Gypsydave5

2
Drücken Sie Strg + d, dh eot.
Shivendra Mishra

3
Ja, das würde es tun - erinnert mich an das Schreiben von E-Mails mit mail.
Gypsydave5

5

Versuchen Sie diesen Code: -

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

3
Scheint, als würde er Scanf()keine Leerzeichen in der Zeichenfolge akzeptieren
Eslam

4

Kann auch so gemacht werden: -

package main
import "fmt"     

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

3

Lesen Sie einige angeforderte Werte sauber ein:

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

Hier ist ein Lauf:

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

2
Auch ein guter Weg, da Strings.TrimSpace das '\ n' entfernt. Und ich glaube, Leser. ReadString ('\ n') ist auch plattformübergreifend.
user2707671

Ich vermute, dass Sie die meiste Zeit standardmäßig \ n entfernen möchten, weshalb es besser ist, bufio.NewScanner als @Naren Yellavula Antwort
John Balvin Arias

2

Sie müssen einen Zeiger auf die Variable bereitstellen, die Sie scannen möchten, wie folgt:

fmt.scan(&text2)

0

In meinem Fall wartete das Programm nicht, da ich den watcherBefehl zum automatischen Ausführen des Programms verwendete. Das manuelle Ausführen des Programms go run main.goführte zu "Text eingeben" und schließlich zum Drucken auf der Konsole.

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

2
Die Einschränkung der Scan*Familie besteht darin, dass sie bis zu einem Leerzeichen (z. B. Leerzeichen) lesen.
George Tseres
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.