...
Tawesoft Logo

Package humanizex

import "tawesoft.co.uk/go/humanizex"
Overview
Index
Subdirectories

Overview ▾

Package humanizex is an elegant, general-purpose, extensible, modular, locale-aware way to format and parse numbers and quantities - like distances, bytes, and time - in a human-readable way ideal for config files and as a building-block for fully translated ergonomic user interfaces.

If golang.org/x/text is ever promoted to core then there will be a new version of this package named `humanize` (dropping the 'x').

What about dustin's go-humanize?

dustin's go-humanize (https://github.com/dustin/go-humanize) is 3.9 to 4.5 times faster formatting and 2 times faster parsing, if this is a bottleneck for you. It's also quite mature, so is probably very well tested by now. If you're only targeting the English language it also has more handy "out of the box" features.

On the other hand, tawesoft's humanizex is more general purpose and has better localisation support. Even with those extra features, tawesoft's humanizex codebase is also smaller and simpler.

Examples

Example formatting and parsing Byte quantities in various locales

https://www.tawesoft.co.uk/go/doc/humanizex/examples/simple/

Example leveraging the raw parts of FormatParts to handle durations in a custom even nicer way for the english language.

https://www.tawesoft.co.uk/go/doc/humanizex/examples/custom-durations/

Example using custom time factors from the Battlestar Galactica 1978 TV series.

https://www.tawesoft.co.uk/go/doc/humanizex/examples/custom-factors/

Package Information

License: MIT (see LICENSE.txt)

Stable: no

For more information, documentation, source code, examples, support, links, etc. please see https://www.tawesoft.co.uk/go and https://www.tawesoft.co.uk/go/humanizex

Constants

const (
    // FactorModeIdentity indicates that the given factor label represents the
    // unit with no changes.
    FactorModeIdentity = FactorMode(0)

    // FactorModeUnitPrefix indicates the given factor label is a unit prefix
    // e.g. "Ki" is a byte prefix giving "KiB".
    FactorModeUnitPrefix = FactorMode(1)

    // FactorModeReplace indicates the given factor label replaces the current
    // unit e.g. the duration of time 100 s becomes 1 min 40 s, not 1 hs
    // (hectosecond)!
    FactorModeReplace = FactorMode(2)

    // FactorModeInputCompat indicates that the given factor label should only
    // be considered on input. This may be combined with any other FactorMode
    // by a bitwise OR operation.
    FactorModeInputCompat = FactorMode(4)
)

Variables

