Jak czytać ze standardowego wejścia w konsoli?


270

Chciałbym odczytać standardowe dane wejściowe z wiersza poleceń, ale moje próby zakończyły się wyjściem programu przed wyświetleniem monitu o wprowadzenie danych. Szukam odpowiednika Console.ReadLine () w C #.

Oto, co obecnie mam:

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

Ten kod wygląda poprawnie. Z ciekawości, uruchamiasz to na placu zabaw? Go Playground nie zezwala na wejście standardowego wejścia z powodów sieciowych.
LinearZoetrope

Niemniej jednak wydaje się, że jest to subtelny problem, w którym potrzebujesz wskaźnika (zobacz moją odpowiedź). Chociaż nie jestem pewien, na czym polega problem z metodą bufio.NewReader, ponieważ działa ona dla mnie.
LinearZoetrope


8
Nie mieszaj bufiobuforowania żadnego czytnika (np. bufio.NewReader(os.Stdin)) Z bezpośrednimi odczytami z podkreślającego czytnika (np. fmt.Scanln(x)Bezpośrednio z os.Stdin). Buforowanie może być odczytywane dowolnie daleko w przód. (W tym konkretnym przypadku później należy fmt.Fscanln(reader,x)odczytać z tego samego bufora).
Dave C

Nie dostaję fmt.Sscanlnprac, po uruchomieniu staje się „% v”
Beeno Tung

Odpowiedzi:


294

Nie jestem pewien, co jest nie tak z blokiem

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

Jak to działa na moim komputerze. Jednak do następnego bloku potrzebujesz wskaźnika do zmiennych, do których przypisujesz dane wejściowe. Spróbuj wymienić fmt.Scanln(text2)z fmt.Scanln(&text2). Nie używaj Sscanln, ponieważ analizuje ciąg znaków już w pamięci zamiast ze standardowego wejścia. Jeśli chcesz zrobić coś takiego, co próbujesz zrobić, zastąp tofmt.Scanf("%s", &ln)

Jeśli to nadal nie działa, twoim winowajcą mogą być jakieś dziwne ustawienia systemowe lub błędne IDE.


2
Czy to mają być pojedyncze cytaty? ReadString('\n')czy ReadString("\n")?
425nesp,

8
@ 425nesp tak, to jest delimetr, który jest pojedynczym bajtem. golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
Dobra odpowiedź, ale to się nie udaje, gdy próbuję użyć klawiszy Backspace itp.
Kumarharsh

4
Tyle, że Golang mógł czytać wiersz z pliku przez czytnik rddo zmiennej sjakoif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
Po prostu dzielę się interesującą rzeczą (jestem początkującym Golangiem): \ n musi znajdować się w pojedynczych cudzysłowach (nie próbuj używać podwójnych cudzysłowów). W przeciwnym razie odtworzy to:cannot use "\n" (type string) as type byte in argument to reader.ReadString
ivanleoncz,

124

możesz również spróbować:

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

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

6
Możesz usunąć „for {}”, jeśli chcesz tylko jeden wiersz.
user2707671

3
jeśli istnieje pętla for {}, jak wyjść z pętli podczas wchodzenia? Czy jest jakiś specjalny znak, który sprawi, że pętla się zatrzyma? - Dzięki
Madhan Ganesh

2
@Madhan scanner.Scan () zwraca wartość bool wskazującą wyjście z pętli for lub nie.
Helin Wang

5
Otrzymasz ten błąd bufio.Scanner: token za długi Jeśli Twój wpis jest większy niż 64 * 1024 bajtów. Nie zapomnij również dodać fmt.Println(scanner.Err())poniżej pętli for.
Yuvaraj Loganathan

Co jeśli wprowadzę „abc \ n ^ D”, oczekiwany ciąg to „abc \ n”, ale zwraca „abc”.
Shivendra Mishra,

96

Myślę, że bardziej standardowym sposobem na to byłoby:

package main

import "fmt"

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

Spójrz na scangodoc: http://godoc.org/fmt#Scan

Skanuje skanuje tekst odczytany ze standardowego wejścia, przechowując kolejne wartości oddzielone spacją w kolejnych argumentach. Nowe linie liczą się jako spacja.

Scanln jest podobny do skanowania, ale zatrzymuje skanowanie w nowej linii, a po ostatnim elemencie musi znajdować się nowa linia lub EOF.


10
To wydaje się nie lubić spacji w ciągu wejściowym.
Hairy Chris,

