5

Go で継続行をスキャンするスキャナーを作成し、それを返す前に行をクリーンアップして、論理行を返すことができるようにしようとしています。したがって、次の SplitLine 関数 ( Play )が与えられます。

func ScanLogicalLines(data []byte, atEOF bool) (int, []byte, error) {
    if atEOF && len(data) == 0 {
        return 0, nil, nil
    }

    i := bytes.IndexByte(data, '\n')
    for i > 0 && data[i-1] == '\\' {
        fmt.Printf("i: %d, data[i] = %q\n", i, data[i])
        i = i + bytes.IndexByte(data[i+1:], '\n')
    }

    var match []byte = nil
    advance := 0
    switch {
    case i >= 0:
        advance, match = i + 1, data[0:i]
    case atEOF: 
        advance, match = len(data), data
    }
    token := bytes.Replace(match, []byte("\\\n"), []byte(""), -1)
    return advance, token, nil
}

func main() {
    simple := `
Just a test.

See what is returned. \
when you have empty lines.

Followed by a newline.
`

    scanner := bufio.NewScanner(strings.NewReader(simple))
    scanner.Split(ScanLogicalLines)
    for scanner.Scan() {
        fmt.Printf("line: %q\n", scanner.Text())
    }
}

私はコードが次のようなものを返すことを期待していました:

line: "Just a test."
line: ""
line: "See what is returned, when you have empty lines."
line: ""
line: "Followed by a newline."

ただし、最初の行を返すと停止します。2 番目の呼び出しは を返し1, "", nilます。

誰にもアイデアがありますか、それともバグですか?

4

1 に答える 1

7

返されたトークンが nil ( bufio.SplitFunc )の場合でも、事前値 > 0 はさらに読み取り呼び出しを行うことを意図していないため、これをバグと見なします。

データがまだ完全なトークンを保持していない場合 (たとえば、行のスキャン中に改行がない場合)、SplitFunc は (0, nil) を返して、スキャナにさらにデータを読み取り、スライスから始まる長いスライスで再試行するように通知できます。入力の同じポイント。

どうなるんだこれ

デフォルトの入力バッファはbufio.Scanner4096 バイトです。つまり、可能な場合は一度にこの量まで読み取り、分割機能を実行します。あなたの場合、4096バイトをはるかに下回っているため、スキャナーは入力を一度に読み取ることができます。これは、次の読み取りで、EOFここでの主な問題が発生することを意味します。

一歩一歩

  1. scanner.Scanすべてのデータを読み取ります
  2. そこにあるすべてのテキストを取得します
  3. トークンを探すと、改行が 1 つしかない最初の改行が見つかります
  4. nil一致から改行を削除することにより、トークンとして返されます
  5. scanner.Scan仮定: ユーザーはより多くのデータを必要とする
  6. scanner.Scanもっと読もうとする
  7. EOF起こる
  8. scanner.Scan最後にもう一度トークン化を試みます
  9. あなたが見つけます"Just a test."
  10. scanner.Scan最後にもう一度トークン化を試みます
  11. トークンを探すと、改行が 1 つしかない 3 行目が見つかります
  12. nil一致から改行を削除することにより、トークンとして返されます
  13. scanner.Scanトークンnilが表示され、エラーが設定されます ( EOF)
  14. 実行終了

回避する方法

非 nil のトークンはこれを防ぎます。nil 以外のトークンを返す限り、スキャナーはチェックせず、トークEOFナイザーを実行し続けます。

nilコードがトークンをbytes.Replace返す 理由は、何もすることがないnilときに返されるためです。. これは非 nil: であるため、容量があり要素がないスライスを返すことでこれを防ぐことができます。append([]byte(nil), nil...) == nilmake([]byte, 0, 1) != nil

于 2013-11-12T22:16:52.857 に答える