Browse Source

Merge pull request #5 from ryho/ryanh/fix_zero_case_in_FormattedValue

Fix zero and negative case in FormattedValue()
Ryan Hollis 8 năm trước cách đây
mục cha
commit
999c7e1c38
2 tập tin đã thay đổi với 112 bổ sung33 xóa
  1. 42 16
      cell.go
  2. 70 17
      cell_test.go

+ 42 - 16
cell.go

@@ -206,6 +206,45 @@ func (c *Cell) Int64() (int64, error) {
 	return f, nil
 	return f, nil
 }
 }
 
 
+// GeneralNumeric returns the value of the cell as a string. It is formatted very closely to the the XLSX spec for how
+// to display values when the storage type is Number and the format type is General. It is not 100% identical to the
+// spec but is as close as you can get using the built in Go formatting tools.
+func (c *Cell) GeneralNumeric() (string, error) {
+	f, err := strconv.ParseFloat(c.Value, 64)
+	if err != nil {
+		return c.Value, err
+	}
+	absF := math.Abs(f)
+	// When using General format, numbers that are less than 1e-9 (0.000000001) and greater than or equal to
+	// 1e11 (100,000,000,000) should be shown in scientific notation.
+	// Numbers less than the number after zero, are assumed to be zero.
+	if (absF >= math.SmallestNonzeroFloat64 && absF < minNonScientificNumber) || absF >= maxNonScientificNumber {
+		return strconv.FormatFloat(f, 'E', -1, 64), nil
+	}
+	// This format (fmt="f", prec=-1) will prevent padding with zeros and will never switch to scientific notation.
+	// However, it will show more than 11 characters for very precise numbers, and this cannot be changed.
+	// You could also use fmt="g", prec=11, which doesn't pad with zeros and allows the correct precision,
+	// but it will use scientific notation on numbers less than 1e-4. That value is hardcoded in Go and cannot be
+	// configured or disabled.
+	return strconv.FormatFloat(f, 'f', -1, 64), nil
+}
+
+// GeneralNumericWithoutScientific returns numbers that are always formatted as numbers, but it does not follow
+// the rules for when XLSX should switch to scientific notation, since sometimes scientific notation is not desired,
+// even if that is how the document is supposed to be formatted.
+func (c *Cell) GeneralNumericWithoutScientific() (string, error) {
+	f, err := strconv.ParseFloat(c.Value, 64)
+	if err != nil {
+		return c.Value, err
+	}
+	// This format (fmt="f", prec=-1) will prevent padding with zeros and will never switch to scientific notation.
+	// However, it will show more than 11 characters for very precise numbers, and this cannot be changed.
+	// You could also use fmt="g", prec=11, which doesn't pad with zeros and allows the correct precision,
+	// but it will use scientific notation on numbers less than 1e-4. That value is hardcoded in Go and cannot be
+	// configured or disabled.
+	return strconv.FormatFloat(f, 'f', -1, 64), nil
+}
+
 // SetInt sets a cell's value to an integer.
 // SetInt sets a cell's value to an integer.
 func (c *Cell) SetInt(n int) {
 func (c *Cell) SetInt(n int) {
 	c.SetValue(n)
 	c.SetValue(n)
@@ -348,7 +387,8 @@ func (c *Cell) formatToInt(format string) (string, error) {
 // leading zeros and decimal separator.***
 // leading zeros and decimal separator.***
 //
 //
 // Added Notes:
 // Added Notes:
-// * "If the number is too large" means "if the number has more than 11 digits", so greater than or equal to 1e11.
+// * "If the number is too large" can also mean "if the number has more than 11 digits", so greater than or equal to
+// 1e11 and less than 1e-9.
 // ** Means that you should switch to scientific if there would be 9 zeros after the decimal (the decimal and first zero
 // ** Means that you should switch to scientific if there would be 9 zeros after the decimal (the decimal and first zero
 // count against the 11 character limit), so less than 1e9.
 // count against the 11 character limit), so less than 1e9.
 // *** The way this is written, you can get numbers that are more than 11 characters because the golang Float fmt
 // *** The way this is written, you can get numbers that are more than 11 characters because the golang Float fmt
@@ -363,21 +403,7 @@ func (c *Cell) FormattedValue() (string, error) {
 	case builtInNumFmt[builtInNumFmtIndex_GENERAL]:
 	case builtInNumFmt[builtInNumFmtIndex_GENERAL]:
 		if c.cellType == CellTypeNumeric {
 		if c.cellType == CellTypeNumeric {
 			// If the cell type is Numeric, format the string the way it should be shown to the user.
 			// If the cell type is Numeric, format the string the way it should be shown to the user.
-			f, err := strconv.ParseFloat(c.Value, 64)
-			if err != nil {
-				return c.Value, err
-			}
-			// When using General format, numbers that are less than 1e-9 (0.000000001) and greater than or equal to
-			// 1e11 (100,000,000,000) should be shown in scientific notation.
-			if f < minNonScientificNumber || f >= maxNonScientificNumber {
-				return strconv.FormatFloat(f, 'E', -1, 64), nil
-			}
-			// This format (fmt="f", prec=-1) will prevent padding with zeros and will never switch to scientific notation.
-			// However, it will show more than 11 characters for very precise numbers, and this cannot be changed.
-			// You could also use fmt="g", prec=11, which doesn't pad with zeros and allows the correct precision,
-			// but it will use scientific notation on numbers less than 1e-4. That value is hardcoded and cannot be
-			// configured or disabled.
-			return strconv.FormatFloat(f, 'f', -1, 64), nil
+			return c.GeneralNumeric()
 		}
 		}
 		return c.Value, nil
 		return c.Value, nil
 	case builtInNumFmt[builtInNumFmtIndex_STRING]:
 	case builtInNumFmt[builtInNumFmtIndex_STRING]:

+ 70 - 17
cell_test.go

@@ -124,36 +124,84 @@ func (l *CellSuite) TestGeneralNumberHandling(c *C) {
 	// 1.1 will get you the same, with a stored value of 1.1000000000000001.
 	// 1.1 will get you the same, with a stored value of 1.1000000000000001.
 	// Also, numbers greater than 1e11 and less than 1e-9 wil be shown as scientific notation.
 	// Also, numbers greater than 1e11 and less than 1e-9 wil be shown as scientific notation.
 	testCases := []struct {
 	testCases := []struct {
-		value  string
-		output string
+		value                string
+		formattedValueOutput string
+		noExpValueOutput     string
 	}{
 	}{
 		{
 		{
-			value:  "18.989999999999998",
-			output: "18.99",
+			value:                "18.989999999999998",
+			formattedValueOutput: "18.99",
+			noExpValueOutput:     "18.99",
 		},
 		},
 		{
 		{
-			value:  "1.1000000000000001",
-			output: "1.1",
+			value:                "1.1000000000000001",
+			formattedValueOutput: "1.1",
+			noExpValueOutput:     "1.1",
 		},
 		},
 		{
 		{
-			value:  "0.0000000000000001",
-			output: "1E-16",
+			value:                "0.0000000000000001",
+			formattedValueOutput: "1E-16",
+			noExpValueOutput:     "0.0000000000000001",
 		},
 		},
 		{
 		{
-			value:  "0.000000000000008",
-			output: "8E-15",
+			value:                "0.000000000000008",
+			formattedValueOutput: "8E-15",
+			noExpValueOutput:     "0.000000000000008",
 		},
 		},
 		{
 		{
-			value:  "1000000000000000000",
-			output: "1E+18",
+			value:                "1000000000000000000",
+			formattedValueOutput: "1E+18",
+			noExpValueOutput:     "1000000000000000000",
 		},
 		},
 		{
 		{
-			value:  "1230000000000000000",
-			output: "1.23E+18",
+			value:                "1230000000000000000",
+			formattedValueOutput: "1.23E+18",
+			noExpValueOutput:     "1230000000000000000",
 		},
 		},
 		{
 		{
-			value:  "12345678",
-			output: "12345678",
+			value:                "12345678",
+			formattedValueOutput: "12345678",
+			noExpValueOutput:     "12345678",
+		},
+		{
+			value:                "0",
+			formattedValueOutput: "0",
+			noExpValueOutput:     "0",
+		},
+		{
+			value:                "-18.989999999999998",
+			formattedValueOutput: "-18.99",
+			noExpValueOutput:     "-18.99",
+		},
+		{
+			value:                "-1.1000000000000001",
+			formattedValueOutput: "-1.1",
+			noExpValueOutput:     "-1.1",
+		},
+		{
+			value:                "-0.0000000000000001",
+			formattedValueOutput: "-1E-16",
+			noExpValueOutput:     "-0.0000000000000001",
+		},
+		{
+			value:                "-0.000000000000008",
+			formattedValueOutput: "-8E-15",
+			noExpValueOutput:     "-0.000000000000008",
+		},
+		{
+			value:                "-1000000000000000000",
+			formattedValueOutput: "-1E+18",
+			noExpValueOutput:     "-1000000000000000000",
+		},
+		{
+			value:                "-1230000000000000000",
+			formattedValueOutput: "-1.23E+18",
+			noExpValueOutput:     "-1230000000000000000",
+		},
+		{
+			value:                "-12345678",
+			formattedValueOutput: "-12345678",
+			noExpValueOutput:     "-12345678",
 		},
 		},
 	}
 	}
 	for _, testCase := range testCases {
 	for _, testCase := range testCases {
@@ -166,7 +214,12 @@ func (l *CellSuite) TestGeneralNumberHandling(c *C) {
 		if err != nil {
 		if err != nil {
 			c.Fatal(err)
 			c.Fatal(err)
 		}
 		}
-		c.Assert(val, Equals, testCase.output)
+		c.Assert(val, Equals, testCase.formattedValueOutput)
+		val, err = cell.GeneralNumericWithoutScientific()
+		if err != nil {
+			c.Fatal(err)
+		}
+		c.Assert(val, Equals, testCase.noExpValueOutput)
 	}
 	}
 }
 }