寻找Go语言中与scanf相等的函数。

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

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     &quot;scanner&quot;
  5     &quot;os&quot;
  6     &quot;fmt&quot;
  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(&quot;%d &quot;, 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(&#39;\n&#39;)
    for err != os.EOF {
        fields := strings.Fields(str)
        for _, f := range fields {
            i, _ := strconv.Atoi(f)
            nums.Push(i)
        }   
        str, err = reader.ReadString(&#39;\n&#39;)
    }   
    r := make([]int, nums.Len())
    for i := 0; i &lt; nums.Len(); i++ {
        r[i] = nums.At(i)
    }   
    return r
}

Improved version:

package main

import (
    &quot;bufio&quot;
    &quot;os&quot;
    &quot;io&quot;
    &quot;fmt&quot;
    &quot;strings&quot;
    &quot;strconv&quot;
    &quot;container/vector&quot;
)

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(&#39;\n&#39;)
    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(&#39;\n&#39;)
    }   
    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()中使用任何输入文件,而不仅仅是Stdinscanf()接受一个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 (
	&quot;bufio&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;os&quot;
	&quot;strconv&quot;
	&quot;strings&quot;
	&quot;container/vector&quot;
)

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(&#39;\n&#39;)
	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(&#39;\n&#39;)
	}
	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 &lt; 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 (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;scanner&quot;
	&quot;strconv&quot;
)

func main() {
	var s scanner.Scanner
	s.Init(os.Stdin)
	s.Error = func(s *scanner.Scanner, msg string) { fmt.Println(&quot;scan error&quot;, msg) }
	s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
	for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
		txt := s.TokenText()
		fmt.Print(&quot;token:&quot;, tok, &quot;text:&quot;, txt)
		switch tok {
		case scanner.Int:
			si, err := strconv.Atoi64(txt)
			if err == nil {
				fmt.Print(&quot; integer: &quot;, si)
			}
		case scanner.String, scanner.RawString:
			fmt.Print(&quot; string: &quot;, txt)
		default:
			if tok &gt;= 0 {
				fmt.Print(&quot; unicode: &quot;, &quot;rune = &quot;, tok)
			} else {
				fmt.Print(&quot; ERROR&quot;)
			}
		}
		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 (
	&quot;fmt&quot;
	&quot;bufio&quot;
	&quot;os&quot;
	&quot;strings&quot;
)

func main() {
	value :=	Input(&quot;Please enter a value: &quot;)
	trimmed := strings.TrimSpace(value)
	fmt.Printf(&quot;Hello %s!\n&quot;, trimmed)
}

func Input(str string) string { 
        print(str) 
        reader := bufio.NewReader(os.Stdin) 
        input, _ := reader.ReadString(&#39;\n&#39;) 
        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 (&quot;fmt&quot;)

func main() {
	var i int
	var j *int
	fmt.Println(&quot;i (a value) = &quot;, i, &quot;; j (a pointer) = &quot;, j)
	j = new(int)
	fmt.Println(&quot;i (a value) = &quot;, i, &quot;; j (a pointer) = &quot;, j, &quot;; *j (a value) = &quot;, *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) =  &lt;nil&gt;

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 (
   &quot;fmt&quot;
   &quot;os&quot;
   &quot;container/vector&quot;
)

func main() {
    numbers := new(vector.IntVector)
    var number int
    n, err := fmt.Scan(os.Stdin, &amp;number)
    for n == 1 &amp;&amp; err == nil {
       numbers.Push(number)
       n, err = fmt.Scan(os.Stdin, &amp;number)
    }
    fmt.Printf(&quot;%v\n&quot;, numbers.Data())
}

huangapple
  • 本文由 发表于 2010年3月10日 19:07:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/2416305.html
匿名

发表评论

匿名网友

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

确定