I'm learning Go.
My program should read data from stdin until I enter a line with a single period.
package main
import (
"os"
"fmt"
"bufio"
)
func main(){
in := bufio.NewReader(os.Stdin)
input := ""
for input != "." {
input, err := in.ReadString('
')
if err != nil {
panic(err)
}
}
}
How I should modify my for loop, to stop the program when I enter a single dot ?
I tried to implement a while loop with the for statement, is there something wrong with my approach, is the condition wrong, or is ReadString messing with my data ?
... is ReadString messing with my data?
No, it isn't. It is reading up to the next ' '
. That means that a line with only a dot on it will have the data ". "
or ". "
depending on the operating system.
To remove line endings, I would do input = strings.TrimRight(input, " ")
Just in case anybody else comes across this question:
Since Go 1.1 there's a much nicer way of looping over the lines of some input available. This is how I would tackle OP's problem today:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
if line == "." {
break
}
fmt.Println(line) // or do something else with line
}
}
scanner.Text()
automatically strips the trailing newline.
The main problem with using any bufio helper function is that it may read some more data beyond stop character ' '
. It reads all available input up to the size of the buffer. In case of concurrent access to os.Stdin the next reader may miss some input that was read by bufio before it. Below is my non buffered "draft" code to sketch concurrent safe method of reading from input stream all characters up to CR (' ')
char.
package main
import "os"
// echo a line in input to output
// you may add exit signal in copy loop as well
func main() {
const BUF_SIZE = 128
in := os.Stdin
out := os.Stdout
bufOut := make([]byte, BUF_SIZE)
n := 0
for { // copy loop
// non buffered byte-by-byte
if _, err := in.Read(bufOut[n : n+1]); err != nil {
break
}
if bufOut[n] == 0xa || n == BUF_SIZE { // reached CR or size limit
if _, err = out.Write(bufOut[0 : n+1]); err != nil {
break
}
n = 0
} else {
n++
}
}
}
Just noticed that question inside the topic is not same as in title. The error with initial sample in question is with input variable been re declared inside the loop. That is why your condition check never gets to the exit point.