var CommonFactors = struct {
    // Time is time units in seconds, minutes, hours, days and years as min, h,
    // d, and y. These are non-SI units but generally accepted in context.
    // For times smaller than a second (e.g. nanoseconds), use SI instead.
    // The expected unit is a second (Unit{"s", "s"} or CommonUnits.Second)
    Time Factors

    // Distance are SI units that stop at kilo (because nobody uses
    // megametres or gigametres!) but includes centi. The expected unit is the
    // SI unit for distance, the metre (Unit{"m", "m"} or CommonUnits.Meter)
    Distance Factors

    // IEC are the "ibi" unit prefixes for bytes e.g. Ki, Mi, Gi with a
    // factor of 1024.
    IEC Factors

    // JEDEC are the old unit prefixes for bytes: K, M, G (only) with a factor
    // of 1024.
    JEDEC Factors

    // SIBytes are the SI unit prefixes for bytes e.g. k, M, G with a
    // factor of 1000. Unlike the normal SI Factors, it is assumed based on
    // context that when a "K" is input this is intended to mean the "k" SI
    // unit prefix instead of Kelvin - I've never heard of a Kelvin-Byte!
    SIBytes Factors

    // SIUncommon are the SI unit prefixes including deci, deca, and hecto
    SIUncommon Factors

    // SI are the SI unit prefixes except centi, deci, deca, and hecto
    SI Factors
}{
    Time: Factors{
        Factors: []Factor{
            {1, Unit{"s", "s"}, FactorModeReplace},
            {60, Unit{"min", "min"}, FactorModeReplace},
            {60 * 60, Unit{"h", "h"}, FactorModeReplace},
            {24 * 60 * 60, Unit{"d", "d"}, FactorModeReplace},
            {365.2422 * 24 * 60 * 60, Unit{"y", "y"}, FactorModeReplace},
        },
        Components: 2,
    },
    Distance: Factors{
        Factors: []Factor{
            {1E-9, Unit{"n", "n"}, FactorModeUnitPrefix},
            {1E-6, Unit{"μ", "u"}, FactorModeUnitPrefix},
            {1E-3, Unit{"m", "m"}, FactorModeUnitPrefix},
            {1E-2, Unit{"c", "c"}, FactorModeUnitPrefix},
            {1, Unit{"", ""}, FactorModeIdentity},
            {1000, Unit{"k", "k"}, FactorModeUnitPrefix},
        },
    },
    IEC: Factors{
        Factors: []Factor{
            {1, Unit{"", ""}, FactorModeUnitPrefix},
            {1024, Unit{"Ki", "Ki"}, FactorModeUnitPrefix},
            {1024 * 1024, Unit{"Mi", "Mi"}, FactorModeUnitPrefix},
            {1024 * 1024 * 1024, Unit{"Gi", "Gi"}, FactorModeUnitPrefix},
            {1024 * 1024 * 1024 * 1024, Unit{"Ti", "Ti"}, FactorModeUnitPrefix},
        },
    },
    JEDEC: Factors{
        Factors: []Factor{
            {1, Unit{"", ""}, FactorModeIdentity},
            {1024, Unit{"K", "K"}, FactorModeUnitPrefix},
            {1024 * 1024, Unit{"M", "M"}, FactorModeUnitPrefix},
            {1024 * 1024 * 1024, Unit{"G", "G"}, FactorModeUnitPrefix},
        },
    },
    SIBytes: Factors{
        Factors: []Factor{
            {1, Unit{"", ""}, FactorModeIdentity},
            {1E3, Unit{"k", "k"}, FactorModeUnitPrefix},
            {1E3, Unit{"K", "K"}, FactorModeUnitPrefix | FactorModeInputCompat},
            {1E6, Unit{"M", "M"}, FactorModeUnitPrefix},
            {1E9, Unit{"G", "G"}, FactorModeUnitPrefix},
            {1E12, Unit{"T", "T"}, FactorModeUnitPrefix},
        },
    },
    SIUncommon: Factors{
        Factors: []Factor{
            {1E-9, Unit{"n", "n"}, FactorModeUnitPrefix},
            {1E-6, Unit{"μ", "u"}, FactorModeUnitPrefix},
            {1E-3, Unit{"m", "m"}, FactorModeUnitPrefix},
            {1E-2, Unit{"c", "c"}, FactorModeUnitPrefix},
            {1E-1, Unit{"d", "d"}, FactorModeUnitPrefix},
            {1, Unit{"", ""}, FactorModeIdentity},
            {1E1, Unit{"da", "da"}, FactorModeUnitPrefix},
            {1E2, Unit{"h", "h"}, FactorModeUnitPrefix},
            {1E3, Unit{"k", "k"}, FactorModeUnitPrefix},
            {1E6, Unit{"M", "M"}, FactorModeUnitPrefix},
            {1E9, Unit{"G", "G"}, FactorModeUnitPrefix},
            {1E12, Unit{"T", "T"}, FactorModeUnitPrefix},
        },
    },
    SI: Factors{
        Factors: []Factor{
            {1E-9, Unit{"n", "n"}, FactorModeUnitPrefix},
            {1E-6, Unit{"μ", "u"}, FactorModeUnitPrefix},
            {1E-3, Unit{"m", "m"}, FactorModeUnitPrefix},
            {1, Unit{"", ""}, FactorModeIdentity},
            {1E3, Unit{"k", "k"}, FactorModeUnitPrefix},
            {1E6, Unit{"M", "M"}, FactorModeUnitPrefix},
            {1E9, Unit{"G", "G"}, FactorModeUnitPrefix},
            {1E12, Unit{"T", "T"}, FactorModeUnitPrefix},
        },
    },
}
var CommonUnits = struct {
    None          Unit
    Second        Unit
    Meter         Unit
    Byte          Unit
    Bit           Unit
    BitsPerSecond Unit
}{
    None:          Unit{"", ""},
    Second:        Unit{"s", "s"},
    Meter:         Unit{"m", "m"},
    Byte:          Unit{"B", "B"},
    Bit:           Unit{"b", "b"},
    BitsPerSecond: Unit{"bps", "bps"},
}

type Factor

Factor defines one entry in an ordered list of Factors.

type Factor struct {

    // Magnitude defines the absolute size of the factor e.g. 1000000 for the
    // SI unit prefix "M".
    Magnitude float64

    // Label describes the magnitude, usually as a unit prefix (like SI "M")
    // or as a replacement (like "min"), controlled by Mode.
    Unit Unit

    // Mode controls the formatting of this factor
    Mode FactorMode
}

