-
Notifications
You must be signed in to change notification settings - Fork 3
/
numwords.go
107 lines (88 loc) · 2.59 KB
/
numwords.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
// Package numwords is a utility that converts textual numbers to their
// actual numeric values. The converted numbers can be parsed out as strings,
// integers, or floats as desired.
//
// Source: https://github.com/rodaine/numwords
package numwords
import "strings"
// ParseFloat reads a text string and converts it to its float value. An error
// is returned if the if the string cannot be resolved to a single float value.
func ParseFloat(s string) (float64, error) {
in := explode(s)
buf := numbers{}
ok := false
for i := range in {
if buf, ok = readIntoBuffer(i, in, buf); !ok {
return -1, ErrNonNumber
}
}
return reduce(buf).Float()
}
// ParseInt reads a text string and converts it to its integer value. An error
// is returned if the if the string cannot be resolved to a single integer value.
// Fractional portions of the number will be truncated.
func ParseInt(s string) (int, error) {
in := explode(s)
buf := numbers{}
ok := false
for i := range in {
if buf, ok = readIntoBuffer(i, in, buf); !ok {
return -1, ErrNonNumber
}
}
return reduce(buf).Int()
}
// ParseString reads a text string and converts all numbers contained within to
// their appropriate values. Integers are preserved exactly while floating point
// numbers are limited to six decimal places. The rest of the string is preserved.
func ParseString(s string) string {
in := explode(s)
out := ParseStrings(in)
return strings.Join(out, " ")
}
// ParseStrings performs the same actions as ParseString but operates on a pre-
// sanitized and split string. This method is exposed for convenience if further
// processing of the string is required.
func ParseStrings(in []string) []string {
out := make([]string, 0, 1)
buf := numbers{}
ok := false
for i, s := range in {
if buf, ok = readIntoBuffer(i, in, buf); !ok {
out = buf.flush(out)
buf = buf[:0]
out = append(out, s)
}
}
return buf.flush(out)
}
func readIntoBuffer(i int, in []string, buf numbers) (out numbers, ok bool) {
s := in[i]
n, ok := lookupNumber(s)
if ok && n.typ != numAnd {
buf = append(buf, n)
return buf, ok
} else if ok && n.typ == numAnd && shouldIncludeAnd(in, buf, i) {
buf = append(buf, n)
return buf, ok
} else if n, ok = maybeNumeric(s); ok {
buf = append(buf, n)
return buf, ok
}
return buf, false
}
func shouldIncludeAnd(in []string, buf numbers, idx int) bool {
if len(buf) == 0 || idx+1 >= len(in) {
return false
}
prev := buf[len(buf)-1]
if prev.ordinal || prev.typ == numFraction {
return false
}
s := in[idx+1]
if _, ok := lookupNumber(s); !ok {
_, ok = maybeNumeric(s)
return ok
}
return true
}