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.

192 lines
4.2 KiB

  1. package humanize
  2. /*
  3. Slightly adapted from the source to fit go-humanize.
  4. Author: https://github.com/gorhill
  5. Source: https://gist.github.com/gorhill/5285193
  6. */
  7. import (
  8. "math"
  9. "strconv"
  10. )
  11. var (
  12. renderFloatPrecisionMultipliers = [...]float64{
  13. 1,
  14. 10,
  15. 100,
  16. 1000,
  17. 10000,
  18. 100000,
  19. 1000000,
  20. 10000000,
  21. 100000000,
  22. 1000000000,
  23. }
  24. renderFloatPrecisionRounders = [...]float64{
  25. 0.5,
  26. 0.05,
  27. 0.005,
  28. 0.0005,
  29. 0.00005,
  30. 0.000005,
  31. 0.0000005,
  32. 0.00000005,
  33. 0.000000005,
  34. 0.0000000005,
  35. }
  36. )
  37. // FormatFloat produces a formatted number as string based on the following user-specified criteria:
  38. // * thousands separator
  39. // * decimal separator
  40. // * decimal precision
  41. //
  42. // Usage: s := RenderFloat(format, n)
  43. // The format parameter tells how to render the number n.
  44. //
  45. // See examples: http://play.golang.org/p/LXc1Ddm1lJ
  46. //
  47. // Examples of format strings, given n = 12345.6789:
  48. // "#,###.##" => "12,345.67"
  49. // "#,###." => "12,345"
  50. // "#,###" => "12345,678"
  51. // "#\u202F###,##" => "12 345,68"
  52. // "#.###,###### => 12.345,678900
  53. // "" (aka default format) => 12,345.67
  54. //
  55. // The highest precision allowed is 9 digits after the decimal symbol.
  56. // There is also a version for integer number, FormatInteger(),
  57. // which is convenient for calls within template.
  58. func FormatFloat(format string, n float64) string {
  59. // Special cases:
  60. // NaN = "NaN"
  61. // +Inf = "+Infinity"
  62. // -Inf = "-Infinity"
  63. if math.IsNaN(n) {
  64. return "NaN"
  65. }
  66. if n > math.MaxFloat64 {
  67. return "Infinity"
  68. }
  69. if n < -math.MaxFloat64 {
  70. return "-Infinity"
  71. }
  72. // default format
  73. precision := 2
  74. decimalStr := "."
  75. thousandStr := ","
  76. positiveStr := ""
  77. negativeStr := "-"
  78. if len(format) > 0 {
  79. format := []rune(format)
  80. // If there is an explicit format directive,
  81. // then default values are these:
  82. precision = 9
  83. thousandStr = ""
  84. // collect indices of meaningful formatting directives
  85. formatIndx := []int{}
  86. for i, char := range format {
  87. if char != '#' && char != '0' {
  88. formatIndx = append(formatIndx, i)
  89. }
  90. }
  91. if len(formatIndx) > 0 {
  92. // Directive at index 0:
  93. // Must be a '+'
  94. // Raise an error if not the case
  95. // index: 0123456789
  96. // +0.000,000
  97. // +000,000.0
  98. // +0000.00
  99. // +0000
  100. if formatIndx[0] == 0 {
  101. if format[formatIndx[0]] != '+' {
  102. panic("RenderFloat(): invalid positive sign directive")
  103. }
  104. positiveStr = "+"
  105. formatIndx = formatIndx[1:]
  106. }
  107. // Two directives:
  108. // First is thousands separator
  109. // Raise an error if not followed by 3-digit
  110. // 0123456789
  111. // 0.000,000
  112. // 000,000.00
  113. if len(formatIndx) == 2 {
  114. if (formatIndx[1] - formatIndx[0]) != 4 {
  115. panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
  116. }
  117. thousandStr = string(format[formatIndx[0]])
  118. formatIndx = formatIndx[1:]
  119. }
  120. // One directive:
  121. // Directive is decimal separator
  122. // The number of digit-specifier following the separator indicates wanted precision
  123. // 0123456789
  124. // 0.00
  125. // 000,0000
  126. if len(formatIndx) == 1 {
  127. decimalStr = string(format[formatIndx[0]])
  128. precision = len(format) - formatIndx[0] - 1
  129. }
  130. }
  131. }
  132. // generate sign part
  133. var signStr string
  134. if n >= 0.000000001 {
  135. signStr = positiveStr
  136. } else if n <= -0.000000001 {
  137. signStr = negativeStr
  138. n = -n
  139. } else {
  140. signStr = ""
  141. n = 0.0
  142. }
  143. // split number into integer and fractional parts
  144. intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
  145. // generate integer part string
  146. intStr := strconv.FormatInt(int64(intf), 10)
  147. // add thousand separator if required
  148. if len(thousandStr) > 0 {
  149. for i := len(intStr); i > 3; {
  150. i -= 3
  151. intStr = intStr[:i] + thousandStr + intStr[i:]
  152. }
  153. }
  154. // no fractional part, we can leave now
  155. if precision == 0 {
  156. return signStr + intStr
  157. }
  158. // generate fractional part
  159. fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
  160. // may need padding
  161. if len(fracStr) < precision {
  162. fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
  163. }
  164. return signStr + intStr + decimalStr + fracStr
  165. }
  166. // FormatInteger produces a formatted number as string.
  167. // See FormatFloat.
  168. func FormatInteger(format string, n int) string {
  169. return FormatFloat(format, float64(n))
  170. }