github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/number/format.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package number 6 7 import ( 8 "strconv" 9 "unicode/utf8" 10 11 "github.com/go-xe2/third/golang.org/x/text/language" 12 ) 13 14 // TODO: 15 // - grouping of fractions 16 // - allow user-defined superscript notation (such as <sup>4</sup>) 17 // - same for non-breaking spaces, like 18 19 // A VisibleDigits computes digits, comma placement and trailing zeros as they 20 // will be shown to the user. 21 type VisibleDigits interface { 22 Digits(buf []byte, t language.Tag, scale int) Digits 23 // TODO: Do we also need to add the verb or pass a format.State? 24 } 25 26 // Formatting proceeds along the following lines: 27 // 0) Compose rounding information from format and context. 28 // 1) Convert a number into a Decimal. 29 // 2) Sanitize Decimal by adding trailing zeros, removing leading digits, and 30 // (non-increment) rounding. The Decimal that results from this is suitable 31 // for determining the plural form. 32 // 3) Render the Decimal in the localized form. 33 34 // Formatter contains all the information needed to render a number. 35 type Formatter struct { 36 Pattern 37 Info 38 } 39 40 func (f *Formatter) init(t language.Tag, index []uint8) { 41 f.Info = InfoFromTag(t) 42 for ; ; t = t.Parent() { 43 if ci, ok := language.CompactIndex(t); ok { 44 f.Pattern = formats[index[ci]] 45 break 46 } 47 } 48 } 49 50 // InitPattern initializes a Formatter for the given Pattern. 51 func (f *Formatter) InitPattern(t language.Tag, pat *Pattern) { 52 f.Info = InfoFromTag(t) 53 f.Pattern = *pat 54 } 55 56 // InitDecimal initializes a Formatter using the default Pattern for the given 57 // language. 58 func (f *Formatter) InitDecimal(t language.Tag) { 59 f.init(t, tagToDecimal) 60 } 61 62 // InitScientific initializes a Formatter using the default Pattern for the 63 // given language. 64 func (f *Formatter) InitScientific(t language.Tag) { 65 f.init(t, tagToScientific) 66 f.Pattern.MinFractionDigits = 0 67 f.Pattern.MaxFractionDigits = -1 68 } 69 70 // InitEngineering initializes a Formatter using the default Pattern for the 71 // given language. 72 func (f *Formatter) InitEngineering(t language.Tag) { 73 f.init(t, tagToScientific) 74 f.Pattern.MinFractionDigits = 0 75 f.Pattern.MaxFractionDigits = -1 76 f.Pattern.MaxIntegerDigits = 3 77 f.Pattern.MinIntegerDigits = 1 78 } 79 80 // InitPercent initializes a Formatter using the default Pattern for the given 81 // language. 82 func (f *Formatter) InitPercent(t language.Tag) { 83 f.init(t, tagToPercent) 84 } 85 86 // InitPerMille initializes a Formatter using the default Pattern for the given 87 // language. 88 func (f *Formatter) InitPerMille(t language.Tag) { 89 f.init(t, tagToPercent) 90 f.Pattern.DigitShift = 3 91 } 92 93 func (f *Formatter) Append(dst []byte, x interface{}) []byte { 94 var d Decimal 95 r := f.RoundingContext 96 d.Convert(r, x) 97 return f.Render(dst, FormatDigits(&d, r)) 98 } 99 100 func FormatDigits(d *Decimal, r RoundingContext) Digits { 101 if r.isScientific() { 102 return scientificVisibleDigits(r, d) 103 } 104 return decimalVisibleDigits(r, d) 105 } 106 107 func (f *Formatter) Format(dst []byte, d *Decimal) []byte { 108 return f.Render(dst, FormatDigits(d, f.RoundingContext)) 109 } 110 111 func (f *Formatter) Render(dst []byte, d Digits) []byte { 112 var result []byte 113 var postPrefix, preSuffix int 114 if d.IsScientific { 115 result, postPrefix, preSuffix = appendScientific(dst, f, &d) 116 } else { 117 result, postPrefix, preSuffix = appendDecimal(dst, f, &d) 118 } 119 if f.PadRune == 0 { 120 return result 121 } 122 width := int(f.FormatWidth) 123 if count := utf8.RuneCount(result); count < width { 124 insertPos := 0 125 switch f.Flags & PadMask { 126 case PadAfterPrefix: 127 insertPos = postPrefix 128 case PadBeforeSuffix: 129 insertPos = preSuffix 130 case PadAfterSuffix: 131 insertPos = len(result) 132 } 133 num := width - count 134 pad := [utf8.UTFMax]byte{' '} 135 sz := 1 136 if r := f.PadRune; r != 0 { 137 sz = utf8.EncodeRune(pad[:], r) 138 } 139 extra := sz * num 140 if n := len(result) + extra; n < cap(result) { 141 result = result[:n] 142 copy(result[insertPos+extra:], result[insertPos:]) 143 } else { 144 buf := make([]byte, n) 145 copy(buf, result[:insertPos]) 146 copy(buf[insertPos+extra:], result[insertPos:]) 147 result = buf 148 } 149 for ; num > 0; num-- { 150 insertPos += copy(result[insertPos:], pad[:sz]) 151 } 152 } 153 return result 154 } 155 156 // decimalVisibleDigits converts d according to the RoundingContext. Note that 157 // the exponent may change as a result of this operation. 158 func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits { 159 if d.NaN || d.Inf { 160 return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} 161 } 162 n := Digits{digits: d.normalize().digits} 163 164 exp := n.Exp 165 exp += int32(r.DigitShift) 166 167 // Cap integer digits. Remove *most-significant* digits. 168 if r.MaxIntegerDigits > 0 { 169 if p := int(exp) - int(r.MaxIntegerDigits); p > 0 { 170 if p > len(n.Digits) { 171 p = len(n.Digits) 172 } 173 if n.Digits = n.Digits[p:]; len(n.Digits) == 0 { 174 exp = 0 175 } else { 176 exp -= int32(p) 177 } 178 // Strip leading zeros. 179 for len(n.Digits) > 0 && n.Digits[0] == 0 { 180 n.Digits = n.Digits[1:] 181 exp-- 182 } 183 } 184 } 185 186 // Rounding if not already done by Convert. 187 p := len(n.Digits) 188 if maxSig := int(r.MaxSignificantDigits); maxSig > 0 { 189 p = maxSig 190 } 191 if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 { 192 if cap := int(exp) + maxFrac; cap < p { 193 p = int(exp) + maxFrac 194 } 195 if p < 0 { 196 p = 0 197 } 198 } 199 n.round(r.Mode, p) 200 201 // set End (trailing zeros) 202 n.End = int32(len(n.Digits)) 203 if n.End == 0 { 204 exp = 0 205 if r.MinFractionDigits > 0 { 206 n.End = int32(r.MinFractionDigits) 207 } 208 if p := int32(r.MinSignificantDigits) - 1; p > n.End { 209 n.End = p 210 } 211 } else { 212 if end := exp + int32(r.MinFractionDigits); end > n.End { 213 n.End = end 214 } 215 if n.End < int32(r.MinSignificantDigits) { 216 n.End = int32(r.MinSignificantDigits) 217 } 218 } 219 n.Exp = exp 220 return n 221 } 222 223 // appendDecimal appends a formatted number to dst. It returns two possible 224 // insertion points for padding. 225 func appendDecimal(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) { 226 if dst, ok := f.renderSpecial(dst, n); ok { 227 return dst, 0, len(dst) 228 } 229 digits := n.Digits 230 exp := n.Exp 231 232 // Split in integer and fraction part. 233 var intDigits, fracDigits []byte 234 numInt := 0 235 numFrac := int(n.End - n.Exp) 236 if exp > 0 { 237 numInt = int(exp) 238 if int(exp) >= len(digits) { // ddddd | ddddd00 239 intDigits = digits 240 } else { // ddd.dd 241 intDigits = digits[:exp] 242 fracDigits = digits[exp:] 243 } 244 } else { 245 fracDigits = digits 246 } 247 248 neg := n.Neg 249 affix, suffix := f.getAffixes(neg) 250 dst = appendAffix(dst, f, affix, neg) 251 savedLen := len(dst) 252 253 minInt := int(f.MinIntegerDigits) 254 if minInt == 0 && f.MinSignificantDigits > 0 { 255 minInt = 1 256 } 257 // add leading zeros 258 for i := minInt; i > numInt; i-- { 259 dst = f.AppendDigit(dst, 0) 260 if f.needsSep(i) { 261 dst = append(dst, f.Symbol(SymGroup)...) 262 } 263 } 264 i := 0 265 for ; i < len(intDigits); i++ { 266 dst = f.AppendDigit(dst, intDigits[i]) 267 if f.needsSep(numInt - i) { 268 dst = append(dst, f.Symbol(SymGroup)...) 269 } 270 } 271 for ; i < numInt; i++ { 272 dst = f.AppendDigit(dst, 0) 273 if f.needsSep(numInt - i) { 274 dst = append(dst, f.Symbol(SymGroup)...) 275 } 276 } 277 278 if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 { 279 dst = append(dst, f.Symbol(SymDecimal)...) 280 } 281 // Add trailing zeros 282 i = 0 283 for n := -int(n.Exp); i < n; i++ { 284 dst = f.AppendDigit(dst, 0) 285 } 286 for _, d := range fracDigits { 287 i++ 288 dst = f.AppendDigit(dst, d) 289 } 290 for ; i < numFrac; i++ { 291 dst = f.AppendDigit(dst, 0) 292 } 293 return appendAffix(dst, f, suffix, neg), savedLen, len(dst) 294 } 295 296 func scientificVisibleDigits(r RoundingContext, d *Decimal) Digits { 297 if d.NaN || d.Inf { 298 return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} 299 } 300 n := Digits{digits: d.normalize().digits, IsScientific: true} 301 302 // Normalize to have at least one digit. This simplifies engineering 303 // notation. 304 if len(n.Digits) == 0 { 305 n.Digits = append(n.Digits, 0) 306 n.Exp = 1 307 } 308 309 // Significant digits are transformed by the parser for scientific notation 310 // and do not need to be handled here. 311 maxInt, numInt := int(r.MaxIntegerDigits), int(r.MinIntegerDigits) 312 if numInt == 0 { 313 numInt = 1 314 } 315 316 // If a maximum number of integers is specified, the minimum must be 1 317 // and the exponent is grouped by this number (e.g. for engineering) 318 if maxInt > numInt { 319 // Correct the exponent to reflect a single integer digit. 320 numInt = 1 321 // engineering 322 // 0.01234 ([12345]e-1) -> 1.2345e-2 12.345e-3 323 // 12345 ([12345]e+5) -> 1.2345e4 12.345e3 324 d := int(n.Exp-1) % maxInt 325 if d < 0 { 326 d += maxInt 327 } 328 numInt += d 329 } 330 331 p := len(n.Digits) 332 if maxSig := int(r.MaxSignificantDigits); maxSig > 0 { 333 p = maxSig 334 } 335 if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 && numInt+maxFrac < p { 336 p = numInt + maxFrac 337 } 338 n.round(r.Mode, p) 339 340 n.Comma = uint8(numInt) 341 n.End = int32(len(n.Digits)) 342 if minSig := int32(r.MinFractionDigits) + int32(numInt); n.End < minSig { 343 n.End = minSig 344 } 345 return n 346 } 347 348 // appendScientific appends a formatted number to dst. It returns two possible 349 // insertion points for padding. 350 func appendScientific(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) { 351 if dst, ok := f.renderSpecial(dst, n); ok { 352 return dst, 0, 0 353 } 354 digits := n.Digits 355 numInt := int(n.Comma) 356 numFrac := int(n.End) - int(n.Comma) 357 358 var intDigits, fracDigits []byte 359 if numInt <= len(digits) { 360 intDigits = digits[:numInt] 361 fracDigits = digits[numInt:] 362 } else { 363 intDigits = digits 364 } 365 neg := n.Neg 366 affix, suffix := f.getAffixes(neg) 367 dst = appendAffix(dst, f, affix, neg) 368 savedLen := len(dst) 369 370 i := 0 371 for ; i < len(intDigits); i++ { 372 dst = f.AppendDigit(dst, intDigits[i]) 373 if f.needsSep(numInt - i) { 374 dst = append(dst, f.Symbol(SymGroup)...) 375 } 376 } 377 for ; i < numInt; i++ { 378 dst = f.AppendDigit(dst, 0) 379 if f.needsSep(numInt - i) { 380 dst = append(dst, f.Symbol(SymGroup)...) 381 } 382 } 383 384 if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 { 385 dst = append(dst, f.Symbol(SymDecimal)...) 386 } 387 i = 0 388 for ; i < len(fracDigits); i++ { 389 dst = f.AppendDigit(dst, fracDigits[i]) 390 } 391 for ; i < numFrac; i++ { 392 dst = f.AppendDigit(dst, 0) 393 } 394 395 // exp 396 buf := [12]byte{} 397 // TODO: use exponential if superscripting is not available (no Latin 398 // numbers or no tags) and use exponential in all other cases. 399 exp := n.Exp - int32(n.Comma) 400 exponential := f.Symbol(SymExponential) 401 if exponential == "E" { 402 dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE 403 dst = append(dst, f.Symbol(SymSuperscriptingExponent)...) 404 dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE 405 dst = f.AppendDigit(dst, 1) 406 dst = f.AppendDigit(dst, 0) 407 switch { 408 case exp < 0: 409 dst = append(dst, superMinus...) 410 exp = -exp 411 case f.Flags&AlwaysExpSign != 0: 412 dst = append(dst, superPlus...) 413 } 414 b = strconv.AppendUint(buf[:0], uint64(exp), 10) 415 for i := len(b); i < int(f.MinExponentDigits); i++ { 416 dst = append(dst, superDigits[0]...) 417 } 418 for _, c := range b { 419 dst = append(dst, superDigits[c-'0']...) 420 } 421 } else { 422 dst = append(dst, exponential...) 423 switch { 424 case exp < 0: 425 dst = append(dst, f.Symbol(SymMinusSign)...) 426 exp = -exp 427 case f.Flags&AlwaysExpSign != 0: 428 dst = append(dst, f.Symbol(SymPlusSign)...) 429 } 430 b = strconv.AppendUint(buf[:0], uint64(exp), 10) 431 for i := len(b); i < int(f.MinExponentDigits); i++ { 432 dst = f.AppendDigit(dst, 0) 433 } 434 for _, c := range b { 435 dst = f.AppendDigit(dst, c-'0') 436 } 437 } 438 return appendAffix(dst, f, suffix, neg), savedLen, len(dst) 439 } 440 441 const ( 442 superMinus = "\u207B" // SUPERSCRIPT HYPHEN-MINUS 443 superPlus = "\u207A" // SUPERSCRIPT PLUS SIGN 444 ) 445 446 var ( 447 // Note: the digits are not sequential!!! 448 superDigits = []string{ 449 "\u2070", // SUPERSCRIPT DIGIT ZERO 450 "\u00B9", // SUPERSCRIPT DIGIT ONE 451 "\u00B2", // SUPERSCRIPT DIGIT TWO 452 "\u00B3", // SUPERSCRIPT DIGIT THREE 453 "\u2074", // SUPERSCRIPT DIGIT FOUR 454 "\u2075", // SUPERSCRIPT DIGIT FIVE 455 "\u2076", // SUPERSCRIPT DIGIT SIX 456 "\u2077", // SUPERSCRIPT DIGIT SEVEN 457 "\u2078", // SUPERSCRIPT DIGIT EIGHT 458 "\u2079", // SUPERSCRIPT DIGIT NINE 459 } 460 ) 461 462 func (f *Formatter) getAffixes(neg bool) (affix, suffix string) { 463 str := f.Affix 464 if str != "" { 465 if f.NegOffset > 0 { 466 if neg { 467 str = str[f.NegOffset:] 468 } else { 469 str = str[:f.NegOffset] 470 } 471 } 472 sufStart := 1 + str[0] 473 affix = str[1:sufStart] 474 suffix = str[sufStart+1:] 475 } 476 // TODO: introduce a NeedNeg sign to indicate if the left pattern already 477 // has a sign marked? 478 if f.NegOffset == 0 && (neg || f.Flags&AlwaysSign != 0) { 479 affix = "-" + affix 480 } 481 return affix, suffix 482 } 483 484 func (f *Formatter) renderSpecial(dst []byte, d *Digits) (b []byte, ok bool) { 485 if d.NaN { 486 return fmtNaN(dst, f), true 487 } 488 if d.Inf { 489 return fmtInfinite(dst, f, d), true 490 } 491 return dst, false 492 } 493 494 func fmtNaN(dst []byte, f *Formatter) []byte { 495 return append(dst, f.Symbol(SymNan)...) 496 } 497 498 func fmtInfinite(dst []byte, f *Formatter, d *Digits) []byte { 499 affix, suffix := f.getAffixes(d.Neg) 500 dst = appendAffix(dst, f, affix, d.Neg) 501 dst = append(dst, f.Symbol(SymInfinity)...) 502 dst = appendAffix(dst, f, suffix, d.Neg) 503 return dst 504 } 505 506 func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte { 507 quoting := false 508 escaping := false 509 for _, r := range affix { 510 switch { 511 case escaping: 512 // escaping occurs both inside and outside of quotes 513 dst = append(dst, string(r)...) 514 escaping = false 515 case r == '\\': 516 escaping = true 517 case r == '\'': 518 quoting = !quoting 519 case quoting: 520 dst = append(dst, string(r)...) 521 case r == '%': 522 if f.DigitShift == 3 { 523 dst = append(dst, f.Symbol(SymPerMille)...) 524 } else { 525 dst = append(dst, f.Symbol(SymPercentSign)...) 526 } 527 case r == '-' || r == '+': 528 if neg { 529 dst = append(dst, f.Symbol(SymMinusSign)...) 530 } else if f.Flags&ElideSign == 0 { 531 dst = append(dst, f.Symbol(SymPlusSign)...) 532 } else { 533 dst = append(dst, ' ') 534 } 535 default: 536 dst = append(dst, string(r)...) 537 } 538 } 539 return dst 540 }