diff --git a/formatter/byte.go b/formatter/byte.go index 26b81f73..10ac3414 100644 --- a/formatter/byte.go +++ b/formatter/byte.go @@ -6,6 +6,9 @@ import ( "strconv" "strings" "unicode" + + "github.com/duke-git/lancet/v2/mathutil" + "github.com/duke-git/lancet/v2/strutil" ) // @@ -91,32 +94,21 @@ func DecimalBytes(size float64, precision ...int) string { size, unit := calculateByteSize(size, 1000.0, decimalByteUnits) - format := fmt.Sprintf("%%.%df", pointPosition) - bytes := fmt.Sprintf(format, size) - - for i := len(bytes); i > 0; i-- { - s := bytes[i-1] - if s != '0' && s != '.' { - break - } - - bytes = bytes[:i-1] - } - - return bytes + unit + return roundToToString(size, pointPosition) + unit } // BinaryBytes returns a human-readable byte size under binary standard (base 1024) // The precision parameter specifies the number of digits after the decimal point, which defaults to 4. // Play: https://go.dev/play/p/G9oHHMCAZxP func BinaryBytes(size float64, precision ...int) string { - p := 5 + pointPosition := 4 if len(precision) > 0 { - p = precision[0] + 1 + pointPosition = precision[0] } + size, unit := calculateByteSize(size, 1024.0, binaryByteUnits) - return fmt.Sprintf("%.*g%s", p, size, unit) + return roundToToString(size, pointPosition) + unit } func calculateByteSize(size float64, base float64, byteUnits []string) (float64, string) { @@ -129,6 +121,29 @@ func calculateByteSize(size float64, base float64, byteUnits []string) (float64, return size, byteUnits[i] } +func roundToToString(x float64, max ...int) string { + pointPosition := 4 + if len(max) > 0 { + pointPosition = max[0] + } + result := mathutil.RoundToString(x, pointPosition) + + // 删除小数位结尾的0 + decimal := strings.TrimRight(strutil.After(result, "."), "0") + if decimal == "" || pointPosition == 0 { + // 没有小数位直接返回整数 + return strutil.Before(result, ".") + } + + // 小数位大于想要设置的位数,按需要截断 + if len(decimal) > pointPosition { + return strutil.Before(result, ".") + "." + decimal[:pointPosition] + } + + // 小数位小于等于想要的位数,直接拼接返回 + return strutil.Before(result, ".") + "." + decimal +} + // ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000). // ParseDecimalBytes("42 MB") -> 42000000, nil // Play: https://go.dev/play/p/Am98ybWjvjj diff --git a/formatter/byte_test.go b/formatter/byte_test.go index dc4e97ab..6bc50d40 100644 --- a/formatter/byte_test.go +++ b/formatter/byte_test.go @@ -25,6 +25,9 @@ func TestDecimalBytes(t *testing.T) { assert.Equal("401MB", DecimalBytes(401000000)) assert.Equal("401MB", DecimalBytes(401000000, 0)) assert.Equal("4MB", DecimalBytes(4010000, 0)) + + assert.Equal("4MB", DecimalBytes(4000000, 0)) + assert.Equal("4MB", DecimalBytes(4000000, 1)) } func TestBinaryBytes(t *testing.T) { @@ -36,6 +39,10 @@ func TestBinaryBytes(t *testing.T) { assert.Equal("1MiB", BinaryBytes(1024*1024)) assert.Equal("1.1774MiB", BinaryBytes(1234567)) assert.Equal("1.18MiB", BinaryBytes(1234567, 2)) + + assert.Equal("10KiB", BinaryBytes(10240, 0)) + assert.Equal("10KiB", BinaryBytes(10240, 1)) + assert.Equal("10KiB", BinaryBytes(10240, 2)) } func TestParseDecimalBytes(t *testing.T) {