Which scan to use to read floats from a string? - go

This seems almost right but it chokes on the newline.
What's the best way to do this?
package main
import (
"fmt"
"strings"
)
func main() {
var z float64
var a []float64
// \n gives an error for Fscanf
s := "3.25 -12.6 33.7 \n 3.47"
in := strings.NewReader(s)
for {
n, err := fmt.Fscanf(in, "%f", &z)
fmt.Println("n", n)
if err != nil {
break
}
a = append(a, z)
}
fmt.Println(a)
}
Output:
n 1
n 1
n 1
n 0
[3.25 -12.6 33.7]
Update:
See the answer from #Atom below. I found another way which is to break if the error is EOF, and otherwise just ignore it. It's just a hack, I know, but I control the source.
_, err := fmt.Fscanf(in, "%f", &z)
if err == os.EOF { break }
if err != nil { continue }

If you are parsing floats only, you can use fmt.Fscan(r io.Reader, a ...interface{}) instead of fmt.Fscanf(r io.Reader, format string, a ...interface{}):
var z float64
...
n, err := fmt.Fscan(in, &z)
The difference between fmt.Fscan and fmt.Fscanf is that in the case of fmt.Fscan newlines count as space. The latter function (with a format string) does not treat newlines as spaces and requires newlines in the input to match newlines in the format string.
The functions with a format string give more control over the form of input, such as when you need to scan %5f or %10s. In this case, if the input contains newlines and it implements the interface io.RuneScanner you can use the method ReadRune to peek the next character and optionally unread it with UnreadRune if it isn't a space or a newline.

If your input is just a bunch of lines with floats separated by white space on each line, it might be easier to just read one line at a time from the file, run Sscanf on that line (assuming the number of floats on each line is fixed). But here's something that works in your example---there may be a way to make it more efficient.
package main
import (
"fmt"
"strings"
)
func main() {
var z float64
var a []float64
// \n gives an error for Fscanf
s := "3.25 -12.6 33.7 \n 3.47"
for _, line := range strings.Split(s, "\n") {
in := strings.NewReader(line)
for {
n, err := fmt.Fscanf(in, "%f", &z)
fmt.Println("n", n)
if err != nil {
fmt.Printf("ERROR: %v\n", err)
break
}
a = append(a, z)
}
}
fmt.Println(a)
}

Related

Fast method to take input separated by space [Golang]

I'm trying to take fast input through scanner.Bytes and I'm it converting to int. The problem is : input provided is single line spaced elements ( like an array ) and scanner.Bytes reads it as a whole and converts it into int. How can I use a Splitfunction on the bytes read!
func main() {
scanner := bufio.NewScanner(os.Stdin)
var t int
fmt.Scanf("%d", &t)
for o := 0; o < t; o++ {
scanner.Scan()
//scanner.Split(bufio.ScanWords())
val := toInt(scanner.Bytes())
fmt.Println(val)
}
}
func toInt(buf []byte) (n int) {
for _, v := range buf {
n = n*10 + int(v-'0')
}
return
}
The default bufio.Scanner (with the default split function) breaks the input into lines with line termination stripped. If you want to break the input into words, you have to set a different split function using the Scanner.Split() method.
There is a ready split function for breaking words: bufio.ScanWords(). We can see this function commented in your code.
But know that Scanner.Split() method expects a function value. You do not need to call the split function, the scanner will call it to break the input data. You just have to pass the function value, which you can do so without calling it, without appending () after the function name, e.g.:
scanner.Split(bufio.ScanWords)
Also note that you only have to do this once, and you can only do this once, before starting to scan the input, so move this line above the for loop:
var t int
fmt.Scanf("%d", &t)
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
for o := 0; o < t; o++ {
scanner.Scan()
val := toInt(scanner.Bytes())
fmt.Println(val)
}
Now running the app, and entering the following lines:
3
1 2 3
The output will be:
1
2
3
Also note that Scanner.Scan() returns a bool value indicating if scanning was successful and you may process the token. You should use this return value and not rely on the user inputting valid data.
why not just try something like
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
val, err := strconv.Atoi(scanner.Text())
if err != nil {
log.Fatal(err)
}
fmt.Println(val)
}
}
Assuming the input is 3 65 65 65 and 3 is the number of following bytes, then this works:
func main() {
var t int
fmt.Scanf("%d", &t)
values := make([]byte, t)
buf := make([]interface{}, t)
for i := 0; i < t; i++ {
buf[i] = &values[i]
}
fmt.Scanln(buf...)
// test
fmt.Printf("%v\n", values)
}
The test output is [65 65 65].

