Reputation: 2791
How do I convert a string into a float from an unusual format (e.g. 2.93B, 201k)? Using the normal approach doesn't work i.e:
i, err := strconv.ParseFloat("2.93B", 64) // Returns an 'invalid syntax' error
Upvotes: 0
Views: 1829
Reputation: 166596
For example,
package main
import (
"fmt"
"strconv"
"unicode/utf8"
)
var siFactors = map[string]float64{
"": 1e0,
"k": 1e3,
"M": 1e6, // Sometimes, M (Roman numeral) for thousands and MM for millions
"G": 1e9,
"T": 1e12,
"P": 1e15,
"E": 1e18,
"Z": 1e21,
"Y": 1e24,
"K": 1e3, // colloquial synonym for "k"
"B": 1e9, // colloquial synonym for "G"
}
func parseNumber(s string) (float64, error) {
f, err := strconv.ParseFloat(s, 64)
if err == nil {
return f, nil
}
r, size := utf8.DecodeLastRuneInString(s)
if r == utf8.RuneError {
return 0, err
}
symbol := s[len(s)-size : len(s)]
factor, ok := siFactors[symbol]
if !ok {
return 0, err
}
f, e := strconv.ParseFloat(s[:len(s)-len(symbol)], 64)
if e != nil {
return 0, err
}
return f * factor, nil
}
func main() {
for _, s := range []string{"2.93", "2.93k", "2.93M", "2.93G", "2.93B", "2930000000", "2.93X", "G"} {
n, err := parseNumber(s)
fmt.Printf("%q\t %g %v\n", s, n, err)
}
}
Playground: https://play.golang.org/p/DYEe5gQ8pl
Output:
"2.93" 2.93 <nil>
"2.93k" 2930 <nil>
"2.93M" 2.93e+06 <nil>
"2.93G" 2.93e+09 <nil>
"2.93B" 2.93e+09 <nil>
"2930000000" 2.93e+09 <nil>
"2.93X" 0 strconv.ParseFloat: parsing "2.93X": invalid syntax
"B" 0 strconv.ParseFloat: parsing "B": invalid syntax
Upvotes: 3