使用 Scanner 处理每行多个标记的更好方法?
a better way to use Scanner for multiple tokens per line?
我正在尝试解析包含一个键、一个 space、一个数字和一个换行符的行的文件。
我的代码有效,但我觉得不对。有没有更好的方法来使用 Scanner?特别是,我不喜欢在没有任何保护的情况下将 Scan() 放在 for 循环中。
func TestScanner(t *testing.T) {
const input = `key1 62128128\n
key2 8337182720\n
key3 7834959872\n
key4 18001920\n
key5 593104896\n`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
scanner.Scan()
value := scanner.Text();
fmt.Printf("k: %v, v: %v\n", key, value)
}
}
您不应在 input
中使用 \n
,并始终检查错误。
工作示例代码:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
if !scanner.Scan() {
break
}
value := scanner.Text()
fmt.Printf("k: %v, v: %v\n", key, value)
}
}
输出:
k: key1, v: 62128128
k: key2, v: 8337182720
k: key3, v: 7834959872
k: key4, v: 18001920
k: key5, v: 593104896
您也可以使用 Fscan
扫描到所需的类型,如下所示:
package main
import "fmt"
import "strings"
func main() {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
rdr := strings.NewReader(input)
for {
k, v := "", 0
n, _ := fmt.Fscan(rdr, &k, &v)
if n != 2 {
//fmt.Println(err)
break
}
fmt.Printf("%T: %[1]v, %T: %[2]v\n", k, v)
}
}
输出:
string: key1, int: 62128128
string: key2, int: 8337182720
string: key3, int: 7834959872
string: key4, int: 18001920
string: key5, int: 593104896
实际上,这样做是绝对安全的,因为 Scan() 会验证输入并设置一个错误,您可以使用 Err() 获得该错误。
所以如果你想检查 Scan() 是否失败,你必须在循环结束时执行,如许多 examples.
所示
您的代码应该是:
func TestScanner(t *testing.T) {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
scanner.Scan()
value := scanner.Text();
fmt.Printf("k: %v, v: %v\n", key, value)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
}
我正在尝试解析包含一个键、一个 space、一个数字和一个换行符的行的文件。
我的代码有效,但我觉得不对。有没有更好的方法来使用 Scanner?特别是,我不喜欢在没有任何保护的情况下将 Scan() 放在 for 循环中。
func TestScanner(t *testing.T) {
const input = `key1 62128128\n
key2 8337182720\n
key3 7834959872\n
key4 18001920\n
key5 593104896\n`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
scanner.Scan()
value := scanner.Text();
fmt.Printf("k: %v, v: %v\n", key, value)
}
}
您不应在 input
中使用 \n
,并始终检查错误。
工作示例代码:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
if !scanner.Scan() {
break
}
value := scanner.Text()
fmt.Printf("k: %v, v: %v\n", key, value)
}
}
输出:
k: key1, v: 62128128
k: key2, v: 8337182720
k: key3, v: 7834959872
k: key4, v: 18001920
k: key5, v: 593104896
您也可以使用 Fscan
扫描到所需的类型,如下所示:
package main
import "fmt"
import "strings"
func main() {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
rdr := strings.NewReader(input)
for {
k, v := "", 0
n, _ := fmt.Fscan(rdr, &k, &v)
if n != 2 {
//fmt.Println(err)
break
}
fmt.Printf("%T: %[1]v, %T: %[2]v\n", k, v)
}
}
输出:
string: key1, int: 62128128
string: key2, int: 8337182720
string: key3, int: 7834959872
string: key4, int: 18001920
string: key5, int: 593104896
实际上,这样做是绝对安全的,因为 Scan() 会验证输入并设置一个错误,您可以使用 Err() 获得该错误。
所以如果你想检查 Scan() 是否失败,你必须在循环结束时执行,如许多 examples.
所示您的代码应该是:
func TestScanner(t *testing.T) {
const input = `key1 62128128
key2 8337182720
key3 7834959872
key4 18001920
key5 593104896`
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
key := scanner.Text()
scanner.Scan()
value := scanner.Text();
fmt.Printf("k: %v, v: %v\n", key, value)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
}