Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions excelize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -779,10 +779,10 @@ func TestSetCellStyleNumberFormat(t *testing.T) {
idxTbl := []int{0, 1, 2, 3, 4, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}
value := []string{"37947.7500001", "-37947.7500001", "0.007", "2.1", "String"}
expected := [][]string{
{"37947.75", "37948", "37947.75", "37,948", "37,947.75", "3794775%", "3794775.00%", "3.79E+04", "37947 3/4", "37947 3/4", "11-22-03", "22-Nov-03", "22-Nov", "Nov-03", "6:00 PM", "6:00:00 PM", "18:00", "18:00:00", "11/22/03 18:00", "37,948 ", "37,948 ", "37,947.75 ", "37,947.75 ", " 37,948 ", " $37,948 ", " 37,947.75 ", " $37,947.75 ", "00:00", "910746:00:00", "00:00.0", "37947.7500001", "37947.7500001"},
{"-37947.75", "-37948", "-37947.75", "-37,948", "-37,947.75", "-3794775%", "-3794775.00%", "-3.79E+04", "-37947 3/4", "-37947 3/4", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "(37,948)", "(37,948)", "(37,947.75)", "(37,947.75)", " (37,948)", " $(37,948)", " (37,947.75)", " $(37,947.75)", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001"},
{"0.007", "0", "0.01", "0", "0.01", "1%", "0.70%", "7.00E-03", "0 ", "0 ", "01-00-00", "0-Jan-00", "0-Jan", "Jan-00", "12:10 AM", "12:10:05 AM", "00:10", "00:10:05", "1/0/00 00:10", "0 ", "0 ", "0.01 ", "0.01 ", " 0 ", " $0 ", " 0.01 ", " $0.01 ", "10:05", "0:10:05", "10:04.8", "0.007", "0.007"},
{"2.1", "2", "2.10", "2", "2.10", "210%", "210.00%", "2.10E+00", "2 1/9", "2 1/10", "01-02-00", "2-Jan-00", "2-Jan", "Jan-00", "2:24 AM", "2:24:00 AM", "02:24", "02:24:00", "1/2/00 02:24", "2 ", "2 ", "2.10 ", "2.10 ", " 2 ", " $2 ", " 2.10 ", " $2.10 ", "24:00", "50:24:00", "24:00.0", "2.1", "2.1"},
{"37947.75", "37948", "37947.75", "37,948", "37,947.75", "3794775%", "3794775.00%", "3.79E+04", "37947 3/4", "37947 3/4 ", "11-22-03", "22-Nov-03", "22-Nov", "Nov-03", "6:00 PM", "6:00:00 PM", "18:00", "18:00:00", "11/22/03 18:00", "37,948 ", "37,948 ", "37,947.75 ", "37,947.75 ", " 37,948 ", " $37,948 ", " 37,947.75 ", " $37,947.75 ", "00:00", "910746:00:00", "00:00.0", "37947.7500001", "37947.7500001"},
{"-37947.75", "-37948", "-37947.75", "-37,948", "-37,947.75", "-3794775%", "-3794775.00%", "-3.79E+04", "-37947 3/4", "-37947 3/4 ", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "(37,948)", "(37,948)", "(37,947.75)", "(37,947.75)", " (37,948)", " $(37,948)", " (37,947.75)", " $(37,947.75)", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001"},
{"0.007", "0", "0.01", "0", "0.01", "1%", "0.70%", "7.00E-03", "0 ", "0 ", "01-00-00", "0-Jan-00", "0-Jan", "Jan-00", "12:10 AM", "12:10:05 AM", "00:10", "00:10:05", "1/0/00 00:10", "0 ", "0 ", "0.01 ", "0.01 ", " 0 ", " $0 ", " 0.01 ", " $0.01 ", "10:05", "0:10:05", "10:04.8", "0.007", "0.007"},
{"2.1", "2", "2.10", "2", "2.10", "210%", "210.00%", "2.10E+00", "2 1/9", "2 1/10", "01-02-00", "2-Jan-00", "2-Jan", "Jan-00", "2:24 AM", "2:24:00 AM", "02:24", "02:24:00", "1/2/00 02:24", "2 ", "2 ", "2.10 ", "2.10 ", " 2 ", " $2 ", " 2.10 ", " $2.10 ", "24:00", "50:24:00", "24:00.0", "2.1", "2.1"},
{"String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", " String ", " String ", " String ", " String ", "String", "String", "String", "String", "String"},
}

Expand Down
66 changes: 50 additions & 16 deletions numfmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -5351,9 +5351,8 @@ func (nf *numberFormat) getNumberFmtConf() {
}
}

// handleDigitsLiteral apply hash and zero place holder tokens for the number
// literal.
func handleDigitsLiteral(text string, tokenValueLen, intPartLen, hashZeroPartLen int) (int, string) {
// handleDigitsLiteral apply digit placeholder tokens for the number literal.
func handleDigitsLiteral(text string, tokenValueLen, intPartLen, hashZeroPartLen int, fill bool) (int, string) {
var result string
l := tokenValueLen
if intPartLen == 0 && len(text) > hashZeroPartLen {
Expand All @@ -5366,6 +5365,8 @@ func handleDigitsLiteral(text string, tokenValueLen, intPartLen, hashZeroPartLen
j := i + intPartLen
if 0 <= j && j < len([]rune(text)) {
result += string([]rune(text)[j])
} else if fill {
result += " "
}
}
return l, result
Expand All @@ -5382,21 +5383,44 @@ func (nf *numberFormat) printNumberLiteral(text string) string {
if nf.usePositive {
result += "-"
}
for _, token := range nf.section[nf.sectionIdx].Items {
if token.TType == nfp.TokenTypeHashPlaceHolder || token.TType == nfp.TokenTypeZeroPlaceHolder {
lastNonFractionPartDigital := math.MaxInt
appearedFraction := false
numeratorPlaceHolder := 0
for idx := len(nf.section[nf.sectionIdx].Items) - 1; idx >= 0; idx-- {
token := nf.section[nf.sectionIdx].Items[idx]
if token.TType == nfp.TokenTypeFraction {
appearedFraction = true
} else if appearedFraction && (token.TType == nfp.TokenTypeHashPlaceHolder || token.TType == nfp.TokenTypeDigitalPlaceHolder) {
lastNonFractionPartDigital = idx - 1 // current idx belongs to the fraction part (numerator)
break
}
}
for idx, token := range nf.section[nf.sectionIdx].Items {
switch token.TType {
case nfp.TokenTypeHashPlaceHolder, nfp.TokenTypeZeroPlaceHolder:
hashZeroPartLen += len(token.TValue)
case nfp.TokenTypeDigitalPlaceHolder:
if lastNonFractionPartDigital >= 0 && idx < lastNonFractionPartDigital {
hashZeroPartLen += len(token.TValue)
}
}
}
for _, token := range nf.section[nf.sectionIdx].Items {
for idx, token := range nf.section[nf.sectionIdx].Items {
if token.TType == nfp.TokenTypeCurrencyLanguage {
_, _ = nf.currencyLanguageHandler(token)
result += nf.currencyString
}
if token.TType == nfp.TokenTypeLiteral {
result += token.TValue
}
if token.TType == nfp.TokenTypeHashPlaceHolder || token.TType == nfp.TokenTypeZeroPlaceHolder || token.TType == nfp.TokenTypeDigitalPlaceHolder {
digits, str := handleDigitsLiteral(text, len(token.TValue), intPartLen, hashZeroPartLen)
if token.TType == nfp.TokenTypeDigitalPlaceHolder && idx > lastNonFractionPartDigital {
// If it is a fraction part, it will be filled in by the fractalHandler()
// If not, fill placeHolder in directly here
if !useFraction { // numerator part
numeratorPlaceHolder = len(token.TValue)
}
} else if token.TType == nfp.TokenTypeHashPlaceHolder || token.TType == nfp.TokenTypeZeroPlaceHolder || token.TType == nfp.TokenTypeDigitalPlaceHolder {
digits, str := handleDigitsLiteral(text, len(token.TValue), intPartLen, hashZeroPartLen, token.TType == nfp.TokenTypeDigitalPlaceHolder)
intPartLen += digits
result += str
}
Expand All @@ -5405,27 +5429,37 @@ func (nf *numberFormat) printNumberLiteral(text string) string {
frac, useFraction = math.Abs(frac), true
}
if useFraction {
result += nf.fractionHandler(frac, token)
result += nf.fractionHandler(frac, token, numeratorPlaceHolder)
}
}
return nf.printSwitchArgument(result)
}

// fractionHandler handling fraction number format expression for positive and
// negative numeric.
func (nf *numberFormat) fractionHandler(frac float64, token nfp.Token) string {
func (nf *numberFormat) fractionHandler(frac float64, token nfp.Token, numeratorPlaceHolder int) string {
var rat, result string
var lastRat *big.Rat
if token.TType == nfp.TokenTypeDigitalPlaceHolder {
fracPlaceHolder := len(token.TValue)
for i := 0; i < 5000; i++ {
if r := newRat(frac, int64(i), 0); len(r.Denom().String()) <= fracPlaceHolder {
if rat = r.String(); strings.HasPrefix(rat, "0/") {
rat = strings.Repeat(" ", 3)
}
denominatorPlaceHolder := len(token.TValue)
for i := range 5000 {
if r := newRat(frac, int64(i), 0); len(r.Denom().String()) <= denominatorPlaceHolder {
lastRat = r // record the last valid ratio, and delay conversion to string
continue
}
break
}
if lastRat != nil {
if lastRat.Num().Int64() == 0 {
rat = strings.Repeat(" ", numeratorPlaceHolder+denominatorPlaceHolder+1)
} else {
num := lastRat.Num().String()
den := lastRat.Denom().String()
numeratorPlaceHolder = max(numeratorPlaceHolder-len(num), 0)
denominatorPlaceHolder = max(denominatorPlaceHolder-len(den), 0)
rat = fmt.Sprintf("%s%s/%s%s", strings.Repeat(" ", numeratorPlaceHolder), num, den, strings.Repeat(" ", denominatorPlaceHolder))
}
}
result += rat
}
if token.TType == nfp.TokenTypeDenominator {
Expand Down
37 changes: 36 additions & 1 deletion numfmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4255,7 +4255,7 @@ func TestNumFmt(t *testing.T) {
{"1.234E-16", "0.000000000000000000%%%%", "0.000000000000012340%"},
{"-123.4567", "# ?/?", "-123 1/2"},
{"123.4567", "# ??/??", "123 37/81"},
{"123.4567", "#\\ ???/???", "123 58/127"},
{"123.4567", "#\\ ???/???", "123 58/127"},
{"123.4567", "#\\ ?/2", "123 1/2"},
{"123.4567", "#\\ ?/4", "123 2/4"},
{"123.4567", "#\\ ?/8", "123 4/8"},
Expand All @@ -4269,6 +4269,18 @@ func TestNumFmt(t *testing.T) {
{"1234.5678", "0.0xxx00", "1234.5xxx68"},
{"80145.899999999994", "[$¥-8004]\" \"#\" \"####\"\"", "¥ 8 0146"},
{"1", "?", "1"},
{"1", "???", " 1"},
{"0", "# ?/?", "0 "},
{"0", "# ??/??", "0 "},
{"0", "# ??/???", "0 "},
{"31.69", "?#???", " 32"},
{"314159.26535", "#,### ??/??", "314,159 13/49"},
{"314159.26535", "# ??? ????/??", "314 159 13/49"},
{"-3.14159265358979323", "# ?/?", "-3 1/7"},
{"-3.14159265358979323", "# ??/??", "-3 1/7 "},
{"-3.14159265358979323", "# ???/???", "-3 16/113"},
{"5.81999", `???? ????`, " 6"},
{"4.6", `# #### ####`, " 5"},
// Unsupported number format
{"37947.7500001", "0.00000000E+000", "37947.7500001"},
{"123", "[DBNum4][$-804]yyyy\"年\"m\"月\";@", "123"},
Expand Down Expand Up @@ -4320,3 +4332,26 @@ func TestNumFmt(t *testing.T) {
assert.Equal(t, ErrUnsupportedNumberFormat, err)
assert.False(t, changeNumFmtCode)
}

func BenchmarkNumFmtPlaceHolder(b *testing.B) {
items := [][]string{
{"1", "?", "1"},
{"1", "???", " 1"},
{"0", "# ?/?", "0 "},
{"0", "# ??/??", "0 "},
{"0", "# ??/???", "0 "},
{"31.69", "?#???", " 32"},
{"314159.26535", "#,### ??/??", "314,159 13/49"},
{"314159.26535", "# ??? ????/??", "314 159 13/49"},
{"-3.14159265358979323", "# ?/?", "-3 1/7"},
{"-3.14159265358979323", "# ??/??", "-3 1/7 "},
{"123.4567", "#\\ ?/10", "123 5/10"},
}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, item := range items {
result := format(item[0], item[1], false, CellTypeNumber, nil)
_ = result
}
}
}