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 &nbsp;
    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  }