Как читать со стандартного ввода в консоли?


270

Я хотел бы прочитать стандартный ввод из командной строки, но мои попытки закончились выходом из программы, прежде чем меня попросят ввести. Я ищу эквивалент Console.ReadLine () в C #.

Вот что у меня сейчас есть:

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

Этот код выглядит правильно. Из любопытства вы запускаете это на детской площадке? Go Playground не позволяет вводить стандартный ввод по сетевым причинам.
— LinearZoetrope

Неважно, это выглядит тонкой проблемой, когда вам нужен указатель (см. Мой ответ). Хотя я не уверен, в чем проблема с методом bufio.NewReader, так как он работает для меня.
— LinearZoetrope


8
Не смешивайте bufioбуферизацию любого считывателя (например bufio.NewReader(os.Stdin)) с прямым чтением из подчеркивающего считывателя (например, fmt.Scanln(x)непосредственно из чтения os.Stdin). Буферизация может читать произвольно далеко вперед. (В этом конкретном случае последнее должно быть fmt.Fscanln(reader,x)прочитано из того же буфера).
— Дэйв С

Я не получаю fmt.Sscanlnработы, он становится "% v" после запуска
— Beeno Tung

Ответы:


295

Я не уверен, что не так с блоком

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

Как это работает на моей машине. Однако для следующего блока вам нужен указатель на переменные, которым вы назначаете вход. Попробуйте заменить fmt.Scanln(text2)на fmt.Scanln(&text2). Не используйте Sscanln, потому что он анализирует строку уже в памяти, а не из стандартного ввода. Если вы хотите сделать что-то вроде того, что вы пытались сделать, замените это наfmt.Scanf("%s", &ln)

Если это все еще не работает, ваш виновник может быть странными настройками системы или глючной IDE.


2
Это должны быть одинарные кавычки? ReadString('\n')или ReadString("\n")?
— 425 июн

8
@ 425nesp да, это разделитель, который представляет собой один байт. golang.org/pkg/bufio/#Reader.ReadString
— LinearZoetrope

3
Хороший ответ, но это не удается, когда я пытаюсь использовать клавиши
— Backspace и

4
Так много для Голанга, чтобы прочитать строку из файла через считыватель rdв переменную, sкакif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
— Nam G VU

2
Просто делюсь интересной вещью (я новичок в Голанге): \ n должно быть в одинарных кавычках (не пытайтесь использовать двойные кавычки). Или же, это воспроизведет это:cannot use "\n" (type string) as type byte in argument to reader.ReadString
— ivanleoncz

124

Вы также можете попробовать:

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

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

6
Вы можете удалить «for {}», если вы просто хотите один ввод строки.
— user2707671

3
если есть цикл for {}, как выйти из цикла при входе? Есть ли специальный символ, который заставит цикл остановиться? - Спасибо
— Мадхан Ганеш

2
@Madhan scanner.Scan () возвращает значение bool для указания выхода из цикла for или нет.
— Хелин Ван

5
Вы получите эту ошибку bufio.Scanner: слишком длинный токен, если ваш ввод больше 64 * 1024 байт. Также не забудьте добавить fmt.Println(scanner.Err())ниже для цикла.
— Юварадж Логанатан

Что если я введу «abc \ n ^ D», ожидаемая строка будет «abc \ n», но вернет «abc».
— Шивендра Мишра

96

Я думаю, что более стандартный способ сделать это будет:

package main

import "fmt"

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

Посмотрите на scanГодока: http://godoc.org/fmt#Scan

Сканирование сканирует текст, прочитанный со стандартного ввода, сохраняя последовательные разделенные пробелами значения в последовательных аргументах. Новые строки считаются пробелом.

Scanln похож на Scan, но останавливает сканирование на новой строке, и после последнего элемента должен быть символ новой строки или EOF.


10
Это не похоже на пробелы во входной строке.
— Волосатый Крис

