寻找相当于scanf的Go

时间:2010-03-10 11:07:21

标签: go

我正在寻找与scanf()等效的Go。 我尝试使用以下代码:

  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 ......

如何扫描由字符串和一些整数组成的行? 遇到新数据类型时更改模式?

包文档:

  

包扫描程序

     

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
}

5 个答案:

答案 0 :(得分:4)

您更新的代码在没有行号的情况下编译起来要容易得多,但它缺少包和import语句。

看着你的代码,我注意到了一些事情。这是我修改后的代码版本。

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的整数切片引用并将其初始化为零来避免冗余。

您没有检查err的{​​{1}}值,这意味着无效输入被转换为零值;我跳过了。

要从矢量复制到新切片并返回切片,您写道:

strconv.Atoi()

首先,我只是将其替换为等效的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

答案 1 :(得分:0)

虽然它可以用于其他事情,但扫描仪包用于扫描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("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()
    }
}

答案 2 :(得分:0)

此示例始终一次读取一行,并将整行作为字符串返回。如果你想从中解析出特定的值,你可以。

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 
}

答案 3 :(得分:0)

在对我的一个答案的评论中,你说:

  

从语言规范:“何时   内存被分配来存储一个值,   通过声明或make()   或者new()调用,没有明确的   初始化提供了内存   给出一个默认的初始化“。   那么new()有什么意义呢?

如果我们跑:

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)
}

声明var i int分配内存以存储整数值并将值初始化为零。声明var j *int分配内存以存储指向整数值的指针并将指针初始化为零(nil指针);没有分配内存来存储整数值。我们看到程序输出类似于:

i (a value) =  0 ; j (a pointer) =  <nil>

内置函数new采用类型T并返回类型*T的值。内存初始化为零值。语句j = new(int)分配内存以存储整数值并将值初始化为零,然后它将指向此整数值的指针存储在j中。我们看到程序输出类似于:

i (a value) =  0 ; j (a pointer) =  0x7fcf913a90f0 ; *j (a value) =  0

答案 4 :(得分: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())
}