diff --git a/buff.go b/buff.go index d1d7d24..211c842 100644 --- a/buff.go +++ b/buff.go @@ -3,6 +3,7 @@ package fixedwidth import ( "bytes" "errors" + "strings" "unicode/utf8" ) @@ -183,6 +184,54 @@ type rawValue struct { codepointIndices []int } +func (r rawValue) trimLeft(cutset string) rawValue { + newData := strings.TrimLeft(r.data, cutset) + leftRemovedBytes := len(r.data) - len(newData) + + if r.codepointIndices == nil { + return rawValue{data: newData} + } + + newIndices := r.trimCodepointIndices(leftRemovedBytes, 0) + return rawValue{data: newData, codepointIndices: newIndices} +} + +func (r rawValue) trimRight(cutset string) rawValue { + newData := strings.TrimRight(r.data, cutset) + rightRemovedBytes := len(r.data) - len(newData) + + if r.codepointIndices == nil { + return rawValue{data: newData} + } + + newIndices := r.trimCodepointIndices(0, rightRemovedBytes) + return rawValue{data: newData, codepointIndices: newIndices} +} + +func (r rawValue) trim(cutset string) rawValue { + leftTrimmed := strings.TrimLeft(r.data, cutset) + leftRemovedBytes := len(r.data) - len(leftTrimmed) + bothTrimmed := strings.TrimRight(leftTrimmed, cutset) + rightRemovedBytes := len(leftTrimmed) - len(bothTrimmed) + + if r.codepointIndices == nil { + return rawValue{data: bothTrimmed} + } + + newIndices := r.trimCodepointIndices(leftRemovedBytes, rightRemovedBytes) + return rawValue{data: bothTrimmed, codepointIndices: newIndices} +} + +func (r rawValue) trimCodepointIndices(leftRemovedBytes int, rightRemovedBytes int) []int { + newIndices := make([]int, 0, len(r.codepointIndices)) + for _, idx := range r.codepointIndices { + if idx >= leftRemovedBytes && idx < len(r.data)-rightRemovedBytes { + newIndices = append(newIndices, idx-leftRemovedBytes) + } + } + return newIndices +} + func newRawValue(data string, useCodepointIndices bool) (rawValue, error) { value := rawValue{ data: data, diff --git a/decode.go b/decode.go index 66794c9..b43ba20 100644 --- a/decode.go +++ b/decode.go @@ -8,7 +8,6 @@ import ( "io" "reflect" "strconv" - "strings" ) var ( @@ -197,26 +196,20 @@ func (d *Decoder) readLine(v reflect.Value) (err error, ok bool) { } func rawValueFromLine(value rawValue, startPos, endPos int, format format) rawValue { - var trimFunc func(in string) (out string, leftRemoved int, rightRemoved int) + var trimFunc func(r rawValue) rawValue switch format.alignment { - case left: - trimFunc = func(s string) (out string, leftRemoved int, rightRemoved int) { - out = strings.TrimRight(s, string(format.padChar)) - return out, 0, len(s) - len(out) + case left: // Aligned left, so trim from right side. + trimFunc = func(r rawValue) rawValue { + return r.trimRight(string(format.padChar)) } - case right: - trimFunc = func(s string) (out string, leftRemoved int, rightRemoved int) { - out = strings.TrimLeft(s, string(format.padChar)) - return out, len(s) - len(out), 0 + case right: // Aligned right, so trim from left side. + trimFunc = func(r rawValue) rawValue { + return r.trimLeft(string(format.padChar)) } default: - trimFunc = func(s string) (out string, leftRemoved int, rightRemoved int) { - leftTrimmed := strings.TrimLeft(s, string(format.padChar)) - leftRemoved = len(s) - len(leftTrimmed) - rightTrimmed := strings.TrimRight(leftTrimmed, string(format.padChar)) - rightRemoved = len(leftTrimmed) - len(rightTrimmed) - return rightTrimmed, leftRemoved, rightRemoved + trimFunc = func(r rawValue) rawValue { + return r.trim(string(format.padChar)) } } @@ -245,24 +238,7 @@ func rawValueFromLine(value rawValue, startPos, endPos int, format format) rawVa } } - // Trim the new line data. - newLineData, leftRemovedBytes, rightRemovedBytes := trimFunc(lineData) - trimmedIndices := newIndices - if leftRemovedBytes > 0 || rightRemovedBytes > 0 { - // We must trim our codepoint indices list in order to match - // the newly trimmed line data string. - trimmedIndices = []int{} - for _, idx := range newIndices { - if idx >= leftRemovedBytes && idx < len(lineData)-rightRemovedBytes { - trimmedIndices = append(trimmedIndices, idx-leftRemovedBytes) - } - } - } - - return rawValue{ - data: newLineData, - codepointIndices: trimmedIndices, - } + return trimFunc(rawValue{data: lineData, codepointIndices: newIndices}) } else { if len(value.data) == 0 || startPos > len(value.data) { return rawValue{data: ""} @@ -270,10 +246,7 @@ func rawValueFromLine(value rawValue, startPos, endPos int, format format) rawVa if endPos > len(value.data) { endPos = len(value.data) } - newLineData, _, _ := trimFunc(value.data[startPos-1 : endPos]) - return rawValue{ - data: newLineData, - } + return trimFunc(rawValue{data: value.data[startPos-1 : endPos]}) } }