diff --git a/pkg/util/excelutils/excelutils.go b/pkg/util/excelutils/excelutils.go index d342850c48..ee3f8cb11a 100644 --- a/pkg/util/excelutils/excelutils.go +++ b/pkg/util/excelutils/excelutils.go @@ -24,6 +24,8 @@ import ( "github.com/360EntSecGroup-Skylar/excelize" "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -92,7 +94,13 @@ func exportRow(xlsx *excelize.File, data jsonutils.JSONObject, keys []string, ro val, _ = data.GetIgnoreCases(keys[i]) } if val != nil { - valStr, _ = val.GetString() + // hack, make floating point number prettier + if fval, ok := val.(*jsonutils.JSONFloat); ok { + f, _ := fval.Float() + valStr = stringutils2.PrettyFloat(f, 2) + } else { + valStr, _ = val.GetString() + } } cell := fmt.Sprintf("%s%d", decimal2Alphabet(i), rowIndex) xlsx.SetCellValue(DEFAULT_SHEET, cell, valStr) diff --git a/pkg/util/stringutils2/stringutils.go b/pkg/util/stringutils2/stringutils.go index e92d66e0c4..205f0006ea 100644 --- a/pkg/util/stringutils2/stringutils.go +++ b/pkg/util/stringutils2/stringutils.go @@ -19,6 +19,7 @@ import ( "encoding/hex" "fmt" "math/rand" + "strconv" "strings" "time" ) @@ -187,3 +188,49 @@ func FilterEmpty(input []string) []string { } return ret } + +func PrettyFloat(f float64, precision int) string { + fstr := strconv.FormatFloat(f, 'f', -1, 64) + dotPos := strings.Index(fstr, ".") + if dotPos < 0 { + return fstr + } + neg := false + if fstr[0] == '-' { + neg = true + fstr = fstr[1:] + dotPos -= 1 + } + numPart, _ := strconv.ParseInt(fstr[:dotPos], 10, 64) + prePartStr := fstr[dotPos+1:] + if numPart == 0 { + nonZeroPos := 0 + for prePartStr[nonZeroPos] == '0' { + nonZeroPos += 1 + } + precision += nonZeroPos + } + if precision < len(prePartStr) { + prePart, _ := strconv.ParseInt(prePartStr[:precision], 10, 64) + if prePartStr[precision] > '4' { + // rounding up + prePart += 1 + } + prePartStr = fmt.Sprintf(fmt.Sprintf("%%.%dd", precision), prePart) + if len(prePartStr) > precision { + prePartStr = prePartStr[1:] + numPart += 1 + } + } + for len(prePartStr) > 0 && prePartStr[len(prePartStr)-1] == '0' { + prePartStr = prePartStr[0 : len(prePartStr)-1] + } + ret := strconv.FormatInt(numPart, 10) + if len(prePartStr) > 0 { + ret += "." + prePartStr + } + if neg { + ret = "-" + ret + } + return ret +} diff --git a/pkg/util/stringutils2/stringutils_test.go b/pkg/util/stringutils2/stringutils_test.go index 8047fcbfdf..05cecc96c8 100644 --- a/pkg/util/stringutils2/stringutils_test.go +++ b/pkg/util/stringutils2/stringutils_test.go @@ -16,6 +16,7 @@ package stringutils2 import ( "reflect" + "strconv" "testing" ) @@ -211,3 +212,73 @@ func TestFilterEmpty(t *testing.T) { } } } + +func TestPrettyFloat(t *testing.T) { + cases := []struct { + in float64 + prec int + want string + }{ + { + in: 3.1415926, + prec: 2, + want: "3.14", + }, + { + in: 3.1415926, + prec: 3, + want: "3.142", + }, + { + in: 3.89999999, + prec: 2, + want: "3.9", + }, + { + in: 3.88999999, + prec: 2, + want: "3.89", + }, + { + in: 3.99999999, + prec: 2, + want: "4", + }, + { + in: 0.000020000001, + prec: 2, + want: "0.00002", + }, + { + in: 0.000021000001, + prec: 2, + want: "0.000021", + }, + { + in: 0.000021100001, + prec: 2, + want: "0.000021", + }, + { + in: -3.15, + prec: 1, + want: "-3.2", + }, + { + in: 3.5, + prec: 0, + want: "4", + }, + { + in: 0.999999999999, + prec: 2, + want: "1", + }, + } + for _, c := range cases { + got := PrettyFloat(c.in, c.prec) + if got != c.want { + t.Errorf("%s precision %d want %s got %s", strconv.FormatFloat(c.in, 'f', -1, 64), c.prec, c.want, got) + } + } +}