You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
2.1 KiB

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