如何从控制台的标准输入中读取?


270

我想从命令行读取标准输入,但是在提示我输入之前,我的尝试以结束程序退出而告终。我正在寻找C#中的Console.ReadLine()等效项。

这是我目前拥有的:

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 2014年

没关系,这似乎是一个微妙的问题,您需要一个指针(请参阅我的回答)。虽然我不确定bufio.NewReader方法的问题是什么,因为它适用于我。
LinearZoetrope 2014年


8
请勿将bufio任何读取器(例如bufio.NewReader(os.Stdin))的缓冲与下划线读取器(例如fmt.Scanln(x)直接从读取os.Stdin)的直接读取混合使用。缓冲可以任意向前读取。(在这种情况下,后面的应该fmt.Fscanln(reader,x)从同一缓冲区读取)。
Dave C

我没有fmt.Sscanln工作,跑步后变成“%v”
董建华

Answers:


294

我不确定块有什么问题

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

因为它可以在我的机器上使用。但是,对于下一个块,您需要一个指针,该指针指向要将输入分配给它们的变量。尝试替换fmt.Scanln(text2)fmt.Scanln(&text2)。不要使用Sscanln,因为它解析内存中已有的字符串,而不是解析来自stdin的字符串。如果您想做类似您想做的事情,请替换为fmt.Scanf("%s", &ln)

如果仍然无法解决问题,您的罪魁祸首可能是一些奇怪的系统设置或有缺陷的IDE。


2
那些应该是单引号吗?ReadString('\n')还是ReadString("\n")
425nesp

8
@ 425nesp是的,这是分隔符,它是一个字节。golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope

3
好的答案,但是当我尝试使用退格键等时,此操作失败
kumarharsh

4
这么多的Golang通过读卡器读取文件中的行rd变量sif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
南摹VU

2
只是分享一个有趣的事情(我是Golang初学者):\ 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 2016年

3
如果有for {}循环,如何在进入时从循环中出来?是否存在使循环停止的特殊字符?-谢谢
Madhan Ganesh

2
@Madhan Scanner.Scan()返回bool值,以指示是否退出for循环。
Helin Wang

5
如果输入大于64 * 1024字节,则会收到此错误bufio.Scanner:令牌太长。同样不要忘记fmt.Println(scanner.Err())在for循环下面添加。
Yuvaraj Loganathan

如果我输入“ abc \ n ^ D”,期望的字符串是“ abc \ n”,但返回“ abc”,该怎么办。
Shivendra Mishra

96

我认为更标准的方法是:

package main

import "fmt"

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

看看scangodoc: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无法确定为什么空间会“破坏”它……我想这是一个错误
karantan 2015年

6
为此打开了一个错误:github.com/golang/go/issues/5703它已作为WorkingAsIntended关闭。另请参阅:stackoverflow.com/questions/24005899/…groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0似乎很多人对此都有疑问。需要更改文档吗?同样,从最后一个链接开始:“ Scan和Scanln用于解析之类的东西,因此仅从stdin中获取一行文本就无法达到目的。”
user2707671 2016年

对我来说,fmt.Scan在其任何类似功能中的使用确实令人困惑,在bufio.NewReader这样的空间中无法很好地发挥作用。
FilBot3 '16

3
使用fmt.Scanlnfmt.Scan当前的2016 go版本(go 1.6.2 linux / amd64版本)一起使用时,仍然存在空格问题。
Chiheb Nexus

30

始终尝试使用bufio.NewScanner从控制台收集输入。正如其他人提到的那样,有多种方法可以完成这项工作,但Scanner最初是打算完成这项工作的。Dave Cheney解释了为什么应使用Scanner而不是bufio.Reader的ReadLine。

https://twitter.com/davecheney/status/604837853344989184?lang=zh-CN

这是您的问题的代码片段答案

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以供高级使用,例如使用自定义函数进行拆分等,扫描不同类型的I / O流(Stdin,String)等。


这应该是公认的答案。这不仅是一个更准确的答案,而且质量更高。
Daniel Farrell

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”检查中使用了一个break并将其包装在无限循环中。好的答案!
tebanep '16

2
看起来您现在也可以摆脱for循环中的条件。
irbanana '18

6

我迟到了。但是一个班轮怎么样:

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

并在命令行输入后按ctrl + d(EOT)。


因为os.Stdin不“结束”,所以不可能全部阅读。您可能正在等待一段时间……
gypsydave5

2
按Ctrl + D即EOT。
Shivendra Mishra

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 2016年

我猜大多数情况下您都希望默认情况下删除\ n,这就是为什么它会更好bufio.NewScanner as @Naren Yellavula答复
John Balvin Arias


0

就我而言,程序没有等待,因为我使用watcher命令来自动运行程序。手动运行该程序会go run main.go导致“输入文本”,并最终打印到控制台。

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

2
Scan*家族的局限性在于它们读取的是空格(例如,空格)分隔符。
乔治·瑟雷斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.