英文:
Looking for Go equivalent of scanf
问题
我正在寻找Go语言中scanf()的等效方法。
我尝试了以下代码:
1 package main
2
3 import (
4 "scanner"
5 "os"
6 "fmt"
7 )
8
9 func main() {
10 var s scanner.Scanner
11 s.Init(os.Stdin)
12 s.Mode = scanner.ScanInts
13 tok := s.Scan()
14 for tok != scanner.EOF {
15 fmt.Printf("%d ", tok)
16 tok = s.Scan()
17 }
18 fmt.Println()
19 }
我用一个包含整数行的文本作为输入运行它。
但它总是输出-3 -3 ...
如何扫描由字符串和一些整数组成的行?
每次遇到新的数据类型时更改模式吗?
包文档:
包scanner
用于UTF-8编码文本的通用扫描器。
但似乎扫描器并不适用于一般用途。
更新后的代码:
func main() {
n := scanf()
fmt.Println(n)
fmt.Println(len(n))
}
func scanf() []int {
nums := new(vector.IntVector)
reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
i, _ := strconv.Atoi(f)
nums.Push(i)
}
str, err = reader.ReadString('\n')
}
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
}
改进的版本:
package main
import (
"bufio"
"os"
"io"
"fmt"
"strings"
"strconv"
"container/vector"
)
func main() {
n := fscanf(os.Stdin)
fmt.Println(len(n), n)
}
func fscanf(in io.Reader) []int {
var nums vector.IntVector
reader := bufio.NewReader(in)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = reader.ReadString('\n')
}
return nums
}
英文:
I'm looking for the Go equivalent of scanf().
I tried with following code:
1 package main
2
3 import (
4 "scanner"
5 "os"
6 "fmt"
7 )
8
9 func main() {
10 var s scanner.Scanner
11 s.Init(os.Stdin)
12 s.Mode = scanner.ScanInts
13 tok := s.Scan()
14 for tok != scanner.EOF {
15 fmt.Printf("%d ", tok)
16 tok = s.Scan()
17 }
18 fmt.Println()
19 }
I run it with input from a text with a line of integers.
But it always output -3 -3 ...
And how to scan a line composed of a string and some integers?
Changing the mode whenever encounter a new data type?
The Package documentation:
> Package scanner
>
> A general-purpose scanner for UTF-8
> encoded text.
But it seems that the scanner is not for general use.
Updated code:
func main() {
n := scanf()
fmt.Println(n)
fmt.Println(len(n))
}
func scanf() []int {
nums := new(vector.IntVector)
reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
i, _ := strconv.Atoi(f)
nums.Push(i)
}
str, err = reader.ReadString('\n')
}
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
}
Improved version:
package main
import (
"bufio"
"os"
"io"
"fmt"
"strings"
"strconv"
"container/vector"
)
func main() {
n := fscanf(os.Stdin)
fmt.Println(len(n), n)
}
func fscanf(in io.Reader) []int {
var nums vector.IntVector
reader := bufio.NewReader(in)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = reader.ReadString('\n')
}
return nums
}
答案1
得分: 4
你的更新代码在去掉行号后更容易编译,但是缺少了包和导入语句。
看了你的代码,我注意到了一些问题。这是我修改后的代码版本。
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"container/vector"
)
func main() {
n := scanf(os.Stdin)
fmt.Println()
fmt.Println(len(n), n)
}
func scanf(in io.Reader) []int {
var nums vector.IntVector
rd := bufio.NewReader(os.Stdin)
str, err := rd.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = rd.ReadString('\n')
}
return nums
}
我可能想要在scanf()
中使用任何输入文件,而不仅仅是Stdin
;scanf()
接受一个io.Reader
作为参数。
你写道:nums := new(vector.IntVector)
,其中type IntVector []int
。这会分配一个名为nums
的整数切片引用,并将其初始化为零,然后new()
函数分配一个整数切片引用并将其初始化为零,然后将其赋给nums
。我写的是:var nums vector.IntVector
,它通过简单地分配一个名为nums
的整数切片引用并将其初始化为零来避免了冗余。
你没有检查strconv.Atoi()
的err
值,这意味着无效的输入会被转换为零值;我跳过了它。
为了从向量复制到一个新切片并返回该切片,你写了:
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
首先,我用等效的IntVector.Data()
方法替换了它:return nums.Data()
。然后,我利用了type IntVector []int
的事实,并通过替换它来避免了分配和复制:return nums
。
英文:
Your updated code was much easier to compile without the line numbers, but it was missing the package and import statements.
Looking at your code, I noticed a few things. Here's my revised version of your code.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"container/vector"
)
func main() {
n := scanf(os.Stdin)
fmt.Println()
fmt.Println(len(n), n)
}
func scanf(in io.Reader) []int {
var nums vector.IntVector
rd := bufio.NewReader(os.Stdin)
str, err := rd.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = rd.ReadString('\n')
}
return nums
}
I might want to use any input file for scanf()
, not just Stdin
; scanf()
takes an io.Reader
as a parameter.
You wrote: nums := new(vector.IntVector)
, where type IntVector []int
. This allocates an integer slice reference named nums
and initializes it to zero, then the new()
function allocates an integer slice reference and initializes it to zero, and then assigns it to nums
. I wrote: var nums vector.IntVector
, which avoids the redundancy by simply allocating an integer slice reference named nums
and initializing it to zero.
You didn't check the err
value for strconv.Atoi()
, which meant invalid input was converted to a zero value; I skip it.
To copy from the vector to a new slice and return the slice, you wrote:
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
First, I simply replaced that with an equivalent, the IntVector.Data()
method: return nums.Data()
. Then, I took advantage of the fact that type IntVector []int
and avoided the allocation and copy by replacing that by: return nums
.
答案2
得分: 0
尽管它可以用于其他用途,但scanner包专门用于扫描Go程序文本。Ints(-123),Chars('c'),Strings("str")等是Go语言的标记类型。
package main
import (
"fmt"
"os"
"scanner"
"strconv"
)
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("扫描错误", msg) }
s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
fmt.Print("标记:", tok, "文本:", txt)
switch tok {
case scanner.Int:
si, err := strconv.Atoi64(txt)
if err == nil {
fmt.Print(" 整数: ", si)
}
case scanner.String, scanner.RawString:
fmt.Print(" 字符串: ", txt)
default:
if tok >= 0 {
fmt.Print(" Unicode: ", "rune = ", tok)
} else {
fmt.Print(" 错误")
}
}
fmt.Println()
}
}
英文:
Although it can be used for other things, the scanner package is designed to scan Go program text. Ints (-123), Chars('c'), Strings("str"), etc. are Go language token types.
package main
import (
"fmt"
"os"
"scanner"
"strconv"
)
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) }
s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
fmt.Print("token:", tok, "text:", txt)
switch tok {
case scanner.Int:
si, err := strconv.Atoi64(txt)
if err == nil {
fmt.Print(" integer: ", si)
}
case scanner.String, scanner.RawString:
fmt.Print(" string: ", txt)
default:
if tok >= 0 {
fmt.Print(" unicode: ", "rune = ", tok)
} else {
fmt.Print(" ERROR")
}
}
fmt.Println()
}
}
答案3
得分: 0
这个例子总是一次读取一行,并将整行作为字符串返回。如果你想从中解析出特定的值,你可以这样做。
package main
import (
"fmt"
"bufio"
"os"
"strings"
)
func main() {
value := Input("请输入一个值:")
trimmed := strings.TrimSpace(value)
fmt.Printf("你好 %s!\n", trimmed)
}
func Input(str string) string {
print(str)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return input
}
英文:
This example always reads in a line at a time and returns the entire line as a string. If you want to parse out specific values from it you could.
package main
import (
"fmt"
"bufio"
"os"
"strings"
)
func main() {
value := Input("Please enter a value: ")
trimmed := strings.TrimSpace(value)
fmt.Printf("Hello %s!\n", trimmed)
}
func Input(str string) string {
print(str)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return input
}
答案4
得分: 0
在对我的一个答案发表评论时,你说:
> 从语言规范中可以看出:“当内存被分配用于存储一个值时,无论是通过声明、make()函数还是new()函数调用,如果没有提供显式初始化,内存都会被赋予默认初始化”。那么new()函数的意义是什么?
如果我们运行以下代码:
package main
import ("fmt")
func main() {
var i int
var j *int
fmt.Println("i (一个值) = ", i, "; j (一个指针) = ", j)
j = new(int)
fmt.Println("i (一个值) = ", i, "; j (一个指针) = ", j, "; *j (一个值) = ", *j)
}
声明var i int
分配内存来存储一个整数值,并将该值初始化为零。声明var j *int
分配内存来存储一个指向整数值的指针,并将该指针初始化为零(一个空指针);没有分配内存来存储整数值。我们看到类似于以下的程序输出:
i (一个值) = 0 ; j (一个指针) = <nil>
内置函数new
接受一个类型T
并返回一个类型为*T
的值。内存被初始化为零值。语句j = new(int)
分配内存来存储一个整数值,并将该值初始化为零,然后将指向该整数值的指针存储在j中。我们看到类似于以下的程序输出:
i (一个值) = 0 ; j (一个指针) = 0x7fcf913a90f0 ; *j (一个值) = 0
英文:
In a comment to one of my answers, you said:
> From the Language Specification: "When
> memory is allocated to store a value,
> either through a declaration or make()
> or new() call, and no explicit
> initialization is provided, the memory
> is given a default initialization".
> Then what's the point of new()?
If we run:
package main
import ("fmt")
func main() {
var i int
var j *int
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j)
j = new(int)
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j)
}
The declaration var i int
allocates memory to store an integer value and initializes the value to zero. The declaration var j *int
allocates memory to store a pointer to an integer value and initializes the pointer to zero (a nil pointer); no memory is allocated to store an integer value. We see program output similar to:
i (a value) = 0 ; j (a pointer) = <nil>
The built-in function new
takes a type T
and returns a value of type *T
. The memory is initialized to zero values. The statement j = new(int)
allocates memory to store an integer value and initializes the value to zero, then it stores a pointer to this integer value in j. We see program output similar to:
i (a value) = 0 ; j (a pointer) = 0x7fcf913a90f0 ; *j (a value) = 0
答案5
得分: 0
Go的最新版本(2010-05-27)在fmt
包中添加了两个函数:Scan()
和Scanln()
。它们不接受任何模式字符串,而是检查参数的类型,就像在C语言中一样。
package main
import (
"fmt"
"os"
"container/vector"
)
func main() {
numbers := new(vector.IntVector)
var number int
n, err := fmt.Scan(os.Stdin, &number)
for n == 1 && err == nil {
numbers.Push(number)
n, err = fmt.Scan(os.Stdin, &number)
}
fmt.Printf("%v\n", numbers.Data())
}
英文:
The latest release of Go (2010-05-27) has added two functions to the fmt
package: Scan()
and Scanln()
. They don't take any pattern string. like in C, but checks the type of the arguments instead.
package main
import (
"fmt"
"os"
"container/vector"
)
func main() {
numbers := new(vector.IntVector)
var number int
n, err := fmt.Scan(os.Stdin, &number)
for n == 1 && err == nil {
numbers.Push(number)
n, err = fmt.Scan(os.Stdin, &number)
}
fmt.Printf("%v\n", numbers.Data())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论