英文:
Which scan to use to read floats from a string?
问题
这似乎几乎正确,但它在换行符上出现问题。
最好的方法是什么?
package main
import (
"fmt"
"strings"
)
func main() {
var z float64
var a []float64
// \n给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)
}
输出:
n 1
n 1
n 1
n 0
[3.25 -12.6 33.7]
更新:
请参见下面@Atom的答案。我找到了另一种方法,即如果错误是EOF,则中断,否则只需忽略它。我知道这只是一个hack,但我控制源代码。
_, err := fmt.Fscanf(in, "%f", &z)
if err == os.EOF { break }
if err != nil { continue }
英文:
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 }
答案1
得分: 5
如果你只解析浮点数,你可以使用fmt.Fscan(r io.Reader, a ...interface{})
而不是fmt.Fscanf(r io.Reader, format string, a ...interface{})
:
var z float64
...
n, err := fmt.Fscan(in, &z)
fmt.Fscan
和fmt.Fscanf
之间的区别在于,在fmt.Fscan
的情况下,换行符被视为空格。后者(带有格式字符串的函数)不将换行符视为空格,并且要求输入中的换行符与格式字符串中的换行符匹配。
带有格式字符串的函数可以更好地控制输入的形式,例如当你需要扫描%5f
或%10s
时。在这种情况下,如果输入包含换行符并且实现了io.RuneScanner
接口,你可以使用ReadRune
方法来查看下一个字符,并使用UnreadRune
方法将其取消读取,如果它不是空格或换行符。
英文:
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.
答案2
得分: 2
如果您的输入只是一堆由空格分隔的浮点数组成的行,那么从文件中一次读取一行,然后在该行上运行Sscanf可能更容易(假设每行上的浮点数数量是固定的)。但是这里有一个在您的示例中有效的方法---可能有一种方法可以使其更高效。
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)
}
英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论