@@ -36,9 +36,10 @@ type numberFormat struct {
36
36
section []nfp.Section
37
37
t time.Time
38
38
sectionIdx int
39
- date1904 , isNumeric , hours , seconds bool
39
+ date1904 , isNumeric , hours , seconds , useMillisecond bool
40
40
number float64
41
41
ap , localCode , result , value , valueSectionType string
42
+ switchArgument , currencyString string
42
43
fracHolder , fracPadding , intHolder , intPadding , expBaseLen int
43
44
percent int
44
45
useCommaSep , usePointer , usePositive , useScientificNotation bool
@@ -47,6 +48,7 @@ type numberFormat struct {
47
48
var (
48
49
// supportedTokenTypes list the supported number format token types currently.
49
50
supportedTokenTypes = []string {
51
+ nfp .TokenSubTypeCurrencyString ,
50
52
nfp .TokenSubTypeLanguageInfo ,
51
53
nfp .TokenTypeColor ,
52
54
nfp .TokenTypeCurrencyLanguage ,
@@ -58,23 +60,20 @@ var (
58
60
nfp .TokenTypeHashPlaceHolder ,
59
61
nfp .TokenTypeLiteral ,
60
62
nfp .TokenTypePercent ,
63
+ nfp .TokenTypeSwitchArgument ,
61
64
nfp .TokenTypeTextPlaceHolder ,
62
65
nfp .TokenTypeThousandsSeparator ,
63
66
nfp .TokenTypeZeroPlaceHolder ,
64
67
}
65
68
// supportedNumberTokenTypes list the supported number token types.
66
69
supportedNumberTokenTypes = []string {
67
- nfp .TokenTypeColor ,
68
- nfp .TokenTypeDecimalPoint ,
70
+ nfp .TokenTypeExponential ,
69
71
nfp .TokenTypeHashPlaceHolder ,
70
- nfp .TokenTypeLiteral ,
71
72
nfp .TokenTypePercent ,
72
- nfp .TokenTypeThousandsSeparator ,
73
73
nfp .TokenTypeZeroPlaceHolder ,
74
74
}
75
75
// supportedDateTimeTokenTypes list the supported date and time token types.
76
76
supportedDateTimeTokenTypes = []string {
77
- nfp .TokenTypeCurrencyLanguage ,
78
77
nfp .TokenTypeDateTimes ,
79
78
nfp .TokenTypeElapsedDateTimes ,
80
79
}
@@ -357,6 +356,30 @@ var (
357
356
apFmtYi = "\ua3b8 \ua111 /\ua06f \ua2d2 "
358
357
// apFmtWelsh defined the AM/PM name in the Welsh.
359
358
apFmtWelsh = "yb/yh"
359
+ // switchArgumentFunc defined the switch argument printer function
360
+ switchArgumentFunc = map [string ]func (s string ) string {
361
+ "[DBNum1]" : func (s string ) string {
362
+ r := strings .NewReplacer (
363
+ "0" , "\u25cb " , "1" , "\u4e00 " , "2" , "\u4e8c " , "3" , "\u4e09 " , "4" , "\u56db " ,
364
+ "5" , "\u4e94 " , "6" , "\u516d " , "7" , "\u4e03 " , "8" , "\u516b " , "9" , "\u4e5d " ,
365
+ )
366
+ return r .Replace (s )
367
+ },
368
+ "[DBNum2]" : func (s string ) string {
369
+ r := strings .NewReplacer (
370
+ "0" , "\u96f6 " , "1" , "\u58f9 " , "2" , "\u8d30 " , "3" , "\u53c1 " , "4" , "\u8086 " ,
371
+ "5" , "\u4f0d " , "6" , "\u9646 " , "7" , "\u67d2 " , "8" , "\u634c " , "9" , "\u7396 " ,
372
+ )
373
+ return r .Replace (s )
374
+ },
375
+ "[DBNum3]" : func (s string ) string {
376
+ r := strings .NewReplacer (
377
+ "0" , "\uff10 " , "1" , "\uff11 " , "2" , "\uff12 " , "3" , "\uff13 " , "4" , "\uff14 " ,
378
+ "5" , "\uff15 " , "6" , "\uff16 " , "7" , "\uff17 " , "8" , "\uff18 " , "9" , "\uff19 " ,
379
+ )
380
+ return r .Replace (s )
381
+ },
382
+ }
360
383
)
361
384
362
385
// prepareNumberic split the number into two before and after parts by a
@@ -431,6 +454,9 @@ func (nf *numberFormat) getNumberFmtConf() {
431
454
if token .TType == nfp .TokenTypeDecimalPoint {
432
455
nf .usePointer = true
433
456
}
457
+ if token .TType == nfp .TokenTypeSwitchArgument {
458
+ nf .switchArgument = token .TValue
459
+ }
434
460
if token .TType == nfp .TokenTypeZeroPlaceHolder {
435
461
if nf .usePointer {
436
462
if nf .useScientificNotation {
@@ -448,20 +474,34 @@ func (nf *numberFormat) getNumberFmtConf() {
448
474
// printNumberLiteral apply literal tokens for the pre-formatted text.
449
475
func (nf * numberFormat ) printNumberLiteral (text string ) string {
450
476
var result string
451
- var useZeroPlaceHolder bool
477
+ var useLiteral , useZeroPlaceHolder bool
452
478
if nf .usePositive {
453
479
result += "-"
454
480
}
455
- for _ , token := range nf .section [nf .sectionIdx ].Items {
481
+ for i , token := range nf .section [nf .sectionIdx ].Items {
482
+ if token .TType == nfp .TokenTypeCurrencyLanguage {
483
+ if err := nf .currencyLanguageHandler (i , token ); err != nil {
484
+ return nf .value
485
+ }
486
+ result += nf .currencyString
487
+ }
456
488
if token .TType == nfp .TokenTypeLiteral {
489
+ if useZeroPlaceHolder {
490
+ useLiteral = true
491
+ }
457
492
result += token .TValue
458
493
}
459
- if ! useZeroPlaceHolder && token .TType == nfp .TokenTypeZeroPlaceHolder {
460
- useZeroPlaceHolder = true
461
- result += text
494
+ if token .TType == nfp .TokenTypeZeroPlaceHolder {
495
+ if useLiteral && useZeroPlaceHolder {
496
+ return nf .value
497
+ }
498
+ if ! useZeroPlaceHolder {
499
+ useZeroPlaceHolder = true
500
+ result += text
501
+ }
462
502
}
463
503
}
464
- return result
504
+ return nf . printSwitchArgument ( result )
465
505
}
466
506
467
507
// printCommaSep format number with thousands separator.
@@ -484,6 +524,17 @@ func printCommaSep(text string) string {
484
524
return target .String ()
485
525
}
486
526
527
+ // printSwitchArgument format number with switch argument.
528
+ func (nf * numberFormat ) printSwitchArgument (text string ) string {
529
+ if nf .switchArgument == "" {
530
+ return text
531
+ }
532
+ if fn , ok := switchArgumentFunc [nf .switchArgument ]; ok {
533
+ return fn (text )
534
+ }
535
+ return nf .value
536
+ }
537
+
487
538
// printBigNumber format number which precision great than 15 with fraction
488
539
// zero padding and percentage symbol.
489
540
func (nf * numberFormat ) printBigNumber (decimal float64 , fracLen int ) string {
@@ -561,14 +612,14 @@ func (nf *numberFormat) numberHandler() string {
561
612
562
613
// dateTimeHandler handling data and time number format expression for a
563
614
// positive numeric.
564
- func (nf * numberFormat ) dateTimeHandler () ( result string ) {
615
+ func (nf * numberFormat ) dateTimeHandler () string {
565
616
nf .t , nf .hours , nf .seconds = timeFromExcelTime (nf .number , nf .date1904 ), false , false
566
617
for i , token := range nf .section [nf .sectionIdx ].Items {
567
618
if token .TType == nfp .TokenTypeCurrencyLanguage {
568
619
if err := nf .currencyLanguageHandler (i , token ); err != nil {
569
- result = nf .value
570
- return
620
+ return nf .value
571
621
}
622
+ nf .result += nf .currencyString
572
623
}
573
624
if token .TType == nfp .TokenTypeDateTimes {
574
625
nf .dateTimesHandler (i , token )
@@ -583,15 +634,18 @@ func (nf *numberFormat) dateTimeHandler() (result string) {
583
634
if token .TType == nfp .TokenTypeDecimalPoint {
584
635
nf .result += "."
585
636
}
637
+ if token .TType == nfp .TokenTypeSwitchArgument {
638
+ nf .switchArgument = token .TValue
639
+ }
586
640
if token .TType == nfp .TokenTypeZeroPlaceHolder {
587
641
zeroHolderLen := len (token .TValue )
588
642
if zeroHolderLen > 3 {
589
643
zeroHolderLen = 3
590
644
}
591
- nf .result += strings . Repeat ( "0 " , zeroHolderLen )
645
+ nf .result += fmt . Sprintf ( "%03d " , nf . t . Nanosecond () / 1e6 )[: zeroHolderLen ]
592
646
}
593
647
}
594
- return nf .result
648
+ return nf .printSwitchArgument ( nf . result )
595
649
}
596
650
597
651
// positiveHandler will be handling positive selection for a number format
@@ -609,13 +663,26 @@ func (nf *numberFormat) positiveHandler() string {
609
663
if fmtNum || nf .number < 0 {
610
664
return nf .value
611
665
}
666
+ var useDateTimeTokens bool
667
+ for _ , token := range nf .section [nf .sectionIdx ].Items {
668
+ if inStrSlice (supportedDateTimeTokenTypes , token .TType , false ) != - 1 {
669
+ if useDateTimeTokens && nf .useMillisecond {
670
+ return nf .value
671
+ }
672
+ useDateTimeTokens = true
673
+ }
674
+ if inStrSlice (supportedNumberTokenTypes , token .TType , false ) != - 1 {
675
+ if token .TType == nfp .TokenTypeZeroPlaceHolder {
676
+ nf .useMillisecond = true
677
+ continue
678
+ }
679
+ return nf .value
680
+ }
681
+ }
612
682
return nf .dateTimeHandler ()
613
683
}
614
684
}
615
- if fmtNum {
616
- return nf .numberHandler ()
617
- }
618
- return nf .value
685
+ return nf .numberHandler ()
619
686
}
620
687
621
688
// currencyLanguageHandler will be handling currency and language types tokens
@@ -626,11 +693,16 @@ func (nf *numberFormat) currencyLanguageHandler(i int, token nfp.Token) (err err
626
693
err = ErrUnsupportedNumberFormat
627
694
return
628
695
}
629
- if _ , ok := supportedLanguageInfo [strings .ToUpper (part .Token .TValue )]; ! ok {
630
- err = ErrUnsupportedNumberFormat
631
- return
696
+ if part .Token .TType == nfp .TokenSubTypeLanguageInfo {
697
+ if _ , ok := supportedLanguageInfo [strings .ToUpper (part .Token .TValue )]; ! ok {
698
+ err = ErrUnsupportedNumberFormat
699
+ return
700
+ }
701
+ nf .localCode = strings .ToUpper (part .Token .TValue )
702
+ }
703
+ if part .Token .TType == nfp .TokenSubTypeCurrencyString {
704
+ nf .currencyString = part .Token .TValue
632
705
}
633
- nf .localCode = strings .ToUpper (part .Token .TValue )
634
706
}
635
707
return
636
708
}
@@ -1039,17 +1111,17 @@ func (nf *numberFormat) minutesHandler(token nfp.Token) {
1039
1111
// secondsHandler will be handling seconds in the date and times types tokens
1040
1112
// for a number format expression.
1041
1113
func (nf * numberFormat ) secondsHandler (token nfp.Token ) {
1042
- nf .seconds = strings .Contains (strings .ToUpper (token .TValue ), "S" )
1043
- if nf .seconds {
1044
- switch len (token .TValue ) {
1045
- case 1 :
1046
- nf .result += strconv .Itoa (nf .t .Second ())
1047
- return
1048
- default :
1049
- nf .result += fmt .Sprintf ("%02d" , nf .t .Second ())
1050
- return
1051
- }
1114
+ if nf .seconds = strings .Contains (strings .ToUpper (token .TValue ), "S" ); ! nf .seconds {
1115
+ return
1116
+ }
1117
+ if ! nf .useMillisecond {
1118
+ nf .t = nf .t .Add (time .Duration (math .Round (float64 (nf .t .Nanosecond ())/ 1e9 )) * time .Second )
1052
1119
}
1120
+ if len (token .TValue ) == 1 {
1121
+ nf .result += strconv .Itoa (nf .t .Second ())
1122
+ return
1123
+ }
1124
+ nf .result += fmt .Sprintf ("%02d" , nf .t .Second ())
1053
1125
}
1054
1126
1055
1127
// elapsedDateTimesHandler will be handling elapsed date and times types tokens
@@ -1114,23 +1186,15 @@ func (nf *numberFormat) secondsNext(i int) bool {
1114
1186
// negativeHandler will be handling negative selection for a number format
1115
1187
// expression.
1116
1188
func (nf * numberFormat ) negativeHandler () (result string ) {
1117
- fmtNum := true
1118
1189
for _ , token := range nf .section [nf .sectionIdx ].Items {
1119
1190
if inStrSlice (supportedTokenTypes , token .TType , true ) == - 1 || token .TType == nfp .TokenTypeGeneral {
1120
1191
return nf .value
1121
1192
}
1122
- if inStrSlice (supportedNumberTokenTypes , token .TType , true ) != - 1 {
1123
- continue
1124
- }
1125
1193
if inStrSlice (supportedDateTimeTokenTypes , token .TType , true ) != - 1 {
1126
1194
return nf .value
1127
1195
}
1128
- fmtNum = false
1129
- }
1130
- if fmtNum {
1131
- return nf .numberHandler ()
1132
1196
}
1133
- return nf .value
1197
+ return nf .numberHandler ()
1134
1198
}
1135
1199
1136
1200
// zeroHandler will be handling zero selection for a number format expression.
0 commit comments