123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- package humanize
- /*
- Slightly adapted from the source to fit go-humanize.
- Author: https://github.com/gorhill
- Source: https://gist.github.com/gorhill/5285193
- */
- import (
- "math"
- "strconv"
- )
- var (
- renderFloatPrecisionMultipliers = [...]float64{
- 1,
- 10,
- 100,
- 1000,
- 10000,
- 100000,
- 1000000,
- 10000000,
- 100000000,
- 1000000000,
- }
- renderFloatPrecisionRounders = [...]float64{
- 0.5,
- 0.05,
- 0.005,
- 0.0005,
- 0.00005,
- 0.000005,
- 0.0000005,
- 0.00000005,
- 0.000000005,
- 0.0000000005,
- }
- )
- // FormatFloat produces a formatted number as string based on the following user-specified criteria:
- // * thousands separator
- // * decimal separator
- // * decimal precision
- //
- // Usage: s := RenderFloat(format, n)
- // The format parameter tells how to render the number n.
- //
- // See examples: http://play.golang.org/p/LXc1Ddm1lJ
- //
- // Examples of format strings, given n = 12345.6789:
- // "#,###.##" => "12,345.67"
- // "#,###." => "12,345"
- // "#,###" => "12345,678"
- // "#\u202F###,##" => "12 345,68"
- // "#.###,###### => 12.345,678900
- // "" (aka default format) => 12,345.67
- //
- // The highest precision allowed is 9 digits after the decimal symbol.
- // There is also a version for integer number, FormatInteger(),
- // which is convenient for calls within template.
- func FormatFloat(format string, n float64) string {
- // Special cases:
- // NaN = "NaN"
- // +Inf = "+Infinity"
- // -Inf = "-Infinity"
- if math.IsNaN(n) {
- return "NaN"
- }
- if n > math.MaxFloat64 {
- return "Infinity"
- }
- if n < -math.MaxFloat64 {
- return "-Infinity"
- }
- // default format
- precision := 2
- decimalStr := "."
- thousandStr := ","
- positiveStr := ""
- negativeStr := "-"
- if len(format) > 0 {
- format := []rune(format)
- // If there is an explicit format directive,
- // then default values are these:
- precision = 9
- thousandStr = ""
- // collect indices of meaningful formatting directives
- formatIndx := []int{}
- for i, char := range format {
- if char != '#' && char != '0' {
- formatIndx = append(formatIndx, i)
- }
- }
- if len(formatIndx) > 0 {
- // Directive at index 0:
- // Must be a '+'
- // Raise an error if not the case
- // index: 0123456789
- // +0.000,000
- // +000,000.0
- // +0000.00
- // +0000
- if formatIndx[0] == 0 {
- if format[formatIndx[0]] != '+' {
- panic("RenderFloat(): invalid positive sign directive")
- }
- positiveStr = "+"
- formatIndx = formatIndx[1:]
- }
- // Two directives:
- // First is thousands separator
- // Raise an error if not followed by 3-digit
- // 0123456789
- // 0.000,000
- // 000,000.00
- if len(formatIndx) == 2 {
- if (formatIndx[1] - formatIndx[0]) != 4 {
- panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
- }
- thousandStr = string(format[formatIndx[0]])
- formatIndx = formatIndx[1:]
- }
- // One directive:
- // Directive is decimal separator
- // The number of digit-specifier following the separator indicates wanted precision
- // 0123456789
- // 0.00
- // 000,0000
- if len(formatIndx) == 1 {
- decimalStr = string(format[formatIndx[0]])
- precision = len(format) - formatIndx[0] - 1
- }
- }
- }
- // generate sign part
- var signStr string
- if n >= 0.000000001 {
- signStr = positiveStr
- } else if n <= -0.000000001 {
- signStr = negativeStr
- n = -n
- } else {
- signStr = ""
- n = 0.0
- }
- // split number into integer and fractional parts
- intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
- // generate integer part string
- intStr := strconv.FormatInt(int64(intf), 10)
- // add thousand separator if required
- if len(thousandStr) > 0 {
- for i := len(intStr); i > 3; {
- i -= 3
- intStr = intStr[:i] + thousandStr + intStr[i:]
- }
- }
- // no fractional part, we can leave now
- if precision == 0 {
- return signStr + intStr
- }
- // generate fractional part
- fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
- // may need padding
- if len(fracStr) < precision {
- fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
- }
- return signStr + intStr + decimalStr + fracStr
- }
- // FormatInteger produces a formatted number as string.
- // See FormatFloat.
- func FormatInteger(format string, n int) string {
- return FormatFloat(format, float64(n))
- }
|