fixedwidth

package module
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2024 License: MIT Imports: 10 Imported by: 8

README

fixedwidth GoDoc Report card Go Cover

Package fixedwidth provides encoding and decoding for fixed-width formatted Data.

go get github.com/ianlopshire/go-fixedwidth

Usage

Struct Tags

The struct tag schema schema used by fixedwidth is: fixed:"{startPos},{endPos},[{alignment},[{padChar}]]"1.

The startPos and endPos arguments control the position within a line. startPos and endPos must both be positive integers greater than 0. Positions start at 1. The interval is inclusive.

The alignment argument controls the alignment of the value within it's interval. The valid options are default2, right, left, and none. The alignment is optional and can be omitted.

The padChar argument controls the character that will be used to pad any empty characters in the interval after writing the value. The default padding character is a space. The padChar is optional and can be omitted.

Fields without tags are ignored.

Encode
// define some data to encode
people := []struct {
    ID        int     `fixed:"1,5"`
    FirstName string  `fixed:"6,15"`
    LastName  string  `fixed:"16,25"`
    Grade     float64 `fixed:"26,30"`
    Age       uint    `fixed:"31,33"`
    Alive     bool    `fixed:"34,39"`
}{
    {1, "Ian", "Lopshire", 99.5, 20, true},
}

data, err := Marshal(people)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s", data)
// Output:
// 1    Ian       Lopshire  99.5020 true
Decode
// define the format
var people []struct {
    ID        int     `fixed:"1,5"`
    FirstName string  `fixed:"6,15"`
    LastName  string  `fixed:"16,25"`
    Grade     float64 `fixed:"26,30"`
    Age       uint    `fixed:"31,33"`
    Alive     bool    `fixed:"34,39"`
    Github    bool    `fixed:"40,41"`
}

// define some fixed-with data to parse
data := []byte("" +
    "1    Ian       Lopshire  99.50 20 false f" + "\n" +
    "2    John      Doe       89.50 21 true t" + "\n" +
    "3    Jane      Doe       79.50 22 false F" + "\n" +
    "4    Ann       Carraway  79.59 23 false T" + "\n")

err := Unmarshal(data, &people)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%+v\n", people[0])
fmt.Printf("%+v\n", people[1])
fmt.Printf("%+v\n", people[2])
fmt.Printf("%+v\n", people[3])
// Output:
//{ID:1 FirstName:Ian LastName:Lopshire Grade:99.5 Age:20 Alive:false Github:false}
//{ID:2 FirstName:John LastName:Doe Grade:89.5 Age:21 Alive:true Github:true}
//{ID:3 FirstName:Jane LastName:Doe Grade:79.5 Age:22 Alive:false Github:false}
//{ID:4 FirstName:Ann LastName:Carraway Grade:79.59 Age:23 Alive:false Github:true}

It is also possible to read data incrementally

decoder := fixedwidth.NewDecoder(bytes.NewReader(data))
for {
    var element myStruct
    err := decoder.Decode(&element)
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    handle(element)
}
UTF-8, Codepoints, and Multibyte Characters

fixedwidth supports encoding and decoding fixed-width data where indices are expressed in unicode codepoints and not raw bytes. The data must be UTF-8 encoded.

decoder := fixedwidth.NewDecoder(strings.NewReader(data))
decoder.SetUseCodepointIndices(true)
// Decode as usual now
buff := new(bytes.Buffer)
encoder := fixedwidth.NewEncoder(buff)
encoder.SetUseCodepointIndices(true)
// Encode as usual now
Alignment Behavior
Alignment Encoding Decoding
default Field is left aligned The padding character is trimmed from both right and left of value
left Field is left aligned The padding character is trimmed from right of value
right Field is right aligned The padding character is trimmed from left of value
none Field is left aligned The padding character is not trimmed from value. Useful for nested structs.

Notes

  1. {} indicates an argument. [] indicates and optional segment ^
  2. The default alignment is similar to left but has slightly different behavior required to maintain backwards compatibility ^

Licence

MIT

Documentation

Overview

Package fixedwidth provides encoding and decoding for fixed-width formatted Data.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrTooLong indicates a line was too long to decode. Currently, the maximum
	// decodable line length is bufio.MaxScanTokenSize-1.
	ErrTooLong = bufio.ErrTooLong
)

Functions

func Marshal added in v0.2.0

func Marshal(v interface{}) ([]byte, error)

Marshal returns the fixed-width encoding of v.

v must be an encodable type or a slice of an encodable type. If v is a slice, each item will be treated as a line. If v is a single encodable type, a single line will be encoded.

In order for a type to be encodable, it must implement the encoding.TextMarshaler interface or be based on one of the following builtin types: string, int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8, float64, float32, bool, or struct. Pointers to encodable types and interfaces containing encodable types are also encodable.

nil pointers and interfaces will be omitted. zero vales will be encoded normally.

A struct is encoded to a single slice of bytes. Each field in a struct will be encoded and placed at the position defined by its struct tags. The tags should be formatted as `fixed:"{startPos},{endPos}"`. Positions start at 1. The interval is inclusive. Fields without tags and Fields of an un-encodable type are ignored.

If the encoded value of a field is longer than the length of the position interval, the overflow is truncated.

