From 7c5918c35f347446cd7db9804ca3a3caa1187a7d Mon Sep 17 00:00:00 2001 From: Leon Bogaert Date: Tue, 10 Dec 2019 14:16:52 +0100 Subject: [PATCH] Implement suggest changes for decode lineTerminator --- decode.go | 30 +++++++++++++----------------- decode_test.go | 30 +++++++++++++++--------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/decode.go b/decode.go index 45eb695..f050d56 100644 --- a/decode.go +++ b/decode.go @@ -22,7 +22,7 @@ func Unmarshal(data []byte, v interface{}) error { // A Decoder reads and decodes fixed width data from an input stream. type Decoder struct { scanner *bufio.Scanner - separator string + lineTerminator []byte done bool useCodepointIndices bool @@ -33,10 +33,10 @@ type Decoder struct { // NewDecoder returns a new decoder that reads from r. func NewDecoder(r io.Reader) *Decoder { dec := &Decoder{ - scanner: bufio.NewScanner(r), - separator: "", + scanner: bufio.NewScanner(r), + lineTerminator: []byte("\n"), } - dec.scanner.Split(dec.Scan) + dec.scanner.Split(dec.scan) return dec } @@ -182,26 +182,22 @@ func findFirstMultiByteChar(data string) int { return len(data) } -func (d *Decoder) SetSeparator(separator string) { - d.separator = separator -} - -func (d Decoder) Separator() string { - if d.separator != "" { - return d.separator +// SetLineTerminator sets the character(s) that will be used to terminate lines. +// +// The default value is "\n". +func (d *Decoder) SetLineTerminator(lineTerminator []byte) { + if len(lineTerminator) > 0 { + d.lineTerminator = lineTerminator } - - return "\n" } -func (d *Decoder) Scan(data []byte, atEOF bool) (advance int, token []byte, err error) { - sep := []byte(d.Separator()) +func (d *Decoder) scan(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } - if i := bytes.Index(data, sep); i >= 0 { + if i := bytes.Index(data, d.lineTerminator); i >= 0 { // We have a full newline-terminated line. - return i + len(sep), data[0:i], nil + return i + len(d.lineTerminator), data[0:i], nil } // If we're at EOF, we have a final, non-terminated line. Return it. if atEOF { diff --git a/decode_test.go b/decode_test.go index dad5812..1cdbed0 100644 --- a/decode_test.go +++ b/decode_test.go @@ -342,12 +342,12 @@ func TestLineSeparator(t *testing.T) { TextUnmarshaler EncodableString `fixed:"16,20"` } for _, tt := range []struct { - name string - rawValue []byte - target interface{} - expected interface{} - shouldErr bool - separator string + name string + rawValue []byte + target interface{} + expected interface{} + shouldErr bool + lineTerminator []byte }{ { name: "CR line endings", @@ -357,8 +357,8 @@ func TestLineSeparator(t *testing.T) { {"foo", 123, 1.2, EncodableString{"bar", nil}}, {"bar", 321, 2.1, EncodableString{"foo", nil}}, }, - shouldErr: false, - separator: "", + shouldErr: false, + lineTerminator: []byte{}, }, { name: "CR line endings", @@ -368,8 +368,8 @@ func TestLineSeparator(t *testing.T) { {"f\ro", 123, 1.2, EncodableString{"bar", nil}}, {"bar", 321, 2.1, EncodableString{"foo", nil}}, }, - shouldErr: false, - separator: "\n", + shouldErr: false, + lineTerminator: []byte("\n"), }, { name: "CRLF line endings", @@ -379,8 +379,8 @@ func TestLineSeparator(t *testing.T) { {"f\no", 123, 1.2, EncodableString{"bar", nil}}, {"bar", 321, 2.1, EncodableString{"foo", nil}}, }, - shouldErr: false, - separator: "\r\n", + shouldErr: false, + lineTerminator: []byte("\r\n"), }, { name: "LF line endings", @@ -390,13 +390,13 @@ func TestLineSeparator(t *testing.T) { {"f\no", 123, 1.2, EncodableString{"bar", nil}}, {"bar", 321, 2.1, EncodableString{"foo", nil}}, }, - shouldErr: false, - separator: "\r", + shouldErr: false, + lineTerminator: []byte("\r"), }, } { t.Run(tt.name, func(t *testing.T) { dec := NewDecoder(bytes.NewReader(tt.rawValue)) - dec.SetSeparator(tt.separator) + dec.SetLineTerminator(tt.lineTerminator) err := dec.Decode(tt.target) if tt.shouldErr != (err != nil) { t.Errorf("Unmarshal() err want %v, have %v (%v)", tt.shouldErr, err != nil, err)