os.File: how to read a line and get the offset of the line end.

1,775 views
Skip to first unread message

no1o...@gmail.com

unread,
Mar 10, 2014, 9:04:34 PM3/10/14
to golan...@googlegroups.com
hi there,

suppose i have a file with following content:

line 1
line 2
line 3

what i want to do is read line by line, each time print the line content and the line-end offset, just like

line 1 : 6
line 2 : 13
line 3 : 20

what should i do?

thanks  a lot for any help.
Message has been deleted

steve wang

unread,
Mar 10, 2014, 10:30:09 PM3/10/14
to golan...@googlegroups.com
bufio.NewScanner and bufio.Reader might help.
The offset can be accumulated while enumerating lines.
And there is something to be defined because the end-of-line may be different on different systems.
Furthermore, whether end-of-file should be considered as an end-of-line is to be determined.

no1o...@gmail.com

unread,
Mar 16, 2014, 9:35:52 PM3/16/14
to golan...@googlegroups.com
hi there.

thanks for the heads up, i'd try again.

peterGo

unread,
Mar 17, 2014, 12:49:43 AM3/17/14
to golan...@googlegroups.com
Use bufio.Scanner.

For example,

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)

func dropCRLF(data []byte) []byte {
    if len(data) > 0 && data[len(data)-1] == '\n' {
        data = data[0 : len(data)-1]
        if len(data) > 0 && data[len(data)-1] == '\r' {
            data = data[0 : len(data)-1]
        }
    }
    return data
}

// Adaptation of bufio.ScanLines that returns end-of-line carriage returns and line feeds.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
    if atEOF && len(data) == 0 {
        return 0, nil, nil
    }
    if i := bytes.IndexByte(data, '\n'); i >= 0 {
        // We have a full newline-terminated line.
        return i + 1, data[0 : i+1], nil
    }
    // If we're at EOF, we have a final, non-terminated line. Return it.
    if atEOF {
        return len(data), data, nil
    }
    // Request more data.
    return 0, nil, nil
}

func main() {
    f, err := os.Open("lines.txt")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    defer f.Close()
    scanner := bufio.NewScanner(f)
    scanner.Split(ScanLines)
    n := int64(0)
    for scanner.Scan() {
        b := scanner.Bytes()
        eol := n
        n += int64(len(b))
        b = dropCRLF(b)
        eol += int64(len(b))
        fmt.Printf("%s : %d\n", b, eol)
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

Input (lines.txt):


line 1
line 2
line 3

Output:


line 1 : 6
line 2 : 13
line 3 : 20

Matt Harden

unread,
Mar 18, 2014, 10:15:14 AM3/18/14
to peterGo, golang-nuts
A fancy split function would could do it fairly cleanly: http://play.golang.org/p/7OZA_MCXNA


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages