Comment lire à partir d'une entrée standard dans la console?


270

Je voudrais lire l'entrée standard à partir de la ligne de commande, mais mes tentatives se sont terminées avec la fermeture du programme avant que je ne sois invité à entrer. Je cherche l'équivalent de Console.ReadLine () en C #.

Voici ce que j'ai actuellement:

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

Ce code semble correct. Par curiosité, exécutez-vous cela sur le Playground? Go Playground n'autorise pas l'entrée stdin pour des raisons de mise en réseau.
LinearZoetrope

Peu importe, cela semble être un problème subtil où vous aviez besoin d'un pointeur (voir ma réponse). Bien que je ne sois pas sûr du problème avec la méthode bufio.NewReader car elle fonctionne pour moi.
LinearZoetrope


8
Ne mélangez pas la bufiomise en mémoire tampon d'un lecteur (par exemple bufio.NewReader(os.Stdin)) avec les lectures directes du lecteur soulignant (par exemple, les lectures directes fmt.Scanln(x)depuis os.Stdin). La mise en mémoire tampon peut se lire arbitrairement très loin. (Dans ce cas spécifique, la dernière doit être fmt.Fscanln(reader,x)de lire à partir du même tampon).
Dave C

Je ne reçois pas de fmt.Sscanlntravaux, il devient "% v" après l'exécution
Beeno Tung

Réponses:


295

Je ne sais pas ce qui ne va pas avec le bloc

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

Comme cela fonctionne sur ma machine. Cependant, pour le bloc suivant, vous avez besoin d'un pointeur sur les variables auxquelles vous affectez l'entrée. Essayez de remplacer fmt.Scanln(text2)par fmt.Scanln(&text2). N'utilisez pas Sscanln, car il analyse une chaîne déjà en mémoire au lieu de stdin. Si vous voulez faire quelque chose comme ce que vous essayez de faire, remplacez-le parfmt.Scanf("%s", &ln)

Si cela ne fonctionne toujours pas, votre coupable pourrait être des paramètres système étranges ou un IDE buggy.


2
Sont-ils censés être des guillemets simples? ReadString('\n')ou ReadString("\n")?
425nep

8
@ 425nesp oui, c'est le délimiteur, qui est un seul octet. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Bonne réponse, mais cela échoue lorsque j'essaie d'utiliser les touches de retour arrière, etc.
kumarharsh

4
Tant pour golang lire une ligne de fichier via un lecteur rdà la variable scommeif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Je partage juste une chose intéressante (je suis un débutant de Golang): \ n doit être entre guillemets simples (n'essayez pas d'utiliser des guillemets doubles). Ou bien, il reproduira ceci:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz

124

vous pouvez aussi essayer:

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

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

6
Vous pouvez supprimer le "pour {}" si vous voulez juste une entrée ligne par ligne.
user2707671

3
s'il y a une boucle for {}, comment sortir de la boucle en entrant? Y a-t-il un caractère spécial qui fera s'arrêter la boucle? - Merci
Madhan Ganesh

2
@Madhan scanner.Scan () renvoie une valeur booléenne pour indiquer de quitter la boucle for ou non.
Helin Wang

5
Vous obtiendrez cette erreur bufio.Scanner: jeton trop long Si votre entrée est supérieure à 64 * 1024 octets. N'oubliez pas non plus d'ajouter fmt.Println(scanner.Err())sous la boucle for.
Yuvaraj Loganathan

Que faire si j'entre "abc \ n ^ D", la chaîne attendue est "abc \ n" mais elle renvoie "abc".
Shivendra Mishra

96

Je pense qu'une façon plus standard de procéder serait:

package main

import "fmt"

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

Jetez un œil au scangodoc: http://godoc.org/fmt#Scan

Scan analyse le texte lu à partir de l'entrée standard, stockant les valeurs séparées par des espaces successifs dans des arguments successifs. Les sauts de ligne comptent comme de l'espace.

Scanln est similaire à Scan, mais arrête de numériser sur une nouvelle ligne et après le dernier élément, il doit y avoir une nouvelle ligne ou EOF.


10
Cela ne semble pas aimer les espaces dans la chaîne d'entrée.
Hairy Chris

3
@HairyChris oui c'est étrange. Dans le doc, il est dit que stops scanning at a newline and after the final item there must be a newline or EOFsi pas sûr pourquoi l'espace le "casse" ... Je suppose que c'est un bug
karantan

6
Un bogue a été ouvert pour cela: github.com/golang/go/issues/5703 Il a été fermé en tant que WorkingAsIntended. Voir aussi: stackoverflow.com/questions/24005899/… et groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Il semble que beaucoup de gens aient des problèmes avec cela. Un changement de documentation est nécessaire? En outre, à partir de ce dernier lien: "Scan et Scanln sont pour l'analyse et des trucs comme ça, donc obtenir une seule ligne de texte de stdin irait à l'encontre du but."
user2707671

Pour moi, c'est vraiment déroutant que fmt.Scan dans l'une de ses fonctions similaires ne joue pas bien avec des espaces comme le bufio.NewReader.
FilBot3

3
Le même problème avec les espaces persiste lors de l'utilisation fmt.Scanlnet fmt.Scande la version go 2016 actuelle (version go go1.6.2 linux / amd64).
Chiheb Nexus

30

Essayez toujours d'utiliser bufio.NewScanner pour collecter les entrées de la console. Comme d'autres l'ont mentionné, il existe plusieurs façons de faire le travail, mais le scanner est initialement destiné à le faire. Dave Cheney explique pourquoi vous devriez utiliser Scanner au lieu de bufio.Reader ReadLine.

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

Voici la réponse d'extrait de code pour votre question

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

Si vous ne voulez pas collecter par programmation les entrées, ajoutez simplement ces lignes

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

Le résultat du programme ci-dessus sera:

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

Le programme ci-dessus recueille les entrées utilisateur et les enregistre dans un tableau. Nous pouvons également briser ce flux avec un caractère spécial. Le scanner fournit une API pour une utilisation avancée comme le fractionnement à l'aide d'une fonction personnalisée, etc., l'analyse de différents types de flux d'E / S (Stdin, String), etc.


Ce devrait être la réponse acceptée. Non seulement c'est une réponse plus précise, mais elle est de meilleure qualité.
Daniel Farrell

11

Une autre façon de lire plusieurs entrées dans une boucle qui peut gérer une entrée avec des espaces:

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

Production:

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
Vous pourriez peut-être simplement utiliser une pause dans la vérification intérieure du «q» et envelopper le tout dans une boucle infinie. Excellente réponse au fait!
tebanep

2
Il semble que vous puissiez également vous débarrasser du conditionnel dans la boucle for.
irbanana

6

Je suis en retard à la fête. Mais que diriez-vous d'une doublure:

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

et appuyez sur ctrl + d (EOT) une fois l'entrée entrée sur la ligne de commande.


Parce que os.Stdinça ne «finit» pas, il est impossible de tout lire. Vous pourriez attendre un peu ...
gypsydave5

2
appuyez sur ctrl + d, c'est-à-dire eot.
Shivendra Mishra

3
Oui, ça le ferait - ça me rappelle d'écrire des e-mails avec mail.
gypsydave5

5

Essayez ce code: -

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

3
Il semble que Scanf()n'accepte pas les espaces blancs dans la chaîne
Eslam

4

Peut aussi se faire comme ceci: -

package main
import "fmt"     

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

3

Lisez proprement dans quelques valeurs invitées:

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

Voici une course:

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

2
Aussi une bonne façon depuis strings.TrimSpace supprime le '\ n'. Et je crois que reader.ReadString ('\ n') est également multiplateforme.
user2707671

Je suppose que la plupart du temps, vous voulez supprimer \ n par défaut, c'est pourquoi il vaut mieux bufio.NewScanner comme @Naren Yellavula réponse
John Balvin Arias

2

Vous devez fournir un pointeur sur la var que vous souhaitez numériser, comme ceci:

fmt.scan(&text2)

0

Dans mon cas, le programme n'attendait pas car j'utilisais la watchercommande pour exécuter automatiquement le programme. L'exécution manuelle du programme a go run main.goentraîné la «saisie de texte» et finalement l'impression sur la console.

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

2
La limitation de la Scan*famille est qu'elle lit jusqu'à un séparateur d'espaces (par exemple un espace).
George Tseres
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.