3
@HairyChris да, это странно. В документе написано, что stops scanning at a newline and after the final item there must be a newline or EOFтак не уверен, почему космос "ломает" его ... Я думаю, это ошибка
— Карантан

6
Для этого была открыта ошибка: github.com/golang/go/issues/5703 Она была закрыта как WorkingAsIntended. См. Также: stackoverflow.com/questions/24005899/… and groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0 Кажется, у многих людей есть проблемы с этим. Требуется изменение документации? Кроме того, из этой последней ссылки: «Scan и Scanln предназначены для синтаксического анализа и тому подобного, поэтому просто получение одной строки текста из stdin может нанести ущерб цели».
— user2707671

Для меня это действительно сбивает с толку, что fmt.Scan в любой из его похожих функций плохо работает с пробелами, как bufio.NewReader.
— FilBot3

3
Та же проблема с пробелами остается при использовании fmt.Scanlnи fmt.Scanс текущей версией 2016 года go (версия go go 1.6.6 linux / amd64).
— Chiheb Nexus

30

Всегда старайтесь использовать bufio.NewScanner для сбора данных с консоли. Как уже упоминалось, есть несколько способов сделать эту работу, но изначально Сканер предназначен для этой работы. Дейв Чейни объясняет, почему вы должны использовать Scanner вместо ReadLine bufio.Reader.

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

Вот фрагмент кода ответа на ваш вопрос

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

Если вы не хотите программно собирать данные, просто добавьте эти строки

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

Вывод вышеуказанной программы будет:

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

Выше программа собирает пользовательский ввод и сохраняет его в массив. Мы также можем разорвать этот поток с помощью специального символа. Сканер предоставляет API для расширенного использования, такого как разделение с использованием пользовательских функций и т. Д., Сканирование различных типов потоков ввода-вывода (Stdin, String) и т. Д.


Это должен быть принятый ответ. Это не только более точный ответ, но и более качественный.
— Даниэль Фаррелл

11

Другой способ прочитать несколько входов в цикле, который может обрабатывать ввод с пробелами:

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

Вывод:

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
Вы можете просто использовать разрыв во внутренней проверке "q" и обернуть все это в бесконечный цикл. Отличный ответ, кстати!
— февраля

2
Похоже, теперь вы также можете избавиться от условного в цикле for.
— ирбанана

6

Я опоздал на вечеринку. Но как насчет одного лайнера:

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

и нажмите Ctrl + D (EOT), как только ввод введен в командной строке.


Потому os.Stdinчто не заканчивается, невозможно все это прочитать. Вы могли бы подождать некоторое время ...
— gypsydave5

2
нажмите Ctrl + D, т. е.
— Шивендра Мишра

3
Да, это сделало бы - напоминает мне о написании электронных писем с mail.
— gypsydave5

5

Попробуйте этот код: -

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

3
Похоже Scanf(), не принимает пробелы в строке
— Eslam

4

Также можно сделать так:

package main
import "fmt"     

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

3

Прочитайте в пару подсказок:

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

Вот бег:

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

2
Также хороший способ, так как strings.TrimSpace удаляет '\ n'. И я считаю, что reader.ReadString ('\ n') тоже кроссплатформенный.
— user2707671

Я предполагаю, что большую часть времени вы хотите удалить \ n по умолчанию, поэтому лучше bufio.NewScanner как ответ @Naren Yellavula
— Джон Балвин Ариас

2

Вам нужно указать указатель на переменную, которую вы хотите сканировать, например:

fmt.scan(&text2)

0

В моем случае программа не ждала, потому что я использовал watcherкоманду для автоматического запуска программы. Запуск программы вручную go run main.goпривел к «Вводу текста» и, в конечном итоге, к печати на консоли.

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

2
Ограничение Scan*семейства состоит в том, что они читают до разделителя пробела (например, пробела).
— Джордж Церес
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.