decimal_format.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package utils
  2. import (
  3. "fmt"
  4. "github.com/shopspring/decimal"
  5. "golang.org/x/text/language"
  6. "golang.org/x/text/message"
  7. "strconv"
  8. "strings"
  9. )
  10. // FormatDecimalToString decimal.Decimal
  11. func FormatDecimalToString(d decimal.Decimal) string {
  12. if d.GreaterThan(decimal.NewFromFloat(100000)) {
  13. return decimalFmtWithText0(d)
  14. }
  15. if d.GreaterThan(decimal.NewFromFloat(1000)) {
  16. return decimalFmtWithText2(d)
  17. }
  18. if d.GreaterThan(decimal.NewFromFloat(0.01)) {
  19. return d.Truncate(4).String()
  20. }
  21. return lessZeroFormat(d)
  22. }
  23. // lessZeroFormat 0.0000090235格式化为 "0.{n}1234" 形式
  24. func lessZeroFormat(d decimal.Decimal) string {
  25. // 转为科学计数法字符串(例如 "9.0235E-6")
  26. sciNotation := customScientific(d, 4)
  27. // 分割科学计数法的基数和指数
  28. parts := strings.Split(sciNotation, "E")
  29. if len(parts) != 2 {
  30. return d.String() // 如果不是科学计数法,直接返回原值
  31. }
  32. // 基数部分(如 "9.0235")
  33. base := parts[0]
  34. // 指数部分(如 "-6")
  35. expStr := parts[1]
  36. // 解析指数值
  37. exp, err := strconv.Atoi(expStr)
  38. if err != nil {
  39. return d.String()
  40. }
  41. // 计算前导零的数量(例如 0.000009 → 5个前导零)
  42. leadingZeros := -exp - 1
  43. // 提取有效数字(去掉小数点,取前4位)
  44. digits := strings.Replace(base, ".", "", 1)
  45. if len(digits) > 4 {
  46. digits = digits[:4] // 只保留4位有效数字
  47. }
  48. // 构造最终格式 "0.{n}xxxx"
  49. return fmt.Sprintf("0.{%d}%s", leadingZeros, digits)
  50. }
  51. func customScientific(d decimal.Decimal, precision int) string {
  52. // 获取绝对值
  53. abs := d.Abs()
  54. // 处理零值
  55. if abs.Equal(decimal.Zero) {
  56. return "0E+0"
  57. }
  58. // 计算指数
  59. exp := int32(0)
  60. ten := decimal.NewFromInt(10)
  61. for abs.LessThan(decimal.NewFromInt(1)) && !abs.Equal(decimal.Zero) {
  62. abs = abs.Mul(ten)
  63. exp--
  64. }
  65. for abs.GreaterThanOrEqual(ten) {
  66. abs = abs.Div(ten)
  67. exp++
  68. }
  69. // 格式化系数
  70. coeff := abs.StringFixed(int32(precision))
  71. // 构造结果
  72. return fmt.Sprintf("%sE%+d", coeff, exp)
  73. }
  74. // decimalFmtWithText0 12345678.987 转换为 12,345,679
  75. func decimalFmtWithText0(d decimal.Decimal) string {
  76. p := message.NewPrinter(language.English)
  77. f, _ := d.Float64()
  78. return p.Sprintf("%.0f", f)
  79. }
  80. // decimalFmtWithText2 12345678.987 转换为 12,345,678.99
  81. func decimalFmtWithText2(d decimal.Decimal) string {
  82. p := message.NewPrinter(language.English)
  83. f, _ := d.Float64()
  84. return p.Sprintf("%.2f", f)
  85. }