number.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package strconv
  2. import (
  3. "math"
  4. "unicode/utf8"
  5. )
  6. // ParseNumber parses a byte-slice and returns the number it represents and the amount of decimals.
  7. // If an invalid character is encountered, it will stop there.
  8. func ParseNumber(b []byte, groupSym rune, decSym rune) (int64, int, int) {
  9. n, dec := 0, 0
  10. sign := int64(1)
  11. price := int64(0)
  12. hasDecimals := false
  13. if 0 < len(b) && b[0] == '-' {
  14. sign = -1
  15. n++
  16. }
  17. for n < len(b) {
  18. if '0' <= b[n] && b[n] <= '9' {
  19. digit := sign * int64(b[n]-'0')
  20. if sign == 1 && (math.MaxInt64/10 < price || math.MaxInt64-digit < price*10) {
  21. break
  22. } else if sign == -1 && (price < math.MinInt64/10 || price*10 < math.MinInt64-digit) {
  23. break
  24. }
  25. price *= 10
  26. price += digit
  27. if hasDecimals {
  28. dec++
  29. }
  30. n++
  31. } else if r, size := utf8.DecodeRune(b[n:]); !hasDecimals && (r == groupSym || r == decSym) {
  32. if r == decSym {
  33. hasDecimals = true
  34. }
  35. n += size
  36. } else {
  37. break
  38. }
  39. }
  40. return price, dec, n
  41. }
  42. // AppendNumber will append an int64 formatted as a number with the given number of decimal digits.
  43. func AppendNumber(b []byte, price int64, dec int, groupSize int, groupSym rune, decSym rune) []byte {
  44. if dec < 0 {
  45. dec = 0
  46. }
  47. if utf8.RuneLen(groupSym) == -1 {
  48. groupSym = '.'
  49. }
  50. if utf8.RuneLen(decSym) == -1 {
  51. decSym = ','
  52. }
  53. sign := int64(1)
  54. if price < 0 {
  55. sign = -1
  56. }
  57. // calculate size
  58. n := LenInt(price)
  59. if dec < n && 0 < groupSize && groupSym != 0 {
  60. n += utf8.RuneLen(groupSym) * (n - dec - 1) / groupSize
  61. }
  62. if 0 < dec {
  63. if n <= dec {
  64. n = 1 + dec // zero and decimals
  65. }
  66. n += utf8.RuneLen(decSym)
  67. }
  68. if sign == -1 {
  69. n++
  70. }
  71. // resize byte slice
  72. i := len(b)
  73. if cap(b) < i+n {
  74. b = append(b, make([]byte, n)...)
  75. } else {
  76. b = b[:i+n]
  77. }
  78. // print fractional-part
  79. i += n - 1
  80. if 0 < dec {
  81. for 0 < dec {
  82. c := byte(sign*(price%10)) + '0'
  83. price /= 10
  84. b[i] = c
  85. dec--
  86. i--
  87. }
  88. i -= utf8.RuneLen(decSym)
  89. utf8.EncodeRune(b[i+1:], decSym)
  90. }
  91. // print integer-part
  92. if price == 0 {
  93. b[i] = '0'
  94. if sign == -1 {
  95. b[i-1] = '-'
  96. }
  97. return b
  98. }
  99. j := 0
  100. for price != 0 {
  101. if 0 < groupSize && groupSym != 0 && 0 < j && j%groupSize == 0 {
  102. i -= utf8.RuneLen(groupSym)
  103. utf8.EncodeRune(b[i+1:], groupSym)
  104. }
  105. c := byte(sign*(price%10)) + '0'
  106. price /= 10
  107. b[i] = c
  108. i--
  109. j++
  110. }
  111. if sign == -1 {
  112. b[i] = '-'
  113. }
  114. return b
  115. }