Come leggere dall'input standard nella console?


270

Vorrei leggere l'input standard dalla riga di comando, ma i miei tentativi sono terminati con l'uscita del programma prima che mi venga richiesto di immettere. Sto cercando l'equivalente di Console.ReadLine () in C #.

Questo è quello che ho attualmente:

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

Questo codice sembra corretto. Per curiosità, stai eseguendo questo nel Playground? Go Playground non consente l'input di stdin per motivi di rete.
LinearZoetrope

Non importa, sembra essere un problema sottile in cui hai bisogno di un puntatore (vedi la mia risposta). Anche se non sono sicuro di quale sia il problema con il metodo bufio.NewReader poiché funziona per me.
LinearZoetrope


8
Non mescolare il bufiobuffering di alcun lettore (ad es. bufio.NewReader(os.Stdin)) Con letture dirette del lettore sottolineato (ad es. fmt.Scanln(x)Letture dirette da os.Stdin). Il buffering può essere letto in modo arbitrario molto più avanti. (In questo caso specifico il secondo dovrebbe essere fmt.Fscanln(reader,x)quello di leggere dallo stesso buffer).
Dave C,

Non ottengo fmt.Sscanlnlavori, diventa "% v" dopo l'esecuzione
Beeno Tung

Risposte:


295

Non sono sicuro di cosa c'è che non va nel blocco

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

Come funziona sulla mia macchina. Tuttavia, per il blocco successivo è necessario un puntatore alle variabili a cui si sta assegnando l'input. Prova a sostituirlo fmt.Scanln(text2)con fmt.Scanln(&text2). Non usare Sscanln, perché analizza una stringa già in memoria anziché da stdin. Se vuoi fare qualcosa di simile a quello che stavi cercando di fare, sostituiscilo confmt.Scanf("%s", &ln)

Se il problema persiste, il tuo colpevole potrebbe essere una strana impostazione del sistema o un IDE errato.


2
Quelle dovrebbero essere virgolette singole? ReadString('\n')o ReadString("\n")?
425nesp

8
@ 425nesp sì, quello è il delimitatore, che è un singolo byte. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Buona risposta, ma questo non riesce quando provo ad usare i tasti backspace, ecc.
kumarharsh,

4
Tanto per Golang leggere una riga dal file tramite il lettore rdalla variabile scomeif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU,

2
Sto solo condividendo una cosa interessante (sono un principiante di Golang): \ n deve essere racchiuso tra virgolette singole (non provare a usare virgolette doppie). Oppure riprodurrà questo:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz il

124

puoi anche provare:

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

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

6
È possibile rimuovere "for {}" se si desidera solo un input di una riga.
user2707671

3
se esiste un ciclo for {}, come uscire dal ciclo quando si entra? C'è un personaggio speciale che farà fermare il loop? - Grazie
Madhan Ganesh il

2
@Madhan scanner.Scan () restituisce un valore booleano per indicare l'uscita dal ciclo for o meno.
Helin Wang,

5
Verrà visualizzato questo errore bufio.Scanner: token troppo lungo Se l'input è maggiore di 64 * 1024 byte. Inoltre, non dimenticare di aggiungere fmt.Println(scanner.Err())sotto il ciclo for.
Yuvaraj Loganathan,

Cosa succede se inserisco "abc \ n ^ D", la stringa prevista è "abc \ n" ma restituisce "abc".
Shivendra Mishra,

96

Penso che un modo più standard per farlo sarebbe:

package main

import "fmt"

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

Dai un'occhiata al scangodoc: http://godoc.org/fmt#Scan

La scansione esegue la scansione del testo letto dallo standard input, memorizzando i valori successivi separati da spazi in argomenti successivi. Newline conta come spazio.

Scanln è simile a Scan, ma interrompe la scansione su una nuova riga e dopo l'elemento finale deve esserci una nuova riga o EOF.


10
Questo non sembra gradire gli spazi nella stringa di input.
Peloso Chris,