Why the array resulted from the stdin in Golang convert the last item to zero?

Note: I am new to StackOverflow as well as to Programming, so if my question is not "so professional" or "well formatted", please forgive me.
I am using the following Go (Golang) code to capture some space-separated numbers (string) from terminal, then split it into a slice. Later I'm converting this slice to a slice of float64 by getting one item at a time from the strings-slice and converting it to float64 and appending it to the float64-slice.
Then I'm returning the resulting float64 slice and printing it in the main function.
The problem is when I pass some space-separated digits to the terminal, the last digit is converted to zero.
for example if I pass 1 2 3 4 5 I expect the resulting slice as [1 2 3 4 5], but it gives me the slice as [1 2 3 4 0].
I'm trying from the last 5 hours, but I'm not able to find what I'm missing or messing.
code:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
a := ReadInput()
fmt.Println(a)
}
func ReadInput() []float64 {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
textSlice := strings.Split(text, " ")
floatsSlice := make([]float64, 0)
for _, elem := range textSlice {
i, _ := strconv.ParseFloat(elem, 64)
floatsSlice = append(floatsSlice, i)
}
return floatsSlice
}
Thank You in advance!
ReadString reads until the first occurrence of delim in the input,
returning a string containing the data up to and including the
delimiter.
so, strings.Split(text, " ") not splits last \n character so:
you may use strings.Fields(text) instead of strings.Split(text, " ")
and always check for errors:
like this working sample code:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
a := ReadInput()
fmt.Println(a)
}
func ReadInput() []float64 {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, err := reader.ReadString('\n')
if err != nil {
fmt.Println(err)
}
textSlice := strings.Fields(text)
floatsSlice := make([]float64, 0)
for _, elem := range textSlice {
i, err := strconv.ParseFloat(elem, 64)
if err != nil {
fmt.Println(err)
}
floatsSlice = append(floatsSlice, i)
}
return floatsSlice
}

golang scan a line of numbers from sdin

I'm trying to read input from stdin like
3 2 1<ENTER>
and save it in a list of ints. At the moment my code looks like this:
nums = make([]int, 0)
var i int
for {
_, err := fmt.Scan(&i)
if err != nil {
if err==io.EOF { break }
log.Fatal(err)
}
nums = append(nums, i)
}
at the moment the program never leaves the for-loop. I can't find an easy way to check for a newline character in the documentation. how would i do this?
Edit:
Since I know that there will almost certainly be four numbers, I tried the following:
var i0,i1,i2,i3 int
fmt.Scanf("%d %d %d %d\n", &i0, &i1, &i2, &i3)
but this only scanned the first number and then exited the program. I'm not sure if that's because of the z-shell I'm using.
Edit:
To clarify, the program will pause and ask for the user to input a list of n numbers separated by spaces and terminated with a newline. these numbers should be stored in an array.
Ok, I decided to bring out the large bufio hammer and solve it like this:
in := bufio.NewReader(os.Stdin)
line, err := in.ReadString('\n')
if err != nil {
log.Fatal(err)
}
strs := strings.Split(line[0:len(line)-1], " ")
nums := make([]int, len(strs))
for i, str := range strs {
if nums[i], err = strconv.Atoi(str); err != nil {
log.Fatal(err)
}
}
It does seem like an awful lot of code, but it works.
It seems that you want https://golang.org/pkg/fmt/#Fscanln
Something like
ok := func(err error) { if err != nil { panic(err) } }
for {
var i, j, k int
_, err := fmt.Fscanln(io.Stdin, &i, &j, &k)
ok(err)
fmt.Println(i, j, k)
}
I will suggest to use "bufio" package with the "scan()" method.
Following is the code where I'm reading two lines from "stdin" and storing the lines into an array.
Hope this helps you.
package main
import (
"fmt"
"bufio"
"os"
"strconv"
"strings"
)
func ReadInput() []string{
var lines []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
lines = append(lines, scanner.Text())
//count, _ := strconv.Atoi(lines[0])
if len(lines) == 2 { break }
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return lines
}
func main(){
lines := ReadInput()
count ,_ := strconv.Atoi(lines[0])
num := strings.Fields(lines[1])
if count != len(num) { os.Exit(0) }
// Do whatever you want here
}
Two lines will be accepted. First line will have a count. Second line will have all the numbers. You can modify the same code as per your requirement.
Example:
3
1 5 10

