Лучший способ использовать сканер для нескольких токенов на линию?

Я пытаюсь проанализировать файл со строками, которые состоят из ключа, пробела, числа и затем новой строки.

Мой код работает, но он мне не пахнет. Есть ли лучший способ использовать сканер? В частности, мне не нравится, когда 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)
    }
}

2 ответа

Решение

Ты не должен использовать \n в inputи всегда проверяйте на ошибки.
рабочий пример кода:

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(), вы должны сделать это в конце цикла, как показано во многих примерах.

Ваш код должен быть:

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)
    }

}
Другие вопросы по тегам