-
Notifications
You must be signed in to change notification settings - Fork 1
/
number.go
202 lines (174 loc) · 4.78 KB
/
number.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package gofn
import (
"fmt"
"strconv"
"strings"
"unsafe"
)
const (
base10 = 10
byte2Bits = 8
fractionSep = '.'
noFractionSep = byte(0)
groupSep = ','
)
func ParseIntEx[T IntEx](s string, base int) (T, error) {
var zeroT T
v, err := strconv.ParseInt(s, base, int(unsafe.Sizeof(zeroT)*byte2Bits))
if err == nil {
return T(v), nil
}
return zeroT, err // nolint: wrapcheck
}
func ParseInt[T IntEx](s string) (T, error) {
return ParseIntEx[T](s, base10)
}
// ParseIntUngroup omit all grouping commas then parse the string value
func ParseIntUngroup[T IntEx](s string) (T, error) {
return ParseIntEx[T](NumberFmtUngroup(s, groupSep), base10)
}
func ParseIntDef[T IntEx](s string, defaultVal T) T {
v, err := strconv.ParseInt(s, base10, int(unsafe.Sizeof(defaultVal)*byte2Bits))
if err == nil {
return T(v)
}
return defaultVal
}
func ParseUintEx[T UIntEx](s string, base int) (T, error) {
var zeroT T
v, err := strconv.ParseUint(s, base, int(unsafe.Sizeof(zeroT)*byte2Bits))
if err == nil {
return T(v), nil
}
return zeroT, err // nolint: wrapcheck
}
func ParseUint[T UIntEx](s string) (T, error) {
return ParseUintEx[T](s, base10)
}
// ParseUintUngroup omit all grouping commas then parse the string value
func ParseUintUngroup[T UIntEx](s string) (T, error) {
return ParseUintEx[T](NumberFmtUngroup(s, groupSep), base10)
}
func ParseUintDef[T UIntEx](s string, defaultVal T) T {
v, err := strconv.ParseUint(s, base10, int(unsafe.Sizeof(defaultVal)*byte2Bits))
if err == nil {
return T(v)
}
return defaultVal
}
func ParseFloat[T FloatEx](s string) (T, error) {
var zeroT T
v, err := strconv.ParseFloat(s, int(unsafe.Sizeof(zeroT)*byte2Bits))
if err == nil {
return T(v), nil
}
return zeroT, err // nolint: wrapcheck
}
// ParseFloatUngroup omit all grouping commas then parse the string value
func ParseFloatUngroup[T FloatEx](s string) (T, error) {
return ParseFloat[T](NumberFmtUngroup(s, groupSep))
}
func ParseFloatDef[T FloatEx](s string, defaultVal T) T {
v, err := strconv.ParseFloat(s, int(unsafe.Sizeof(defaultVal)*byte2Bits))
if err == nil {
return T(v)
}
return defaultVal
}
func FormatIntEx[T IntEx](v T, format string) string {
return fmt.Sprintf(format, v)
}
func FormatInt[T IntEx](v T) string {
return strconv.FormatInt(int64(v), base10)
}
// FormatIntGroup format the value then group the decimal using comma
func FormatIntGroup[T IntEx](v T) string {
s := strconv.FormatInt(int64(v), base10)
return NumberFmtGroup(s, noFractionSep, groupSep)
}
func FormatUintEx[T UIntEx](v T, format string) string {
return fmt.Sprintf(format, v)
}
func FormatUint[T UIntEx](v T) string {
return strconv.FormatUint(uint64(v), base10)
}
// FormatUintGroup format the value then group the decimal using comma
func FormatUintGroup[T UIntEx](v T) string {
return NumberFmtGroup(strconv.FormatUint(uint64(v), base10), noFractionSep, groupSep)
}
func FormatFloatEx[T FloatEx](v T, format string) string {
return fmt.Sprintf(format, v)
}
func FormatFloat[T FloatEx](v T) string {
return fmt.Sprintf("%f", v)
}
// FormatFloatGroup format the value then group the decimal using comma
func FormatFloatGroup[T FloatEx](v T) string {
return NumberFmtGroup(fmt.Sprintf("%f", v), fractionSep, groupSep)
}
// FormatFloatGroupEx format the value then group the decimal using comma
func FormatFloatGroupEx[T FloatEx](v T, format string) string {
return NumberFmtGroup(fmt.Sprintf(format, v), fractionSep, groupSep)
}
// NumberFmtGroup separate decimal groups in the value string
func NumberFmtGroup(num string, fractionSep, groupSep byte) string {
if len(num) < 4 { // nolint: gomnd
return num
}
// Format as integer
if fractionSep == 0 {
return numberPartFmtGroup(num, groupSep)
}
// Format as real number
fractionIndex := strings.IndexByte(num, fractionSep)
if fractionIndex >= 0 {
return numberPartFmtGroup(num[:fractionIndex], groupSep) + num[fractionIndex:]
}
return numberPartFmtGroup(num, groupSep)
}
// NumberFmtUngroup ungroup the value string
func NumberFmtUngroup(num string, groupSep byte) string {
ret := make([]byte, 0, len(num))
for i := range num {
if num[i] == groupSep {
continue
}
ret = append(ret, num[i])
}
return string(ret)
}
func numberPartFmtGroup(s string, groupSep byte) string {
if !stringIsNumeric(s, true) {
return s
}
buf := make([]byte, 0, len(s)+5) // nolint: gomnd
ch := s[0]
if ch == '-' {
buf = append(buf, ch)
s = s[1:]
}
start := len(s) % 3
if start == 0 {
start = 3
}
for i := range s {
ch = s[i]
if i != 0 && i == start {
buf = append(buf, groupSep)
start += 3
}
buf = append(buf, ch)
}
return string(buf)
}
func stringIsNumeric(s string, allowSign bool) bool {
if allowSign && len(s) > 0 && s[0] == '-' {
s = s[1:]
}
for _, ch := range s {
if ch < '0' || ch > '9' {
return false
}
}
return true
}