forked from p30928647/excelize
This closes #660, supports currency string, and switches argument for the number format code
- Support round millisecond for the date time - Update built-in number formats mapping - Update unit tests - Upgrade dependencies package
This commit is contained in:
parent
7c221cf295
commit
bbdb83abf0
|
@ -407,7 +407,7 @@ func TestInsertCols(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
sheet1 := f.GetSheetName(0)
|
sheet1 := f.GetSheetName(0)
|
||||||
|
|
||||||
fillCells(f, sheet1, 10, 10)
|
assert.NoError(t, fillCells(f, sheet1, 10, 10))
|
||||||
|
|
||||||
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
||||||
assert.NoError(t, f.MergeCell(sheet1, "A1", "C3"))
|
assert.NoError(t, f.MergeCell(sheet1, "A1", "C3"))
|
||||||
|
@ -430,7 +430,7 @@ func TestRemoveCol(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
sheet1 := f.GetSheetName(0)
|
sheet1 := f.GetSheetName(0)
|
||||||
|
|
||||||
fillCells(f, sheet1, 10, 15)
|
assert.NoError(t, fillCells(f, sheet1, 10, 15))
|
||||||
|
|
||||||
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
||||||
assert.NoError(t, f.SetCellHyperLink(sheet1, "C5", "https://github.com", "External"))
|
assert.NoError(t, f.SetCellHyperLink(sheet1, "C5", "https://github.com", "External"))
|
||||||
|
|
|
@ -750,10 +750,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}
|
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"}
|
value := []string{"37947.7500001", "-37947.7500001", "0.007", "2.1", "String"}
|
||||||
expected := [][]string{
|
expected := [][]string{
|
||||||
{"37947.7500001", "37948", "37947.75", "37,948", "37,947.75", "3794775%", "3794775.00%", "3.79E+04", "37947.7500001", "37947.7500001", "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 ", "37947.7500001", "37947.7500001", "37947.7500001", "37947.7500001", "00:00", "910746:00:00", "0000.0", "37947.7500001", "37947.7500001"},
|
{"37947.7500001", "37948", "37947.75", "37,948", "37,947.75", "3794775%", "3794775.00%", "3.79E+04", "37947.7500001", "37947.7500001", "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 ", "37947.7500001", "37947.7500001", "37947.7500001", "37947.7500001", "00:00", "910746:00:00", "00:00.0", "37947.7500001", "37947.7500001"},
|
||||||
{"-37947.7500001", "-37948", "-37947.75", "-37,948", "-37,947.75", "-3794775%", "-3794775.00%", "-3.79E+04", "-37947.7500001", "-37947.7500001", "-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)", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001"},
|
{"-37947.7500001", "-37948", "-37947.75", "-37,948", "-37,947.75", "-3794775%", "-3794775.00%", "-3.79E+04", "-37947.7500001", "-37947.7500001", "-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)", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-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.007", "0.007", "12-30-99", "30-Dec-99", "30-Dec", "Dec-99", "0:10 am", "0:10:04 am", "00:10", "00:10:04", "12/30/99 00:10", "0 ", "0 ", "0.01 ", "0.01 ", "0.007", "0.007", "0.007", "0.007", "10:04", "0:10:04", "1004.0", "0.007", "0.007"},
|
{"0.007", "0", "0.01", "0", "0.01", "1%", "0.70%", "7.00E-03", "0.007", "0.007", "12-30-99", "30-Dec-99", "30-Dec", "Dec-99", "0:10 AM", "0:10:05 AM", "00:10", "00:10:05", "12/30/99 00:10", "0 ", "0 ", "0.01 ", "0.01 ", "0.007", "0.007", "0.007", "0.007", "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", "2.1", "01-01-00", "1-Jan-00", "1-Jan", "Jan-00", "2:24 am", "2:24:00 am", "02:24", "02:24:00", "1/1/00 02:24", "2 ", "2 ", "2.10 ", "2.10 ", "2.1", "2.1", "2.1", "2.1", "24:00", "50:24:00", "2400.0", "2.1", "2.1"},
|
{"2.1", "2", "2.10", "2", "2.10", "210%", "210.00%", "2.10E+00", "2.1", "2.1", "01-01-00", "1-Jan-00", "1-Jan", "Jan-00", "2:24 AM", "2:24:00 AM", "02:24", "02:24:00", "1/1/00 02:24", "2 ", "2 ", "2.10 ", "2.10 ", "2.1", "2.1", "2.1", "2.1", "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"},
|
{"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"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -7,7 +7,7 @@ require (
|
||||||
github.com/richardlehane/mscfb v1.0.4
|
github.com/richardlehane/mscfb v1.0.4
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9
|
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9
|
||||||
github.com/xuri/nfp v0.0.0-20230428090735-b50b0f0358f4
|
github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83
|
||||||
golang.org/x/crypto v0.8.0
|
golang.org/x/crypto v0.8.0
|
||||||
golang.org/x/image v0.5.0
|
golang.org/x/image v0.5.0
|
||||||
golang.org/x/net v0.9.0
|
golang.org/x/net v0.9.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -17,8 +17,8 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9 h1:ge5g8vsTQclA5lXDi+PuiAFw5GMIlMHOB/5e1hsf96E=
|
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9 h1:ge5g8vsTQclA5lXDi+PuiAFw5GMIlMHOB/5e1hsf96E=
|
||||||
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||||
github.com/xuri/nfp v0.0.0-20230428090735-b50b0f0358f4 h1:YoU/1S7L25dvNepEir3Fg2aU9iGmDyE4gWKoEswWXts=
|
github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83 h1:xVwnvkzzi+OiwhIkWOXvh1skFI6bagk8OvGuazM80Rw=
|
||||||
github.com/xuri/nfp v0.0.0-20230428090735-b50b0f0358f4/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
|
152
numfmt.go
152
numfmt.go
|
@ -36,9 +36,10 @@ type numberFormat struct {
|
||||||
section []nfp.Section
|
section []nfp.Section
|
||||||
t time.Time
|
t time.Time
|
||||||
sectionIdx int
|
sectionIdx int
|
||||||
date1904, isNumeric, hours, seconds bool
|
date1904, isNumeric, hours, seconds, useMillisecond bool
|
||||||
number float64
|
number float64
|
||||||
ap, localCode, result, value, valueSectionType string
|
ap, localCode, result, value, valueSectionType string
|
||||||
|
switchArgument, currencyString string
|
||||||
fracHolder, fracPadding, intHolder, intPadding, expBaseLen int
|
fracHolder, fracPadding, intHolder, intPadding, expBaseLen int
|
||||||
percent int
|
percent int
|
||||||
useCommaSep, usePointer, usePositive, useScientificNotation bool
|
useCommaSep, usePointer, usePositive, useScientificNotation bool
|
||||||
|
@ -47,6 +48,7 @@ type numberFormat struct {
|
||||||
var (
|
var (
|
||||||
// supportedTokenTypes list the supported number format token types currently.
|
// supportedTokenTypes list the supported number format token types currently.
|
||||||
supportedTokenTypes = []string{
|
supportedTokenTypes = []string{
|
||||||
|
nfp.TokenSubTypeCurrencyString,
|
||||||
nfp.TokenSubTypeLanguageInfo,
|
nfp.TokenSubTypeLanguageInfo,
|
||||||
nfp.TokenTypeColor,
|
nfp.TokenTypeColor,
|
||||||
nfp.TokenTypeCurrencyLanguage,
|
nfp.TokenTypeCurrencyLanguage,
|
||||||
|
@ -58,23 +60,20 @@ var (
|
||||||
nfp.TokenTypeHashPlaceHolder,
|
nfp.TokenTypeHashPlaceHolder,
|
||||||
nfp.TokenTypeLiteral,
|
nfp.TokenTypeLiteral,
|
||||||
nfp.TokenTypePercent,
|
nfp.TokenTypePercent,
|
||||||
|
nfp.TokenTypeSwitchArgument,
|
||||||
nfp.TokenTypeTextPlaceHolder,
|
nfp.TokenTypeTextPlaceHolder,
|
||||||
nfp.TokenTypeThousandsSeparator,
|
nfp.TokenTypeThousandsSeparator,
|
||||||
nfp.TokenTypeZeroPlaceHolder,
|
nfp.TokenTypeZeroPlaceHolder,
|
||||||
}
|
}
|
||||||
// supportedNumberTokenTypes list the supported number token types.
|
// supportedNumberTokenTypes list the supported number token types.
|
||||||
supportedNumberTokenTypes = []string{
|
supportedNumberTokenTypes = []string{
|
||||||
nfp.TokenTypeColor,
|
nfp.TokenTypeExponential,
|
||||||
nfp.TokenTypeDecimalPoint,
|
|
||||||
nfp.TokenTypeHashPlaceHolder,
|
nfp.TokenTypeHashPlaceHolder,
|
||||||
nfp.TokenTypeLiteral,
|
|
||||||
nfp.TokenTypePercent,
|
nfp.TokenTypePercent,
|
||||||
nfp.TokenTypeThousandsSeparator,
|
|
||||||
nfp.TokenTypeZeroPlaceHolder,
|
nfp.TokenTypeZeroPlaceHolder,
|
||||||
}
|
}
|
||||||
// supportedDateTimeTokenTypes list the supported date and time token types.
|
// supportedDateTimeTokenTypes list the supported date and time token types.
|
||||||
supportedDateTimeTokenTypes = []string{
|
supportedDateTimeTokenTypes = []string{
|
||||||
nfp.TokenTypeCurrencyLanguage,
|
|
||||||
nfp.TokenTypeDateTimes,
|
nfp.TokenTypeDateTimes,
|
||||||
nfp.TokenTypeElapsedDateTimes,
|
nfp.TokenTypeElapsedDateTimes,
|
||||||
}
|
}
|
||||||
|
@ -357,6 +356,30 @@ var (
|
||||||
apFmtYi = "\ua3b8\ua111/\ua06f\ua2d2"
|
apFmtYi = "\ua3b8\ua111/\ua06f\ua2d2"
|
||||||
// apFmtWelsh defined the AM/PM name in the Welsh.
|
// apFmtWelsh defined the AM/PM name in the Welsh.
|
||||||
apFmtWelsh = "yb/yh"
|
apFmtWelsh = "yb/yh"
|
||||||
|
// switchArgumentFunc defined the switch argument printer function
|
||||||
|
switchArgumentFunc = map[string]func(s string) string{
|
||||||
|
"[DBNum1]": func(s string) string {
|
||||||
|
r := strings.NewReplacer(
|
||||||
|
"0", "\u25cb", "1", "\u4e00", "2", "\u4e8c", "3", "\u4e09", "4", "\u56db",
|
||||||
|
"5", "\u4e94", "6", "\u516d", "7", "\u4e03", "8", "\u516b", "9", "\u4e5d",
|
||||||
|
)
|
||||||
|
return r.Replace(s)
|
||||||
|
},
|
||||||
|
"[DBNum2]": func(s string) string {
|
||||||
|
r := strings.NewReplacer(
|
||||||
|
"0", "\u96f6", "1", "\u58f9", "2", "\u8d30", "3", "\u53c1", "4", "\u8086",
|
||||||
|
"5", "\u4f0d", "6", "\u9646", "7", "\u67d2", "8", "\u634c", "9", "\u7396",
|
||||||
|
)
|
||||||
|
return r.Replace(s)
|
||||||
|
},
|
||||||
|
"[DBNum3]": func(s string) string {
|
||||||
|
r := strings.NewReplacer(
|
||||||
|
"0", "\uff10", "1", "\uff11", "2", "\uff12", "3", "\uff13", "4", "\uff14",
|
||||||
|
"5", "\uff15", "6", "\uff16", "7", "\uff17", "8", "\uff18", "9", "\uff19",
|
||||||
|
)
|
||||||
|
return r.Replace(s)
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// prepareNumberic split the number into two before and after parts by a
|
// prepareNumberic split the number into two before and after parts by a
|
||||||
|
@ -431,6 +454,9 @@ func (nf *numberFormat) getNumberFmtConf() {
|
||||||
if token.TType == nfp.TokenTypeDecimalPoint {
|
if token.TType == nfp.TokenTypeDecimalPoint {
|
||||||
nf.usePointer = true
|
nf.usePointer = true
|
||||||
}
|
}
|
||||||
|
if token.TType == nfp.TokenTypeSwitchArgument {
|
||||||
|
nf.switchArgument = token.TValue
|
||||||
|
}
|
||||||
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
||||||
if nf.usePointer {
|
if nf.usePointer {
|
||||||
if nf.useScientificNotation {
|
if nf.useScientificNotation {
|
||||||
|
@ -448,20 +474,34 @@ func (nf *numberFormat) getNumberFmtConf() {
|
||||||
// printNumberLiteral apply literal tokens for the pre-formatted text.
|
// printNumberLiteral apply literal tokens for the pre-formatted text.
|
||||||
func (nf *numberFormat) printNumberLiteral(text string) string {
|
func (nf *numberFormat) printNumberLiteral(text string) string {
|
||||||
var result string
|
var result string
|
||||||
var useZeroPlaceHolder bool
|
var useLiteral, useZeroPlaceHolder bool
|
||||||
if nf.usePositive {
|
if nf.usePositive {
|
||||||
result += "-"
|
result += "-"
|
||||||
}
|
}
|
||||||
for _, token := range nf.section[nf.sectionIdx].Items {
|
for i, token := range nf.section[nf.sectionIdx].Items {
|
||||||
|
if token.TType == nfp.TokenTypeCurrencyLanguage {
|
||||||
|
if err := nf.currencyLanguageHandler(i, token); err != nil {
|
||||||
|
return nf.value
|
||||||
|
}
|
||||||
|
result += nf.currencyString
|
||||||
|
}
|
||||||
if token.TType == nfp.TokenTypeLiteral {
|
if token.TType == nfp.TokenTypeLiteral {
|
||||||
|
if useZeroPlaceHolder {
|
||||||
|
useLiteral = true
|
||||||
|
}
|
||||||
result += token.TValue
|
result += token.TValue
|
||||||
}
|
}
|
||||||
if !useZeroPlaceHolder && token.TType == nfp.TokenTypeZeroPlaceHolder {
|
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
||||||
useZeroPlaceHolder = true
|
if useLiteral && useZeroPlaceHolder {
|
||||||
result += text
|
return nf.value
|
||||||
|
}
|
||||||
|
if !useZeroPlaceHolder {
|
||||||
|
useZeroPlaceHolder = true
|
||||||
|
result += text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return nf.printSwitchArgument(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// printCommaSep format number with thousands separator.
|
// printCommaSep format number with thousands separator.
|
||||||
|
@ -484,6 +524,17 @@ func printCommaSep(text string) string {
|
||||||
return target.String()
|
return target.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printSwitchArgument format number with switch argument.
|
||||||
|
func (nf *numberFormat) printSwitchArgument(text string) string {
|
||||||
|
if nf.switchArgument == "" {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
if fn, ok := switchArgumentFunc[nf.switchArgument]; ok {
|
||||||
|
return fn(text)
|
||||||
|
}
|
||||||
|
return nf.value
|
||||||
|
}
|
||||||
|
|
||||||
// printBigNumber format number which precision great than 15 with fraction
|
// printBigNumber format number which precision great than 15 with fraction
|
||||||
// zero padding and percentage symbol.
|
// zero padding and percentage symbol.
|
||||||
func (nf *numberFormat) printBigNumber(decimal float64, fracLen int) string {
|
func (nf *numberFormat) printBigNumber(decimal float64, fracLen int) string {
|
||||||
|
@ -561,14 +612,14 @@ func (nf *numberFormat) numberHandler() string {
|
||||||
|
|
||||||
// dateTimeHandler handling data and time number format expression for a
|
// dateTimeHandler handling data and time number format expression for a
|
||||||
// positive numeric.
|
// positive numeric.
|
||||||
func (nf *numberFormat) dateTimeHandler() (result string) {
|
func (nf *numberFormat) dateTimeHandler() string {
|
||||||
nf.t, nf.hours, nf.seconds = timeFromExcelTime(nf.number, nf.date1904), false, false
|
nf.t, nf.hours, nf.seconds = timeFromExcelTime(nf.number, nf.date1904), false, false
|
||||||
for i, token := range nf.section[nf.sectionIdx].Items {
|
for i, token := range nf.section[nf.sectionIdx].Items {
|
||||||
if token.TType == nfp.TokenTypeCurrencyLanguage {
|
if token.TType == nfp.TokenTypeCurrencyLanguage {
|
||||||
if err := nf.currencyLanguageHandler(i, token); err != nil {
|
if err := nf.currencyLanguageHandler(i, token); err != nil {
|
||||||
result = nf.value
|
return nf.value
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
nf.result += nf.currencyString
|
||||||
}
|
}
|
||||||
if token.TType == nfp.TokenTypeDateTimes {
|
if token.TType == nfp.TokenTypeDateTimes {
|
||||||
nf.dateTimesHandler(i, token)
|
nf.dateTimesHandler(i, token)
|
||||||
|
@ -583,15 +634,18 @@ func (nf *numberFormat) dateTimeHandler() (result string) {
|
||||||
if token.TType == nfp.TokenTypeDecimalPoint {
|
if token.TType == nfp.TokenTypeDecimalPoint {
|
||||||
nf.result += "."
|
nf.result += "."
|
||||||
}
|
}
|
||||||
|
if token.TType == nfp.TokenTypeSwitchArgument {
|
||||||
|
nf.switchArgument = token.TValue
|
||||||
|
}
|
||||||
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
||||||
zeroHolderLen := len(token.TValue)
|
zeroHolderLen := len(token.TValue)
|
||||||
if zeroHolderLen > 3 {
|
if zeroHolderLen > 3 {
|
||||||
zeroHolderLen = 3
|
zeroHolderLen = 3
|
||||||
}
|
}
|
||||||
nf.result += strings.Repeat("0", zeroHolderLen)
|
nf.result += fmt.Sprintf("%03d", nf.t.Nanosecond()/1e6)[:zeroHolderLen]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nf.result
|
return nf.printSwitchArgument(nf.result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// positiveHandler will be handling positive selection for a number format
|
// positiveHandler will be handling positive selection for a number format
|
||||||
|
@ -609,13 +663,26 @@ func (nf *numberFormat) positiveHandler() string {
|
||||||
if fmtNum || nf.number < 0 {
|
if fmtNum || nf.number < 0 {
|
||||||
return nf.value
|
return nf.value
|
||||||
}
|
}
|
||||||
|
var useDateTimeTokens bool
|
||||||
|
for _, token := range nf.section[nf.sectionIdx].Items {
|
||||||
|
if inStrSlice(supportedDateTimeTokenTypes, token.TType, false) != -1 {
|
||||||
|
if useDateTimeTokens && nf.useMillisecond {
|
||||||
|
return nf.value
|
||||||
|
}
|
||||||
|
useDateTimeTokens = true
|
||||||
|
}
|
||||||
|
if inStrSlice(supportedNumberTokenTypes, token.TType, false) != -1 {
|
||||||
|
if token.TType == nfp.TokenTypeZeroPlaceHolder {
|
||||||
|
nf.useMillisecond = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nf.value
|
||||||
|
}
|
||||||
|
}
|
||||||
return nf.dateTimeHandler()
|
return nf.dateTimeHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fmtNum {
|
return nf.numberHandler()
|
||||||
return nf.numberHandler()
|
|
||||||
}
|
|
||||||
return nf.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// currencyLanguageHandler will be handling currency and language types tokens
|
// currencyLanguageHandler will be handling currency and language types tokens
|
||||||
|
@ -626,11 +693,16 @@ func (nf *numberFormat) currencyLanguageHandler(i int, token nfp.Token) (err err
|
||||||
err = ErrUnsupportedNumberFormat
|
err = ErrUnsupportedNumberFormat
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, ok := supportedLanguageInfo[strings.ToUpper(part.Token.TValue)]; !ok {
|
if part.Token.TType == nfp.TokenSubTypeLanguageInfo {
|
||||||
err = ErrUnsupportedNumberFormat
|
if _, ok := supportedLanguageInfo[strings.ToUpper(part.Token.TValue)]; !ok {
|
||||||
return
|
err = ErrUnsupportedNumberFormat
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nf.localCode = strings.ToUpper(part.Token.TValue)
|
||||||
|
}
|
||||||
|
if part.Token.TType == nfp.TokenSubTypeCurrencyString {
|
||||||
|
nf.currencyString = part.Token.TValue
|
||||||
}
|
}
|
||||||
nf.localCode = strings.ToUpper(part.Token.TValue)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1039,17 +1111,17 @@ func (nf *numberFormat) minutesHandler(token nfp.Token) {
|
||||||
// secondsHandler will be handling seconds in the date and times types tokens
|
// secondsHandler will be handling seconds in the date and times types tokens
|
||||||
// for a number format expression.
|
// for a number format expression.
|
||||||
func (nf *numberFormat) secondsHandler(token nfp.Token) {
|
func (nf *numberFormat) secondsHandler(token nfp.Token) {
|
||||||
nf.seconds = strings.Contains(strings.ToUpper(token.TValue), "S")
|
if nf.seconds = strings.Contains(strings.ToUpper(token.TValue), "S"); !nf.seconds {
|
||||||
if nf.seconds {
|
return
|
||||||
switch len(token.TValue) {
|
|
||||||
case 1:
|
|
||||||
nf.result += strconv.Itoa(nf.t.Second())
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
nf.result += fmt.Sprintf("%02d", nf.t.Second())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if !nf.useMillisecond {
|
||||||
|
nf.t = nf.t.Add(time.Duration(math.Round(float64(nf.t.Nanosecond())/1e9)) * time.Second)
|
||||||
|
}
|
||||||
|
if len(token.TValue) == 1 {
|
||||||
|
nf.result += strconv.Itoa(nf.t.Second())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nf.result += fmt.Sprintf("%02d", nf.t.Second())
|
||||||
}
|
}
|
||||||
|
|
||||||
// elapsedDateTimesHandler will be handling elapsed date and times types tokens
|
// elapsedDateTimesHandler will be handling elapsed date and times types tokens
|
||||||
|
@ -1114,23 +1186,15 @@ func (nf *numberFormat) secondsNext(i int) bool {
|
||||||
// negativeHandler will be handling negative selection for a number format
|
// negativeHandler will be handling negative selection for a number format
|
||||||
// expression.
|
// expression.
|
||||||
func (nf *numberFormat) negativeHandler() (result string) {
|
func (nf *numberFormat) negativeHandler() (result string) {
|
||||||
fmtNum := true
|
|
||||||
for _, token := range nf.section[nf.sectionIdx].Items {
|
for _, token := range nf.section[nf.sectionIdx].Items {
|
||||||
if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral {
|
if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral {
|
||||||
return nf.value
|
return nf.value
|
||||||
}
|
}
|
||||||
if inStrSlice(supportedNumberTokenTypes, token.TType, true) != -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if inStrSlice(supportedDateTimeTokenTypes, token.TType, true) != -1 {
|
if inStrSlice(supportedDateTimeTokenTypes, token.TType, true) != -1 {
|
||||||
return nf.value
|
return nf.value
|
||||||
}
|
}
|
||||||
fmtNum = false
|
|
||||||
}
|
}
|
||||||
if fmtNum {
|
return nf.numberHandler()
|
||||||
return nf.numberHandler()
|
|
||||||
}
|
|
||||||
return nf.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroHandler will be handling zero selection for a number format expression.
|
// zeroHandler will be handling zero selection for a number format expression.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/xuri/nfp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNumFmt(t *testing.T) {
|
func TestNumFmt(t *testing.T) {
|
||||||
|
@ -67,7 +68,7 @@ func TestNumFmt(t *testing.T) {
|
||||||
{"43528", "[$-409]MM/DD/YYYY", "03/04/2019"},
|
{"43528", "[$-409]MM/DD/YYYY", "03/04/2019"},
|
||||||
{"43528", "[$-409]MM/DD/YYYY am/pm", "03/04/2019 AM"},
|
{"43528", "[$-409]MM/DD/YYYY am/pm", "03/04/2019 AM"},
|
||||||
{"43528", "[$-111]MM/DD/YYYY", "43528"},
|
{"43528", "[$-111]MM/DD/YYYY", "43528"},
|
||||||
{"43528", "[$US-409]MM/DD/YYYY", "43528"},
|
{"43528", "[$US-409]MM/DD/YYYY", "US03/04/2019"},
|
||||||
{"43543.586539351854", "AM/PM h h:mm", "PM 14 2:04"},
|
{"43543.586539351854", "AM/PM h h:mm", "PM 14 2:04"},
|
||||||
{"text", "AM/PM h h:mm", "text"},
|
{"text", "AM/PM h h:mm", "text"},
|
||||||
{"44562.189571759256", "[$-36]mmm dd yyyy h:mm AM/PM", "Jan. 01 2022 4:32 vm."},
|
{"44562.189571759256", "[$-36]mmm dd yyyy h:mm AM/PM", "Jan. 01 2022 4:32 vm."},
|
||||||
|
@ -1017,6 +1018,18 @@ func TestNumFmt(t *testing.T) {
|
||||||
{"-1234.5678", "0.00;-0.00", "-1234.57"},
|
{"-1234.5678", "0.00;-0.00", "-1234.57"},
|
||||||
{"-1234.5678", "0.00%%", "-12345678.00%%"},
|
{"-1234.5678", "0.00%%", "-12345678.00%%"},
|
||||||
{"2.1", "mmss.0000", "2400.000"},
|
{"2.1", "mmss.0000", "2400.000"},
|
||||||
|
{"0.007", "[h]:mm:ss.0", "0:10:04.8"},
|
||||||
|
{"0.007", "[h]:mm:ss.00", "0:10:04.80"},
|
||||||
|
{"0.007", "[h]:mm:ss.000", "0:10:04.800"},
|
||||||
|
{"0.007", "[h]:mm:ss.0000", "0:10:04.800"},
|
||||||
|
{"123", "[h]:mm,:ss.0", "2952:00,:00.0"},
|
||||||
|
{"123", "yy-.dd", "00-.02"},
|
||||||
|
{"123", "[DBNum1][$-804]yyyy\"年\"m\"月\";@", "\u4e00\u4e5d\u25cb\u25cb\u5e74\u4e94\u6708"},
|
||||||
|
{"123", "[DBNum2][$-804]yyyy\"年\"m\"月\";@", "\u58f9\u7396\u96f6\u96f6\u5e74\u4f0d\u6708"},
|
||||||
|
{"123", "[DBNum3][$-804]yyyy\"年\"m\"月\";@", "\uff11\uff19\uff10\uff10\u5e74\uff15\u6708"},
|
||||||
|
{"1234567890", "[DBNum1][$-804]0.00", "\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u25cb.\u25cb\u25cb"},
|
||||||
|
{"1234567890", "[DBNum2][$-804]0.00", "\u58f9\u8d30\u53c1\u8086\u4f0d\u9646\u67d2\u634c\u7396\u96f6.\u96f6\u96f6"},
|
||||||
|
{"1234567890", "[DBNum3][$-804]0.00", "\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19\uff10.\uff10\uff10"},
|
||||||
{"1234.5678", "0.00###", "1234.5678"},
|
{"1234.5678", "0.00###", "1234.5678"},
|
||||||
{"1234.5678", "00000.00###", "01234.5678"},
|
{"1234.5678", "00000.00###", "01234.5678"},
|
||||||
{"-1234.5678", "00000.00###;;", ""},
|
{"-1234.5678", "00000.00###;;", ""},
|
||||||
|
@ -1029,14 +1042,23 @@ func TestNumFmt(t *testing.T) {
|
||||||
{"1.234E-16", "0.000000000000000000", "0.000000000000000123"},
|
{"1.234E-16", "0.000000000000000000", "0.000000000000000123"},
|
||||||
{"1.234E-16", "0.000000000000000000%", "0.000000000000012340%"},
|
{"1.234E-16", "0.000000000000000000%", "0.000000000000012340%"},
|
||||||
{"1.234E-16", "0.000000000000000000%%%%", "0.000000000000012340%"},
|
{"1.234E-16", "0.000000000000000000%%%%", "0.000000000000012340%"},
|
||||||
|
{"1234.5678", "[$$-409]#,##0.00", "$1,234.57"},
|
||||||
// Unsupported number format
|
// Unsupported number format
|
||||||
{"37947.7500001", "0.00000000E+000", "37947.7500001"},
|
{"37947.7500001", "0.00000000E+000", "37947.7500001"},
|
||||||
|
{"123", "[$kr.-46F]#,##0.00", "123"},
|
||||||
|
{"123", "[$kr.-46F]MM/DD/YYYY", "123"},
|
||||||
|
{"123", "[DBNum4][$-804]yyyy\"年\"m\"月\";@", "123"},
|
||||||
// Invalid number format
|
// Invalid number format
|
||||||
{"123", "x0.00s", "123"},
|
{"123", "x0.00s", "123"},
|
||||||
|
{"123", "[h]:m00m:ss", "123"},
|
||||||
|
{"123", "yy-00dd", "123"},
|
||||||
|
{"123", "yy-##dd", "123"},
|
||||||
|
{"123", "xx[h]:mm,:ss.0xx", "xx2952:00,:00.0xx"},
|
||||||
{"-123", "x0.00s", "-123"},
|
{"-123", "x0.00s", "-123"},
|
||||||
{"-1234.5678", ";E+;", "-1234.5678"},
|
{"-1234.5678", ";E+;", "-1234.5678"},
|
||||||
{"1234.5678", "E+;", "1234.5678"},
|
{"1234.5678", "E+;", "1234.5678"},
|
||||||
{"1234.5678", "00000.00###s", "1234.5678"},
|
{"1234.5678", "00000.00###s", "1234.5678"},
|
||||||
|
{"1234.5678", "0.0xxx00", "1234.5678"},
|
||||||
{"-1234.5678", "00000.00###;s;", "-1234.5678"},
|
{"-1234.5678", "00000.00###;s;", "-1234.5678"},
|
||||||
} {
|
} {
|
||||||
result := format(item[0], item[1], false, CellTypeNumber)
|
result := format(item[0], item[1], false, CellTypeNumber)
|
||||||
|
@ -1055,4 +1077,6 @@ func TestNumFmt(t *testing.T) {
|
||||||
assert.Equal(t, item[2], result, item)
|
assert.Equal(t, item[2], result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nf := numberFormat{}
|
||||||
|
assert.Equal(t, ErrUnsupportedNumberFormat, nf.currencyLanguageHandler(0, nfp.Token{Parts: []nfp.Part{{}}}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ func TestRemoveRow(t *testing.T) {
|
||||||
colCount = 10
|
colCount = 10
|
||||||
rowCount = 10
|
rowCount = 10
|
||||||
)
|
)
|
||||||
fillCells(f, sheet1, colCount, rowCount)
|
assert.NoError(t, fillCells(f, sheet1, colCount, rowCount))
|
||||||
|
|
||||||
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ func TestInsertRows(t *testing.T) {
|
||||||
colCount = 10
|
colCount = 10
|
||||||
rowCount = 10
|
rowCount = 10
|
||||||
)
|
)
|
||||||
fillCells(f, sheet1, colCount, rowCount)
|
assert.NoError(t, fillCells(f, sheet1, colCount, rowCount))
|
||||||
|
|
||||||
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ var builtInNumFmt = map[int]string{
|
||||||
15: "d-mmm-yy",
|
15: "d-mmm-yy",
|
||||||
16: "d-mmm",
|
16: "d-mmm",
|
||||||
17: "mmm-yy",
|
17: "mmm-yy",
|
||||||
18: "h:mm am/pm",
|
18: "h:mm AM/PM",
|
||||||
19: "h:mm:ss am/pm",
|
19: "h:mm:ss AM/PM",
|
||||||
20: "hh:mm",
|
20: "hh:mm",
|
||||||
21: "hh:mm:ss",
|
21: "hh:mm:ss",
|
||||||
22: "m/d/yy hh:mm",
|
22: "m/d/yy hh:mm",
|
||||||
|
@ -56,7 +56,7 @@ var builtInNumFmt = map[int]string{
|
||||||
44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`,
|
44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`,
|
||||||
45: "mm:ss",
|
45: "mm:ss",
|
||||||
46: "[h]:mm:ss",
|
46: "[h]:mm:ss",
|
||||||
47: "mmss.0",
|
47: "mm:ss.0",
|
||||||
48: "##0.0E+0",
|
48: "##0.0E+0",
|
||||||
49: "@",
|
49: "@",
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue