Como ler da entrada padrão no console?


270

Gostaria de ler a entrada padrão na linha de comando, mas minhas tentativas foram encerradas com a saída do programa antes de ser solicitada a entrada. Estou procurando o equivalente de Console.ReadLine () em c #.

Isto é o que eu tenho atualmente:

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

Este código parece correto. Por curiosidade, você está executando isso no Playground? O Go Playground não permite entrada stdin devido a razões de rede.
LinearZoetrope

Deixa pra lá, parece ser uma questão sutil em que você precisava de um ponteiro (veja minha resposta). Embora eu não tenha certeza de qual é o problema com o método bufio.NewReader, pois funciona para mim.
LinearZoetrope


8
Não misture bufiobuffer de qualquer leitor (por exemplo bufio.NewReader(os.Stdin)) com leituras diretas do leitor subjacente (por exemplo, fmt.Scanln(x)leia diretamente de os.Stdin). O buffer pode ler arbitrariamente muito à frente. (Nesse caso específico, o último deve ser fmt.Fscanln(reader,x)a leitura do mesmo buffer).
Dave C

Eu não entendo fmt.Sscanlnobras, torna-se "% v" após a execução
Beeno Tung

Respostas:


295

Não tenho certeza do que há de errado com o bloco

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

Como funciona na minha máquina. No entanto, para o próximo bloco, você precisa de um ponteiro para as variáveis ​​às quais está atribuindo a entrada. Tente substituir fmt.Scanln(text2)por fmt.Scanln(&text2). Não use Sscanln, porque analisa uma string já na memória, em vez de no stdin. Se você quiser fazer algo parecido com o que estava tentando fazer, substitua-o porfmt.Scanf("%s", &ln)

Se isso ainda não funcionar, seu culpado pode ser algumas configurações estranhas do sistema ou um IDE com bugs.


2
Essas devem ser aspas simples? ReadString('\n')ou ReadString("\n")?
425nesp

8
@ 425nesp sim, esse é o delímetro, que é um único byte. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Boa resposta, mas isso falhar quando eu tento usar backspace, chaves, etc
kumarharsh

4
Tanto para Golang ler uma linha do arquivo através do leitor rdpara a variável scomoif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Apenas compartilhando uma coisa interessante (eu sou iniciante em Golang): \ n deve estar entre aspas simples (não tente usar aspas duplas). Ou então, ele reproduzirá o seguinte:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz

124

você também pode tentar:

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

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

6
Você pode remover o "for {}" se quiser apenas uma entrada de uma linha.
user2707671

3
se houver um loop for {}, como sair do loop quando você entra? Existe um caractere especial que fará com que o loop pare? - Obrigado
Madhan Ganesh

2
@Madhan scanner.Scan () retorna o valor bool para indicar sair do loop for ou não.
Helin Wang

5
Você receberá esse erro bufio.Scanner: token muito longo Se sua entrada for maior que 64 * 1024 bytes. Também não se esqueça de adicionar fmt.Println(scanner.Err())abaixo do loop for.
Yuvaraj Loganathan

E se eu digitar "abc \ n ^ D", a sequência esperada for "abc \ n", mas retorne "abc".
Shivendra Mishra

96

Eu acho que uma maneira mais padrão de fazer isso seria:

package main

import "fmt"

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

Dê uma olhada no scangodoc: http://godoc.org/fmt#Scan

A digitalização digitaliza o texto lido da entrada padrão, armazenando sucessivos valores separados por espaço em argumentos sucessivos. As novas linhas contam como espaço.

Scanln é semelhante ao Scan, mas para a digitalização em uma nova linha e após o item final deve haver uma nova linha ou EOF.


10
Parece não gostar de espaços na string de entrada.
22820 Cabeleireiro Chris

3
@HairyChris sim, isso é estranho. No doc diz que stops scanning at a newline and after the final item there must be a newline or EOFentão não tenho certeza porque o espaço "quebra" ... Eu acho que é um bug
karantan

6
Houve um erro aberto para isso: github.com/golang/go/issues/5703 Foi fechado como WorkingAsIntended. Veja também: stackoverflow.com/questions/24005899/… e groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Parece que muitas pessoas têm problemas com isso. É necessário alterar a documentação? Além disso, a partir desse último link: "Scan e Scanln são para análise e coisas assim, portanto, apenas obter uma única linha de texto de stdin derrotaria o objetivo".
user2707671

Para mim, é realmente confuso que o fmt.Scan em qualquer uma de suas funções semelhantes não funcione bem com espaços como o bufio.NewReader.
FilBot3

3
O mesmo problema com espaços permanece durante o uso fmt.Scanlne fmt.Scancom a versão atual 2016 go (versão go1.6.2 linux / amd64).
Chiheb Nexus

30

Sempre tente usar o bufio.NewScanner para coletar entradas do console. Como já mencionado, existem várias maneiras de executar o trabalho, mas o Scanner foi originalmente projetado para executar o trabalho. Dave Cheney explica por que você deve usar o Scanner em vez do ReadLine do bufio.Reader.

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

Aqui está a resposta do trecho de código para sua pergunta

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 você não deseja coletar programaticamente as entradas, basta adicionar essas linhas

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

A saída do programa acima será:

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

O programa acima coleta as entradas do usuário e as salva em uma matriz. Também podemos interromper esse fluxo com um caractere especial. O scanner fornece API para uso avançado, como divisão usando uma função personalizada, etc., varredura de diferentes tipos de fluxos de E / S (Stdin, String) etc.


Essa deve ser a resposta aceita. Não é apenas uma resposta mais precisa, mas é de melhor qualidade.
Daniel Farrell

11

Outra maneira de ler várias entradas em um loop que pode manipular uma entrada com espaços:

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

Resultado:

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
Você pode apenas usar uma quebra na verificação "q" interna e agrupar tudo em um loop infinito. Ótima resposta pelo caminho!
tebanep

2
Parece que você também pode se livrar da condicional no loop for agora.
precisa saber é o seguinte

6

Estou atrasado para a festa. Mas que tal um forro:

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

e pressione ctrl + d (EOT) quando a entrada for inserida na linha de comando.


Porque os.Stdinnão 'termina', é impossível ler tudo. Você pode estar à espera de um tempo ...
gypsydave5

2
pressione ctrl + d ou seja, eot.
Shivendra Mishra

3
Sim, isso faria - me lembra de escrever e-mails com mail.
precisa saber é o seguinte

5

Experimente este código: -

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

3
Parece que Scanf()não aceita espaços em branco na corda
Eslam

4

Também pode ser feito assim: -

package main
import "fmt"     

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

3

Leia corretamente alguns valores solicitados:

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

Aqui está uma corrida:

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

2
Também é uma boa maneira, já que o strings.TrimSpace remove o '\ n'. E eu acredito que reader.ReadString ('\ n') também é multiplataforma.
user2707671

Vou adivinhar que a maioria do tempo que deseja remover \ n por padrão, que é por isso que é melhor bufio.NewScanner como resposta @Naren Yellavula
John Balvin Arias

2

Você precisa fornecer um ponteiro para a var que deseja digitalizar, da seguinte forma:

fmt.scan(&text2)

0

No meu caso, o programa não estava esperando porque eu estava usando o watchercomando para executar automaticamente o programa. A execução manual do programa go run main.goresultou em "Inserir texto" e, eventualmente, na impressão no console.

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

2
A limitação da Scan*família é que eles leem até um separador de espaço em branco (por exemplo, espaço).
George Tseres
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.