25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

262 satır
7.3 KiB

  1. // Copyright 2016 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. //go:generate go run gen.go gen_common.go
  5. // Package plural provides utilities for handling linguistic plurals in text.
  6. //
  7. // The definitions in this package are based on the plural rule handling defined
  8. // in CLDR. See
  9. // https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for
  10. // details.
  11. package plural
  12. import (
  13. "golang.org/x/text/internal/language/compact"
  14. "golang.org/x/text/internal/number"
  15. "golang.org/x/text/language"
  16. )
  17. // Rules defines the plural rules for all languages for a certain plural type.
  18. //
  19. //
  20. // This package is UNDER CONSTRUCTION and its API may change.
  21. type Rules struct {
  22. rules []pluralCheck
  23. index []byte
  24. langToIndex []byte
  25. inclusionMasks []uint64
  26. }
  27. var (
  28. // Cardinal defines the plural rules for numbers indicating quantities.
  29. Cardinal *Rules = cardinal
  30. // Ordinal defines the plural rules for numbers indicating position
  31. // (first, second, etc.).
  32. Ordinal *Rules = ordinal
  33. ordinal = &Rules{
  34. ordinalRules,
  35. ordinalIndex,
  36. ordinalLangToIndex,
  37. ordinalInclusionMasks[:],
  38. }
  39. cardinal = &Rules{
  40. cardinalRules,
  41. cardinalIndex,
  42. cardinalLangToIndex,
  43. cardinalInclusionMasks[:],
  44. }
  45. )
  46. // getIntApprox converts the digits in slice digits[start:end] to an integer
  47. // according to the following rules:
  48. // - Let i be asInt(digits[start:end]), where out-of-range digits are assumed
  49. // to be zero.
  50. // - Result n is big if i / 10^nMod > 1.
  51. // - Otherwise the result is i % 10^nMod.
  52. //
  53. // For example, if digits is {1, 2, 3} and start:end is 0:5, then the result
  54. // for various values of nMod is:
  55. // - when nMod == 2, n == big
  56. // - when nMod == 3, n == big
  57. // - when nMod == 4, n == big
  58. // - when nMod == 5, n == 12300
  59. // - when nMod == 6, n == 12300
  60. // - when nMod == 7, n == 12300
  61. func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
  62. // Leading 0 digits just result in 0.
  63. p := start
  64. if p < 0 {
  65. p = 0
  66. }
  67. // Range only over the part for which we have digits.
  68. mid := end
  69. if mid >= len(digits) {
  70. mid = len(digits)
  71. }
  72. // Check digits more significant that nMod.
  73. if q := end - nMod; q > 0 {
  74. if q > mid {
  75. q = mid
  76. }
  77. for ; p < q; p++ {
  78. if digits[p] != 0 {
  79. return big
  80. }
  81. }
  82. }
  83. for ; p < mid; p++ {
  84. n = 10*n + int(digits[p])
  85. }
  86. // Multiply for trailing zeros.
  87. for ; p < end; p++ {
  88. n *= 10
  89. }
  90. return n
  91. }
  92. // MatchDigits computes the plural form for the given language and the given
  93. // decimal floating point digits. The digits are stored in big-endian order and
  94. // are of value byte(0) - byte(9). The floating point position is indicated by
  95. // exp and the number of visible decimals is scale. All leading and trailing
  96. // zeros may be omitted from digits.
  97. //
  98. // The following table contains examples of possible arguments to represent
  99. // the given numbers.
  100. // decimal digits exp scale
  101. // 123 []byte{1, 2, 3} 3 0
  102. // 123.4 []byte{1, 2, 3, 4} 3 1
  103. // 123.40 []byte{1, 2, 3, 4} 3 2
  104. // 100000 []byte{1} 6 0
  105. // 100000.00 []byte{1} 6 3
  106. func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
  107. index := tagToID(t)
  108. // Differentiate up to including mod 1000000 for the integer part.
  109. n := getIntApprox(digits, 0, exp, 6, 1000000)
  110. // Differentiate up to including mod 100 for the fractional part.
  111. f := getIntApprox(digits, exp, exp+scale, 2, 100)
  112. return matchPlural(p, index, n, f, scale)
  113. }
  114. func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
  115. n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
  116. return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
  117. }
  118. func validForms(p *Rules, t language.Tag) (forms []Form) {
  119. offset := p.langToIndex[tagToID(t)]
  120. rules := p.rules[p.index[offset]:p.index[offset+1]]
  121. forms = append(forms, Other)
  122. last := Other
  123. for _, r := range rules {
  124. if cat := Form(r.cat & formMask); cat != andNext && last != cat {
  125. forms = append(forms, cat)
  126. last = cat
  127. }
  128. }
  129. return forms
  130. }
  131. func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form {
  132. return matchPlural(p, tagToID(t), n, f, scale)
  133. }
  134. // MatchPlural returns the plural form for the given language and plural
  135. // operands (as defined in
  136. // https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
  137. // where
  138. // n absolute value of the source number (integer and decimals)
  139. // input
  140. // i integer digits of n.
  141. // v number of visible fraction digits in n, with trailing zeros.
  142. // w number of visible fraction digits in n, without trailing zeros.
  143. // f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w))
  144. // t visible fractional digits in n, without trailing zeros.
  145. //
  146. // If any of the operand values is too large to fit in an int, it is okay to
  147. // pass the value modulo 10,000,000.
  148. func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form {
  149. return matchPlural(p, tagToID(lang), i, f, v)
  150. }
  151. func matchPlural(p *Rules, index compact.ID, n, f, v int) Form {
  152. nMask := p.inclusionMasks[n%maxMod]
  153. // Compute the fMask inline in the rules below, as it is relatively rare.
  154. // fMask := p.inclusionMasks[f%maxMod]
  155. vMask := p.inclusionMasks[v%maxMod]
  156. // Do the matching
  157. offset := p.langToIndex[index]
  158. rules := p.rules[p.index[offset]:p.index[offset+1]]
  159. for i := 0; i < len(rules); i++ {
  160. rule := rules[i]
  161. setBit := uint64(1 << rule.setID)
  162. var skip bool
  163. switch op := opID(rule.cat >> opShift); op {
  164. case opI: // i = x
  165. skip = n >= numN || nMask&setBit == 0
  166. case opI | opNotEqual: // i != x
  167. skip = n < numN && nMask&setBit != 0
  168. case opI | opMod: // i % m = x
  169. skip = nMask&setBit == 0
  170. case opI | opMod | opNotEqual: // i % m != x
  171. skip = nMask&setBit != 0
  172. case opN: // n = x
  173. skip = f != 0 || n >= numN || nMask&setBit == 0
  174. case opN | opNotEqual: // n != x
  175. skip = f == 0 && n < numN && nMask&setBit != 0
  176. case opN | opMod: // n % m = x
  177. skip = f != 0 || nMask&setBit == 0
  178. case opN | opMod | opNotEqual: // n % m != x
  179. skip = f == 0 && nMask&setBit != 0
  180. case opF: // f = x
  181. skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
  182. case opF | opNotEqual: // f != x
  183. skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
  184. case opF | opMod: // f % m = x
  185. skip = p.inclusionMasks[f%maxMod]&setBit == 0
  186. case opF | opMod | opNotEqual: // f % m != x
  187. skip = p.inclusionMasks[f%maxMod]&setBit != 0
  188. case opV: // v = x
  189. skip = v < numN && vMask&setBit == 0
  190. case opV | opNotEqual: // v != x
  191. skip = v < numN && vMask&setBit != 0
  192. case opW: // w == 0
  193. skip = f != 0
  194. case opW | opNotEqual: // w != 0
  195. skip = f == 0
  196. // Hard-wired rules that cannot be handled by our algorithm.
  197. case opBretonM:
  198. skip = f != 0 || n == 0 || n%1000000 != 0
  199. case opAzerbaijan00s:
  200. // 100,200,300,400,500,600,700,800,900
  201. skip = n == 0 || n >= 1000 || n%100 != 0
  202. case opItalian800:
  203. skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800
  204. }
  205. if skip {
  206. // advance over AND entries.
  207. for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
  208. }
  209. continue
  210. }
  211. // return if we have a final entry.
  212. if cat := rule.cat & formMask; cat != andNext {
  213. return Form(cat)
  214. }
  215. }
  216. return Other
  217. }
  218. func tagToID(t language.Tag) compact.ID {
  219. id, _ := compact.RegionalID(compact.Tag(t))
  220. return id
  221. }