3
@HairyChris sì, è strano. Nel documento dice che stops scanning at a newline and after the final item there must be a newline or EOFquindi non sono sicuro del perché lo spazio "lo rompa" ... Immagino che sia un bug
Karantan,

6
È stato aperto un bug per questo: github.com/golang/go/issues/5703 È stato chiuso come WorkingAsIntended. Vedi anche: stackoverflow.com/questions/24005899/… e groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Sembra che molte persone abbiano problemi con questo. È necessario modificare la documentazione? Inoltre, da quell'ultimo link: "Scan e Scanln sono per l'analisi e cose del genere, quindi solo ottenere una singola riga di testo da stdin avrebbe vanificato lo scopo."
user2707671

Per me, è davvero confuso che fmt.Scan in una qualsiasi delle sue funzioni simili non giochi bene con spazi come bufio.NewReader.
FilBot3,

3
Lo stesso problema con gli spazi rimane durante l'utilizzo fmt.Scanlne fmt.Scancon l'attuale versione go 2016 (vai versione go1.6.2 linux / amd64).
Chiheb Nexus,

30

Cerca sempre di utilizzare bufio.NewScanner per raccogliere input dalla console. Come altri hanno già detto, esistono diversi modi per eseguire il lavoro, ma lo scanner è originariamente destinato a fare il lavoro. Dave Cheney spiega perché dovresti usare Scanner invece di bufio.Reader ReadLine.

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

Ecco la risposta dello snippet di codice per la tua domanda

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

Se non si desidera raccogliere programmaticamente gli input, è sufficiente aggiungere queste righe

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

L'output del programma sopra sarà:

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

Il programma sopra raccoglie l'input dell'utente e li salva in un array. Possiamo anche interrompere quel flusso con un personaggio speciale. Scanner fornisce API per un uso avanzato come la divisione mediante una funzione personalizzata ecc., La scansione di diversi tipi di flussi I / O (Stdin, String) ecc.


Questa dovrebbe essere la risposta accettata. Non solo è una risposta più accurata, ma è di migliore qualità.
Daniel Farrell, il

11

Un altro modo per leggere più input all'interno di un loop in grado di gestire un input con spazi:

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

Produzione:

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
Potresti semplicemente usare una pausa nel controllo "q" interno e avvolgerlo in un ciclo infinito. Ottima risposta a proposito!
Tebanep,

2
Sembra che ora puoi anche sbarazzarti del condizionale nel ciclo for.
irbanana,

6

Sono in ritardo alla festa. Ma che ne dici di un liner:

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

e premere ctrl + d (EOT) una volta immesso l'ingresso nella riga di comando.


Perché os.Stdinnon "finisce" è impossibile leggere tutto. Potresti aspettare un po '...
gypsydave5

2
premi ctrl + d cioè eot.
Shivendra Mishra,

3
Sì, lo farebbe - mi ricorda di scrivere e-mail con mail.
gypsydave5,

5

Prova questo codice: -

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

3
Sembra Scanf()che non accetti spazi bianchi nella stringa
Eslam

4

Può anche essere fatto in questo modo: -

package main
import "fmt"     

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

3

Leggi in modo chiaro in un paio di valori richiesti:

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

Ecco una corsa:

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

2
Anche un bel modo da quando stringhe. TrimSpace rimuove '\ n'. E credo che reader.ReadString ('\ n') sia anche multipiattaforma.
user2707671

Immagino che la maggior parte delle volte desideri rimuovere \ n per impostazione predefinita, è per questo che è meglio bufio.NewScanner come @Naren Yellavula risponde
John Balvin Arias,

2

Devi fornire un puntatore al var che vuoi scansionare, in questo modo:

fmt.scan(&text2)

0

Nel mio caso, il programma non era in attesa perché stavo usando il watchercomando per eseguire automaticamente il programma. L'esecuzione manuale del programma ha go run main.gocomportato "Immettere testo" e infine stampare sulla console.

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

2
Il limite della Scan*famiglia è che leggono fino a un separatore di spazi bianchi (ad es. Spazio).
George Tseres il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.