3
@HairyChris tak, to dziwne. W dokumencie jest napisane, że stops scanning at a newline and after the final item there must be a newline or EOFnie jestem pewien, dlaczego przestrzeń go „łamie” ... Myślę, że to błąd
karantan

6
Został otwarty błąd: github.com/golang/go/issues/5703 Został zamknięty jako WorkingAsIntended. Zobacz także: stackoverflow.com/questions/24005899/... and groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Wydaje się, że wiele osób ma z tym problemy. Czy potrzebujesz zmiany dokumentacji? Ponadto z tego ostatniego linku: „Skanowanie i skanowanie są przeznaczone do analizowania i tym podobne, więc uzyskanie pojedynczego wiersza tekstu ze standardowego standardu byłoby niemożliwe.”
user2707671

Dla mnie to naprawdę mylące, że fmt.Scan w którejkolwiek z podobnych funkcji nie działa dobrze ze spacjami, takimi jak bufio.NewReader.
FilBot3

3
Ten sam problem ze spacjami pozostaje podczas używania fmt.Scanlni fmt.Scanbieżącej wersji go 2016 (wersja go1.6.2 linux / amd64).
Chiheb Nexus,

30

Zawsze staraj się używać bufio.NewScanner do zbierania danych wejściowych z konsoli. Jak wspomniano inni, istnieje wiele sposobów wykonania zadania, ale skaner pierwotnie miał na celu wykonanie zadania. Dave Cheney wyjaśnia, dlaczego warto używać skanera zamiast bufio.Reader's ReadLine.

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

Oto odpowiedź na fragment kodu dla twojego pytania

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

Jeśli nie chcesz programowo zbierać danych wejściowych, po prostu dodaj te wiersze

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

Wyjście powyższego programu będzie:

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

Powyższy program zbiera dane wejściowe użytkownika i zapisuje je w tablicy. Możemy również przerwać ten przepływ specjalnym charakterem. Skaner zapewnia interfejs API do zaawansowanych zastosowań, takich jak dzielenie przy użyciu funkcji niestandardowej itp., Skanowanie różnych typów strumieni we / wy (Stdin, String) itp.


To powinna być zaakceptowana odpowiedź. Jest to nie tylko dokładniejsza odpowiedź, ale ma lepszą jakość.
Daniel Farrell

11

Innym sposobem odczytu wielu danych wejściowych w pętli, które mogą obsłużyć dane wejściowe ze spacjami:

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

Wynik:

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
Możesz po prostu użyć przerwy w wewnętrznej kontroli „q” i owinąć to wszystko w nieskończoną pętlę. Nawiasem mówiąc, świetna odpowiedź!
tebanep

2
Wygląda na to, że teraz możesz także pozbyć się warunku w pętli for.
irbanana

6

Jestem spóźniony na przyjęcie. Ale co powiesz na jedną wkładkę:

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

i naciśnij ctrl + d (EOT) po wprowadzeniu danych w wierszu poleceń.


Ponieważ os.Stdinnie kończy się, nie można przeczytać wszystkiego. Być może czekasz chwilę ...
gypsydave5

2
naciśnij ctrl + d tj. eot.
Shivendra Mishra

3
Tak, to by wystarczyło - przypomina mi pisanie e-maili mail.
gypsydave5,

5

Wypróbuj ten kod: -

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

3
Wygląda na to, Scanf()że nie akceptuje białych znaków w łańcuchu
Eslam

4

Można to również zrobić w następujący sposób:

package main
import "fmt"     

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

3

Wyczyść kilka podpowiedzi:

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

Oto przebieg:

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

2
Również miły sposób, ponieważ ciągi. TrimSpace usuwa „\ n”. I wierzę, że reader.ReadString ('\ n') jest także wieloplatformowy.
user2707671

Domyślam się, że przez większość czasu chcesz domyślnie usunąć \ n, dlatego lepiej jest buforio.NewScanner jako @Naren Yellavula odpowiedź
John Balvin Arias

2

Musisz podać wskaźnik do zmiennej, którą chcesz skanować, na przykład:

fmt.scan(&text2)

0

W moim przypadku program nie czekał, ponieważ użyłem watcherpolecenia do automatycznego uruchomienia programu. Ręczne uruchomienie programu go run main.gospowodowało „Wprowadź tekst” i ostatecznie drukowanie na konsoli.

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

2
Ograniczeniem Scan*rodziny jest to, że czytają do separatora białych znaków (np. Spacji).
George Tseres,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.