使用键盘输入或管道文件输入

huangapple go评论85阅读模式
英文:

go - keyboard or piped-file input

问题

我正在尝试编写一个函数,可以从键盘读取输入,或者逐行从管道输入的文件中读取。我已经有一个函数,类似于测试代码中的prompt(),可以接受键盘输入:

package main

import (
	"fmt"
	"bufio"
	"os"
)

func print(format string, a ...interface{}) {
	fmt.Printf(format+"\n", a...)
}

func prompt(format string) string {
	fmt.Print(format)
	in := bufio.NewScanner(os.Stdin)
	in.Scan()
	return in.Text()
}

func greet() {
	name := prompt("enter name: ")
	print(`Hello %s!`, name)
}

func humor() {
	color := prompt("enter favorite color: ")
	print(`I like %s too!`, color)
}

func main() {
	greet()
	humor()
}

在这里,greet()humor() 都使用 prompt() 来获取输入,如果我运行程序并键入响应,它将按预期工作。然而,如果我有一个文件 a.txt

bobby bill
soft, blue-ish turquoise

然后运行:.\test< a.txt,程序将输出:

enter name: Hello bobby bill!
enter favorite color: I like  too!

而不是:

enter name: Hello bobby bill!
enter favorite color: I like soft, blue-ish turquoise too!

据我了解,这是因为在 greet() 中创建的 bufio.Scanner 读取了整个 a.txt。我可以通过将 bufio.Scanner 设置为全局变量,并让 prompt() 使用它而不是每次创建一个新的 bufio.Scanner 来解决这个问题,但我想知道是否有更好的方法来解决这个问题,而不必使用全局变量。

英文:

I am trying to write a function that can read input from the keyboard or read from a piped-in file one line at a time. I already have a function that takes keyboard input similar to prompt() in this test code:

package main

import (
	&quot;fmt&quot;
	&quot;bufio&quot;
	&quot;os&quot;
)

func print(format string, a ...interface{}) {
	fmt.Printf(format+&quot;\n&quot;, a...)
}

func prompt(format string) string {
	fmt.Print(format)
	in := bufio.NewScanner(os.Stdin)
	in.Scan()
	return in.Text()
}

func greet() {
	name := prompt(&quot;enter name: &quot;)
	print(`Hello %s!`, name)
}

func humor() {
	color := prompt(&quot;enter favorite color: &quot;)
	print(`I like %s too!`, color)
}

func main() {
	greet()
	humor()
}

Here, greet() and humor() both use prompt() to get the input, and if I run the program and type in the responses, it will work as expected. However, if I have a file a.txt:

bobby bill
soft, blue-ish turquoise

and then run: .\test&lt; a.txt, the program will output:

enter name: Hello bobby bill!
enter favorite color: I like  too!

instead of:

enter name: Hello bobby bill!
enter favorite color: I like soft, blue-ish turquoise too!

As I understand it, this is because the bufio.Scanner that was made in greet() read all of a.txt. I can solve this problem easily by making the bufio.Scanner a global variable and have prompt() use that instead of creating a new bufio.Scanner each time, but I am wondering if there is a better way to do this without having to resort to global variables.

答案1

得分: 1

你的分析是正确的,问题在于bufio.Scanner缓冲了多于一行的文本,所以当你丢弃它时,你就会丢失那部分输入。如果你要使用缓冲输入,你应该确保所有的东西都使用相同的缓冲区,以避免这种问题。

使用全局变量是一种解决方案。另一种解决方案是创建一个类型来保存bufio.Scanner,并将一些函数转换为方法。

英文:

Your analysis is correct, and the problem is that bufio.Scanner buffers more than a line of text so when you throw it away you lose that input. If you are going to use buffered input, you should make sure everything uses the same buffer to avoid this sort of problem.

Using a global variable is one solution. Another would be to create a type to hold the bufio.Scanner and turn some of your functions into methods.

答案2

得分: 1

我认为,由于os.Stdin是一个全局变量,拥有一个全局缓冲版本是完全合适的。

请注意,Go语言没有真正的全局变量 - 一切都始终在包命名空间中,因此创建一个全局变量并不像在C语言中那样重要。

例如:

package main

import (
	"bufio"
	"fmt"
	"os"
)

// 全局变量
var (
	in = bufio.NewScanner(os.Stdin)
)

func prompt(format string) string {
	fmt.Print(format)
	in.Scan()
	return in.Text()
}

func greet() {
	name := prompt("请输入姓名:")
	fmt.Printf("你好,%s!\n", name)
}

func humor() {
	color := prompt("请输入喜欢的颜色:")
	fmt.Printf("我也喜欢%s!\n", color)
}

func main() {
	greet()
	humor()
}
英文:

I would say that since os.Stdin is a global variable, having a global buffered version of it would be entirely appropriate.

Note that Go doesn't have true global variables - everything is always in a package namespace so making a global variable isn't quite such a big deal as in a language such as C.

Eg

package main

import (
	&quot;bufio&quot;
	&quot;fmt&quot;
	&quot;os&quot;
)

// Globals
var (
	in = bufio.NewScanner(os.Stdin)
)

func prompt(format string) string {
	fmt.Print(format)
	in.Scan()
	return in.Text()
}

func greet() {
	name := prompt(&quot;enter name: &quot;)
	fmt.Printf(&quot;Hello %s!\n&quot;, name)
}

func humor() {
	color := prompt(&quot;enter favorite color: &quot;)
	fmt.Printf(&quot;I like %s too!\n&quot;, color)
}

func main() {
	greet()
	humor()
}

huangapple
  • 本文由 发表于 2013年10月24日 14:09:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/19558234.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定