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


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.