comma.go raw

   1  package humanize
   2  
   3  import (
   4  	"bytes"
   5  	"math"
   6  	"math/big"
   7  	"strconv"
   8  	"strings"
   9  )
  10  
  11  // Comma produces a string form of the given number in base 10 with
  12  // commas after every three orders of magnitude.
  13  //
  14  // e.g. Comma(834142) -> 834,142
  15  func Comma(v int64) string {
  16  	sign := ""
  17  
  18  	// Min int64 can't be negated to a usable value, so it has to be special cased.
  19  	if v == math.MinInt64 {
  20  		return "-9,223,372,036,854,775,808"
  21  	}
  22  
  23  	if v < 0 {
  24  		sign = "-"
  25  		v = 0 - v
  26  	}
  27  
  28  	parts := []string{"", "", "", "", "", "", ""}
  29  	j := len(parts) - 1
  30  
  31  	for v > 999 {
  32  		parts[j] = strconv.FormatInt(v%1000, 10)
  33  		switch len(parts[j]) {
  34  		case 2:
  35  			parts[j] = "0" + parts[j]
  36  		case 1:
  37  			parts[j] = "00" + parts[j]
  38  		}
  39  		v = v / 1000
  40  		j--
  41  	}
  42  	parts[j] = strconv.Itoa(int(v))
  43  	return sign + strings.Join(parts[j:], ",")
  44  }
  45  
  46  // Commaf produces a string form of the given number in base 10 with
  47  // commas after every three orders of magnitude.
  48  //
  49  // e.g. Commaf(834142.32) -> 834,142.32
  50  func Commaf(v float64) string {
  51  	buf := &bytes.Buffer{}
  52  	if v < 0 {
  53  		buf.Write([]byte{'-'})
  54  		v = 0 - v
  55  	}
  56  
  57  	comma := []byte{','}
  58  
  59  	parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
  60  	pos := 0
  61  	if len(parts[0])%3 != 0 {
  62  		pos += len(parts[0]) % 3
  63  		buf.WriteString(parts[0][:pos])
  64  		buf.Write(comma)
  65  	}
  66  	for ; pos < len(parts[0]); pos += 3 {
  67  		buf.WriteString(parts[0][pos : pos+3])
  68  		buf.Write(comma)
  69  	}
  70  	buf.Truncate(buf.Len() - 1)
  71  
  72  	if len(parts) > 1 {
  73  		buf.Write([]byte{'.'})
  74  		buf.WriteString(parts[1])
  75  	}
  76  	return buf.String()
  77  }
  78  
  79  // CommafWithDigits works like the Commaf but limits the resulting
  80  // string to the given number of decimal places.
  81  //
  82  // e.g. CommafWithDigits(834142.32, 1) -> 834,142.3
  83  func CommafWithDigits(f float64, decimals int) string {
  84  	return stripTrailingDigits(Commaf(f), decimals)
  85  }
  86  
  87  // BigComma produces a string form of the given big.Int in base 10
  88  // with commas after every three orders of magnitude.
  89  func BigComma(b *big.Int) string {
  90  	sign := ""
  91  	if b.Sign() < 0 {
  92  		sign = "-"
  93  		b.Abs(b)
  94  	}
  95  
  96  	athousand := big.NewInt(1000)
  97  	c := (&big.Int{}).Set(b)
  98  	_, m := oom(c, athousand)
  99  	parts := make([]string, m+1)
 100  	j := len(parts) - 1
 101  
 102  	mod := &big.Int{}
 103  	for b.Cmp(athousand) >= 0 {
 104  		b.DivMod(b, athousand, mod)
 105  		parts[j] = strconv.FormatInt(mod.Int64(), 10)
 106  		switch len(parts[j]) {
 107  		case 2:
 108  			parts[j] = "0" + parts[j]
 109  		case 1:
 110  			parts[j] = "00" + parts[j]
 111  		}
 112  		j--
 113  	}
 114  	parts[j] = strconv.Itoa(int(b.Int64()))
 115  	return sign + strings.Join(parts[j:], ",")
 116  }
 117