Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for Go equivalent of scanf

Tags:

go

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
}
like image 371
Stephen Hsu Avatar asked Mar 10 '10 11:03

Stephen Hsu


People also ask

What is scanf Golang?

Scanf() function in Go language scans the input texts which is given in the standard input, reads from there and stores the successive space-separated values into successive arguments as determined by the format. Moreover, this function is defined under the fmt package.

How do I use FMT scanf in Golang?

To use this function, you must import the fmt package in your file and access the Scanf function within by using the . notation ( fmt. Scanf ). Here, Scanf is the actual function, while fmt is the Go package that stores the definition of this function.

When scanf returns 0 in c?

A return value of 0 means that no fields were assigned.

How scanf function works in c?

The scanf() function reads data from the standard input stream stdin into the locations given by each entry in argument-list. Each argument must be a pointer to a variable with a type that corresponds to a type specifier in format-string.


1 Answers

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.

like image 161
peterSO Avatar answered Sep 23 '22 20:09

peterSO