Invalid indirect of type func (int) string

I'm getting stucked with the following error:
./main.go:76: invalid indirect of Fizzbuzz (type func(int) string)
I understand that the Fizzbuzz function does not satisfy the writeString. My intuition is telling me that this is probably because I should be using an interface to Fizzbuzz? Can someone please give me some direction on how to execute this? What can I do to make this code Go idiomatic?
// -------------------------------INPUT--------------------------------------
// Your program should read an input file (provided on the command line),
// which contains multiple newline separated lines.
// Each line will contain 3 numbers which are space delimited.
// The first number is first number to divide by ('A' in this example),
// the second number is the second number to divide by ('B' in this example)
// and the third number is where you should count till ('N' in this example).
// You may assume that the input file is formatted correctly and the
// numbers are valid positive integers. E.g.
// 3 5 10
// 2 7 15
// -------------------------------OUTPUT------------------------------------
// Print out the series 1 through N replacing numbers divisible by 'A' by F,
// numbers divisible by 'B' by B and numbers divisible by both as 'FB'.
// Since the input file contains multiple sets of values, your output will
// print out one line per set. Ensure that there are no trailing empty spaces
// on each line you print. E.g.
// 1 2 F 4 B F 7 8 F B
// 1 F 3 F 5 F B F 9 F 11 F 13 FB 15
// ---------------------------PROPOSED SOLUTION-----------------------------
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func Fizzbuzz(N int) (output string) {
var (
A = N%3 == 0
B = N%5 == 0
)
switch {
case A && B:
output = "FB"
case A:
output = "F"
case B:
output = "B"
default:
output = fmt.Sprintf("%v", N)
}
return
}
func openFile(name string) *os.File {
file, err := os.Open(name)
if err != nil {
log.Fatalf("failed opening %s for writing: %s", name, err)
}
return file
}
func Readln(r *bufio.Reader) {
line, prefix, err := r.ReadLine()
if err != nil {
log.Fatalf("failed reading a line: %v", err)
}
if prefix {
log.Printf("Line is too big for buffer, only first %d bytes returned", len(line))
}
}
func WriteString(w *bufio.Writer) {
if n, err := w.WriteString(*Fizzbuzz); err != nil {
log.Fatalf("failed writing string: %s", err)
} else {
log.Printf("Wrote string in %d bytes", n)
}
}
func main() {
file := openFile(os.Args[1])
defer file.Close()
fi := bufio.NewReader(file)
Readln(fi)
fo := bufio.NewWriter(file)
defer fo.Flush()
WriteString(fo)
}
Go-Playground
* as a unary operator is used to dereference (or "indirect") a pointer. Fizzbuzz is a function, not a pointer. That is why the compiler says:
Invalid indirect of type func (int) string
What you really want to do is call the function: Fizzbuzz()
So line:
if fizzbuzz, err := w.WriteString(*Fizzbuzz); err != nil {
should be:
if fizzbuzz, err := w.WriteString(Fizzbuzz()); err != nil{
It is not very idiomatic to call the first return of writestring something like fizzbuzz. Normally we name it "n".
if n, err := w.WriteString(Fizzbuzz()); err != nil{

Reading an integer from standard input

How do I use the fmt.Scanf function in Go to get an integer input from the standard input?
If this can't be done using fmt.Scanf, what's the best way to read a single integer?
http://golang.org/pkg/fmt/#Scanf
All the included libraries in Go are well documented.
That being said, I believe
func main() {
var i int
_, err := fmt.Scanf("%d", &i)
}
does the trick
An alternative that can be a bit more concise is to just use fmt.Scan:
package main
import "fmt"
func main() {
var i int
fmt.Scan(&i)
fmt.Println("read number", i, "from stdin")
}
This uses reflection on the type of the argument to discover how the input should be parsed.
http://golang.org/pkg/fmt/#Scan
Here is my "Fast IO" method for reading positive integers. It could be improved with bitshifts and laying out memory in advance.
package main
import (
"io/ioutil"
"bufio"
"os"
"strconv"
)
func main() {
out := bufio.NewWriter(os.Stdout)
ints := getInts()
var T int64
T, ints = ints[0], ints[1:]
..
out.WriteString(strconv.Itoa(my_num) + "\n")
out.Flush()
}
}
func getInts() []int64 {
//assumes POSITIVE INTEGERS. Check v for '-' if you have negative.
var buf []byte
buf, _ = ioutil.ReadAll(os.Stdin)
var ints []int64
num := int64(0)
found := false
for _, v := range buf {
if '0' <= v && v <= '9' {
num = 10*num + int64(v - '0') //could use bitshifting here.
found = true
} else if found {
ints = append(ints, num)
found = false
num = 0
}
}
if found {
ints = append(ints, num)
found = false
num = 0
}
return ints
}
Golang fmt.Scan is simpler than Golang fmt.Scanf (which is simpler than Clang scanf)
If fmt.Scan errors i.e. if not nil, log & return
1 Read single variable:
import (
"fmt"
"log"
)
var i int
if _, err := fmt.Scan(&i); err != nil {
log.Print(" Scan for i failed, due to ", err)
return
}
fmt.Println(i)
2 Read multiple variables:
import (
"fmt"
"log"
)
var i, j, k int
if _, err := fmt.Scan(&i, &j, &k); err != nil {
log.Print(" Scan for i, j & k failed, due to ", err)
return
}
fmt.Println(i, j, k)
Best of luck
Example from: http://www.sortedinf.com/?q=golang-in-1-hour
You can use fmt.Scanf with a format specifier. The format specifier for the integer is %d. So you can use standard input like below.
func main() {
var someVar int
fmt.Scanf("%d", &someVar)
}
or else you can use fmt.Scan or fmt.Scanln as below.
func main() {
var someVar int
fmt.Scanln(&someVar)
}
You could also use bufio.NewReader to read an integer from the standard input.
The below program:
Prompts for an integer input
Creates a bufio.Reader to read from standard input
Reads input till it encounters a newline character '\n' (Note that this will only read a single integer. Space separated values will not work)
Removes the newline character
Converts string to int
package main
import (
"fmt"
"bufio"
"os"
"strconv"
"strings"
)
func getInt() error {
fmt.Println("Enter an integer")
userInput := bufio.NewReader(os.Stdin)
userVal, err := userInput.ReadString('\n')
if err != nil {
return err
}
input := strings.TrimSpace(userVal)
intVal, err := strconv.Atoi(input)
if err != nil {
return err
}
fmt.Printf("You entered: %d\n", intVal)
return nil
}
func main() {
getInt()
}
Why can't we just use a scanf? just like we use in C? it's working though.
package main
import "fmt"
func main() {
var i int
fmt.Scanf("%d", &i)
fmt.Println(i)
}

Resources