type FactorMode

FactorMode controls the formatting of a factor.

type FactorMode int

type Factors

Factors describes a way to format a quantity with units.

type Factors struct {
    // Factors is a list of Factor entries in ascending order of size.
    Factors []Factor

    // Components controls how the formatting is broken up -
    //
    // - if zero (default) or 1 (interchangeable), formatting has a single
    // component e.g. "1.5 M".
    //
    // - if 2 or more, formatting is broken up into previous factors e.g.
    // "1 h 50 min" (2 components) or "1 h 50 min 25 s" (3 components)
    Components int
}

type Humanizer

Humanizer implements a locale-aware way to parse and format humanized quantities.

type Humanizer interface {
    // Format is a general purpose locale-aware way to format any quantity
    // with a defined set of factors. The unit argument is the base unit
    // e.g. s for seconds, m for meters, B for bytes.
    Format(value float64, unit Unit, factors Factors) String

    FormatNumber(number float64) String           // e.g. 12 k
    FormatDistance(meters float64) String         // e.g. 10 µm, 10 km
    FormatDuration(duration time.Duration) string // e.g. 1 h 50 min
    FormatSeconds(seconds float64) string         // e.g. 1 h 50 min
    FormatBytesJEDEC(bytes int64) string          // e.g. 12 KB, 5 MB
    FormatBytesIEC(bytes int64) string            // e.g. 12 kB, 5 MB
    FormatBytesSI(bytes int64) string             // e.g. 12 KiB, 5 MiB

    // Accept is a general purpose locale-aware way to parse any quantity
    // with a defined set of factors from the start of the string str. The
    // provided unit is optional and is accepted if it appears in str.
    //
    // Accept returns the value, the number of bytes successfully parsed (which
    // may be zero), or an error.
    Accept(str string, unit Unit, factors Factors) (float64, int, error)

    // Parse is a general purpose locale-aware way to parse any quantity
    // with a defined set of factors.  The provided unit is optional and is
    // accepted if it appears in str.
    Parse(str string, unit Unit, factors Factors) (float64, error)

    ParseDuration(str string) (time.Duration, error)
    ParseBytesJEDEC(str string) (int64, error)
    ParseBytesIEC(str string) (int64, error)
    ParseBytesSI(str string) (int64, error)
}

func NewHumanizer

func NewHumanizer(tag language.Tag, options ...interface{}) Humanizer

NewHumanizer initialises a human language number encoder/decoder for the given tag (representing a specific language or locale).

The language.Tag is usually a named language from golang.org/x/text/language e.g. language.English and controls how numbers are written e.g. comma placement, decimal point, digits.

type Part

Part describes some component of a formatting result e.g. 1.5 km or 1 hour

type Part struct {
    Magnitude float64
    Unit      Unit
}

func FormatParts

func FormatParts(n float64, unit Unit, factors Factors) []Part

FormatParts is a general purpose locale-aware way to format any quantity with a defined set of factors into a list of parts. The unit argument is the base unit e.g. s for seconds, m for meters, B for bytes. In the simple case a list of only one Part is returned, e.g. a Part representing 1.5 km. In other cases, there may be multiple parts e.g. the two parts "1 h" and "30 min" making up the time "1 h 30 min". The number of parts returned is never more than that defined by the factors argument's Components field (but may be fewer).

type String

String holds an Utf8-encoded and an Ascii-compatible encoding of a string.

type String struct {
    // Utf8 is the native Utf8-encoded Unicode representation
    Utf8 string

    // Ascii is an alternative version accepted for non-Unicode inputs (such
    // as when a user does not know how to enter µ on their keyboard (on mine,
    // it's Right-Alt+m)) or for non-Unicode output (such as legacy systems).
    Ascii string
}

type Unit

Unit describes some quantity e.g. "m" for length in metres, "k" for the SI unit prefix kilo, "km" for a kilometre.

type Unit String

func (Unit) Cat

func (u Unit) Cat(v Unit) Unit

Cat concatenates two units (u + v) and returns the result.

Subdirectories

Name Synopsis
examples
custom-durations Example leveraging the raw parts of FormatParts to handle durations in a custom even nicer way for the english language.
custom-factors Example using custom time factors from the Battlestar Galactica 1978 TV series.
simple Example formatting and parsing Byte quantities in various locales