Example
// define some data to encode
people := []struct {
	ID        int     `fixed:"1,5"`
	FirstName string  `fixed:"6,15"`
	LastName  string  `fixed:"16,25"`
	Grade     float64 `fixed:"26,30"`
	Age       uint    `fixed:"31,33"`
	Alive     bool    `fixed:"34,39"`
}{
	{1, "Ian", "Lopshire", 99.5, 20, true},
}

data, err := Marshal(people)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s", data)
Output:

1    Ian       Lopshire  99.5020 true
Example (ConfigurableFormatting)
// define some data to encode
people := []struct {
	ID        int     `fixed:"1,5,right,#"`
	FirstName string  `fixed:"6,15,right,#"`
	LastName  string  `fixed:"16,25,right,#"`
	Grade     float64 `fixed:"26,30,right,#"`
	Age       uint    `fixed:"31,33,right,#"`
	Alive     bool    `fixed:"34,39,right,#"`
}{
	{1, "Ian", "Lopshire", 99.5, 20, true},
}

data, err := Marshal(people)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s", data)
Output:

####1#######Ian##Lopshire99.50#20##true

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal parses fixed width encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

Example
// define the format
var people []struct {
	ID        int     `fixed:"1,5"`
	FirstName string  `fixed:"6,15"`
	LastName  string  `fixed:"16,25"`
	Grade     float64 `fixed:"26,30"`
	Age       uint    `fixed:"31,33"`
	Alive     bool    `fixed:"34,39"`
	Github    bool    `fixed:"40,41"`
}

// define some fixed-with data to parse
data := []byte("" +
	"1    Ian       Lopshire  99.50 20 false f" + "\n" +
	"2    John      Doe       89.50 21 true t" + "\n" +
	"3    Jane      Doe       79.50 22 false F" + "\n" +
	"4    Ann       Carraway  79.59 23 false T" + "\n")

err := Unmarshal(data, &people)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("%+v\n", people[0])
fmt.Printf("%+v\n", people[1])
fmt.Printf("%+v\n", people[2])
fmt.Printf("%+v\n", people[3])
Output:

{ID:1 FirstName:Ian LastName:Lopshire Grade:99.5 Age:20 Alive:false Github:false}
{ID:2 FirstName:John LastName:Doe Grade:89.5 Age:21 Alive:true Github:true}
{ID:3 FirstName:Jane LastName:Doe Grade:79.5 Age:22 Alive:false Github:false}
{ID:4 FirstName:Ann LastName:Carraway Grade:79.59 Age:23 Alive:false Github:true}

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

A Decoder reads and decodes fixed width data from an input stream.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new decoder that reads from r.

func (*Decoder) Decode

func (d *Decoder) Decode(v interface{}) error

Decode reads from its input and stores the decoded data to the value pointed to by v.

In the case that v points to a struct value, Decode will read a single line from the input. If there is no data remaining in the file, returns io.EOF

In the case that v points to a slice value, Decode will read until the end of its input.

Currently, the maximum decodable line length is bufio.MaxScanTokenSize-1. ErrTooLong is returned if a line is encountered that too long to decode.

func (*Decoder) SetLineTerminator added in v0.6.0

func (d *Decoder) SetLineTerminator(lineTerminator []byte)

SetLineTerminator sets the character(s) that will be used to terminate lines.

The default value is "\n".

func (*Decoder) SetUseCodepointIndices added in v0.4.0

func (d *Decoder) SetUseCodepointIndices(use bool)

SetUseCodepointIndices configures `Decoder` on whether the indices in the `fixedwidth` struct tags are expressed in terms of bytes (the default behavior) or in terms of UTF-8 decoded codepoints.

type Encoder added in v0.2.0

type Encoder struct {
	// contains filtered or unexported fields
}

An Encoder writes fixed-width formatted data to an output stream.

func NewEncoder added in v0.2.0

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new encoder that writes to w.

func (*Encoder) Encode added in v0.2.0

func (e *Encoder) Encode(i interface{}) (err error)

Encode writes the fixed-width encoding of v to the stream. See the documentation for Marshal for details about encoding behavior.

func (*Encoder) SetLineTerminator added in v0.5.0

func (e *Encoder) SetLineTerminator(lineTerminator []byte)

SetLineTerminator sets the character(s) that will be used to terminate lines.

The default value is "\n".

func (*Encoder) SetUseCodepointIndices added in v0.9.0

func (e *Encoder) SetUseCodepointIndices(use bool)

SetUseCodepointIndices configures `Encoder` on whether the indices in the `fixedwidth` struct tags are expressed in terms of bytes (the default behavior) or in terms of UTF-8 decoded codepoints.

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type MarshalInvalidTypeError added in v0.2.0

type MarshalInvalidTypeError struct {
	// contains filtered or unexported fields
}

MarshalInvalidTypeError describes an invalid type being marshaled.

func (*MarshalInvalidTypeError) Error added in v0.2.0

func (e *MarshalInvalidTypeError) Error() string

type UnmarshalTypeError

type UnmarshalTypeError struct {
	Value  string       // the raw value
	Type   reflect.Type // type of Go value it could not be assigned to
	Struct string       // name of the struct type containing the field
	Field  string       // name of the field holding the Go value
	Cause  error        // original error
}

An UnmarshalTypeError describes a value that was not appropriate for a value of a specific Go type.

func (*UnmarshalTypeError) Error

func (e *UnmarshalTypeError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL