1 // Copyright 2014 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.
7 // This file contains the definitions of case mappings for all supported
8 // languages. The rules for the language-specific tailorings were taken and
9 // modified from the CLDR transform definitions in common/transforms.
16 "golang.org/x/text/internal"
17 "golang.org/x/text/language"
18 "golang.org/x/text/transform"
19 "golang.org/x/text/unicode/norm"
22 // A mapFunc takes a context set to the current rune and writes the mapped
23 // version to the same context. It may advance the context to the next rune. It
24 // returns whether a checkpoint is possible: whether the pDst bytes written to
25 // dst so far won't need changing as we see more source bytes.
26 type mapFunc func(*context) bool
28 // A spanFunc takes a context set to the current rune and returns whether this
29 // rune would be altered when written to the output. It may advance the context
30 // to the next rune. It returns whether a checkpoint is possible.
31 type spanFunc func(*context) bool
33 // maxIgnorable defines the maximum number of ignorables to consider for
34 // lookahead operations.
35 const maxIgnorable = 30
37 // supported lists the language tags for which we have tailorings.
38 const supported = "und af az el lt nl tr"
41 tags := []language.Tag{}
42 for _, s := range strings.Split(supported, " ") {
43 tags = append(tags, language.MustParse(s))
45 matcher = internal.NewInheritanceMatcher(tags)
46 Supported = language.NewCoverage(tags)
50 matcher *internal.InheritanceMatcher
52 Supported language.Coverage
54 // We keep the following lists separate, instead of having a single per-
55 // language struct, to give the compiler a chance to remove unused code.
57 // Some uppercase mappers are stateless, so we can precompute the
58 // Transformers and save a bit on runtime allocations.
59 upperFunc = []struct {
65 {aztrUpper(upper), isUpper}, // az
66 {elUpper, noSpan}, // el
67 {ltUpper(upper), noSpan}, // lt
69 {aztrUpper(upper), isUpper}, // tr
72 undUpper transform.SpanningTransformer = &undUpperCaser{}
73 undLower transform.SpanningTransformer = &undLowerCaser{}
74 undLowerIgnoreSigma transform.SpanningTransformer = &undLowerIgnoreSigmaCaser{}
76 lowerFunc = []mapFunc{
86 titleInfos = []struct {
90 rewrite func(*context)
92 {title, lower, isTitle, nil}, // und
93 {title, lower, isTitle, afnlRewrite}, // af
94 {aztrUpper(title), aztrLower, isTitle, nil}, // az
95 {title, lower, isTitle, nil}, // el
96 {ltUpper(title), ltLower, noSpan, nil}, // lt
97 {nlTitle, lower, nlTitleSpan, afnlRewrite}, // nl
98 {aztrUpper(title), aztrLower, isTitle, nil}, // tr
102 func makeUpper(t language.Tag, o options) transform.SpanningTransformer {
103 _, i, _ := matcher.Match(t)
104 f := upperFunc[i].upper
108 return &simpleCaser{f: f, span: upperFunc[i].span}
111 func makeLower(t language.Tag, o options) transform.SpanningTransformer {
112 _, i, _ := matcher.Match(t)
115 if o.ignoreFinalSigma {
116 return undLowerIgnoreSigma
120 if o.ignoreFinalSigma {
121 return &simpleCaser{f: f, span: isLower}
125 midWord: finalSigma(f),
129 func makeTitle(t language.Tag, o options) transform.SpanningTransformer {
130 _, i, _ := matcher.Match(t)
134 lower = (*context).copy
135 } else if !o.ignoreFinalSigma {
136 lower = finalSigma(lower)
141 titleSpan: x.titleSpan,
146 func noSpan(c *context) bool {
147 c.err = transform.ErrEndOfSpan
151 // TODO: consider a similar special case for the fast majority lower case. This
152 // is a bit more involved so will require some more precise benchmarking to
155 type undUpperCaser struct{ transform.NopResetter }
157 // undUpperCaser implements the Transformer interface for doing an upper case
158 // mapping for the root locale (und). It eliminates the need for an allocation
159 // as it prevents escaping by not using function pointers.
160 func (t undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
161 c := context{dst: dst, src: src, atEOF: atEOF}
169 func (t undUpperCaser) Span(src []byte, atEOF bool) (n int, err error) {
170 c := context{src: src, atEOF: atEOF}
171 for c.next() && isUpper(&c) {
177 // undLowerIgnoreSigmaCaser implements the Transformer interface for doing
178 // a lower case mapping for the root locale (und) ignoring final sigma
179 // handling. This casing algorithm is used in some performance-critical packages
180 // like secure/precis and x/net/http/idna, which warrants its special-casing.
181 type undLowerIgnoreSigmaCaser struct{ transform.NopResetter }
183 func (t undLowerIgnoreSigmaCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
184 c := context{dst: dst, src: src, atEOF: atEOF}
185 for c.next() && lower(&c) {
192 // Span implements a generic lower-casing. This is possible as isLower works
193 // for all lowercasing variants. All lowercase variants only vary in how they
194 // transform a non-lowercase letter. They will never change an already lowercase
195 // letter. In addition, there is no state.
196 func (t undLowerIgnoreSigmaCaser) Span(src []byte, atEOF bool) (n int, err error) {
197 c := context{src: src, atEOF: atEOF}
198 for c.next() && isLower(&c) {
204 type simpleCaser struct {
210 // simpleCaser implements the Transformer interface for doing a case operation
211 // on a rune-by-rune basis.
212 func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
213 c := context{dst: dst, src: src, atEOF: atEOF}
214 for c.next() && t.f(&c) {
220 func (t *simpleCaser) Span(src []byte, atEOF bool) (n int, err error) {
221 c := context{src: src, atEOF: atEOF}
222 for c.next() && t.span(&c) {
228 // undLowerCaser implements the Transformer interface for doing a lower case
229 // mapping for the root locale (und) ignoring final sigma handling. This casing
230 // algorithm is used in some performance-critical packages like secure/precis
231 // and x/net/http/idna, which warrants its special-casing.
232 type undLowerCaser struct{ transform.NopResetter }
234 func (t undLowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
235 c := context{dst: dst, src: src, atEOF: atEOF}
237 for isInterWord := true; c.next(); {
239 if c.info.isCased() {
244 } else if !c.copy() {
248 if c.info.isNotCasedAndNotCaseIgnorable() {
253 } else if !c.hasPrefix("Σ") {
257 } else if !finalSigmaBody(&c) {
266 func (t undLowerCaser) Span(src []byte, atEOF bool) (n int, err error) {
267 c := context{src: src, atEOF: atEOF}
268 for c.next() && isLower(&c) {
274 // lowerCaser implements the Transformer interface. The default Unicode lower
275 // casing requires different treatment for the first and subsequent characters
276 // of a word, most notably to handle the Greek final Sigma.
277 type lowerCaser struct {
278 undLowerIgnoreSigmaCaser
282 first, midWord mapFunc
285 func (t *lowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
286 t.context = context{dst: dst, src: src, atEOF: atEOF}
289 for isInterWord := true; c.next(); {
291 if c.info.isCased() {
296 } else if !c.copy() {
300 if c.info.isNotCasedAndNotCaseIgnorable() {
305 } else if !t.midWord(c) {
314 // titleCaser implements the Transformer interface. Title casing algorithms
315 // distinguish between the first letter of a word and subsequent letters of the
316 // same word. It uses state to avoid requiring a potentially infinite lookahead.
317 type titleCaser struct {
320 // rune mappings used by the actual casing algorithms.
325 rewrite func(*context)
328 // Transform implements the standard Unicode title case algorithm as defined in
329 // Chapter 3 of The Unicode Standard:
330 // toTitlecase(X): Find the word boundaries in X according to Unicode Standard
331 // Annex #29, "Unicode Text Segmentation." For each word boundary, find the
332 // first cased character F following the word boundary. If F exists, map F to
333 // Titlecase_Mapping(F); then map all characters C between F and the following
334 // word boundary to Lowercase_Mapping(C).
335 func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
336 t.context = context{dst: dst, src: src, atEOF: atEOF, isMidWord: t.isMidWord}
345 if t.rewrite != nil {
350 // Break out of this loop on failure to ensure we do not modify the
351 // state incorrectly.
358 } else if !t.lower(c) {
361 } else if !c.copy() {
363 } else if p.isBreak() {
367 // As we save the state of the transformer, it is safe to call
368 // checkpoint after any successful write.
369 if !(c.isMidWord && wasMid) {
376 if wasMid && c.info.isMid() {
383 func (t *titleCaser) Span(src []byte, atEOF bool) (n int, err error) {
384 t.context = context{src: src, atEOF: atEOF, isMidWord: t.isMidWord}
393 if t.rewrite != nil {
398 // Break out of this loop on failure to ensure we do not modify the
399 // state incorrectly.
406 } else if !isLower(c) {
409 } else if p.isBreak() {
412 // As we save the state of the transformer, it is safe to call
413 // checkpoint after any successful write.
414 if !(c.isMidWord && wasMid) {
421 if wasMid && c.info.isMid() {
428 // finalSigma adds Greek final Sigma handing to another casing function. It
429 // determines whether a lowercased sigma should be σ or ς, by looking ahead for
430 // case-ignorables and a cased letters.
431 func finalSigma(f mapFunc) mapFunc {
432 return func(c *context) bool {
433 if !c.hasPrefix("Σ") {
436 return finalSigmaBody(c)
440 func finalSigmaBody(c *context) bool {
441 // Current rune must be ∑.
444 // # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
445 // Σ } [:case-ignorable:]* [:cased:] → σ;
446 // [:cased:] [:case-ignorable:]* { Σ → ς;
453 // TODO: we should do this here, but right now this will never have an
454 // effect as this is called when the prefix is Sigma, whereas Dutch and
455 // Afrikaans only test for an apostrophe.
457 // if t.rewrite != nil {
461 // We need to do one more iteration after maxIgnorable, as a cased
462 // letter is not an ignorable and may modify the result.
464 for i := 0; i < maxIgnorable+1; i++ {
468 if !c.info.isCaseIgnorable() {
469 // All Midword runes are also case ignorable, so we are
470 // guaranteed to have a letter or word break here. As we are
471 // unreading the run, there is no need to unset c.isMidWord;
472 // the title caser will handle this.
473 if c.info.isCased() {
474 // p+1 is guaranteed to be in bounds: if writing ς was
475 // successful, p+1 will contain the second byte of ς. If not,
476 // this function will have returned after c.next returned false.
477 c.dst[p+1]++ // ς → σ
482 // A case ignorable may also introduce a word break, so we may need
483 // to continue searching even after detecting a break.
484 isMid := c.info.isMid()
485 if (wasMid && isMid) || c.info.isBreak() {
494 // finalSigmaSpan would be the same as isLower.
496 // elUpper implements Greek upper casing, which entails removing a predefined
497 // set of non-blocked modifiers. Note that these accents should not be removed
499 // Example: "Οδός" -> "ΟΔΟΣ".
500 func elUpper(c *context) bool {
502 // [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Above:]]*? { [\u0313\u0314\u0301\u0300\u0306\u0342\u0308\u0304] → ;
503 // [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Iota_Subscript:]]*? { \u0345 → ;
505 r, _ := utf8.DecodeRune(c.src[c.pSrc:])
510 if !unicode.Is(unicode.Greek, r) {
514 // Take the properties of the uppercased rune that is already written to the
515 // destination. This saves us the trouble of having to uppercase the
516 // decomposed rune again.
517 if b := norm.NFD.Properties(c.dst[oldPDst:]).Decomposition(); b != nil {
518 // Restore the destination position and process the decomposed rune.
519 r, sz := utf8.DecodeRune(b)
520 if r <= 0xFF { // See A.6.1
524 // Insert the first rune and ignore the modifiers. See A.6.2.
526 i = len(b[sz:]) / 2 // Greek modifiers are always of length 2.
529 for ; i < maxIgnorable && c.next(); i++ {
530 switch r, _ := utf8.DecodeRune(c.src[c.pSrc:]); r {
531 // Above and Iota Subscript
532 case 0x0300, // U+0300 COMBINING GRAVE ACCENT
533 0x0301, // U+0301 COMBINING ACUTE ACCENT
534 0x0304, // U+0304 COMBINING MACRON
535 0x0306, // U+0306 COMBINING BREVE
536 0x0308, // U+0308 COMBINING DIAERESIS
537 0x0313, // U+0313 COMBINING COMMA ABOVE
538 0x0314, // U+0314 COMBINING REVERSED COMMA ABOVE
539 0x0342, // U+0342 COMBINING GREEK PERISPOMENI
540 0x0345: // U+0345 COMBINING GREEK YPOGEGRAMMENI
541 // No-op. Gobble the modifier.
544 switch v, _ := trie.lookup(c.src[c.pSrc:]); info(v).cccType() {
549 // We don't need to test for IotaSubscript as the only rune that
550 // qualifies (U+0345) was already excluded in the switch statement
556 // Some other modifier. We're still allowed to gobble Greek
557 // modifiers after this.
562 return i == maxIgnorable
565 // TODO: implement elUpperSpan (low-priority: complex and infrequent).
567 func ltLower(c *context) bool {
569 // # Introduce an explicit dot above when lowercasing capital I's and J's
570 // # whenever there are more accents above.
571 // # (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
572 // # 0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
573 // # 004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
574 // # 012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
575 // # 00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
576 // # 00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
577 // # 0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
579 // I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307;
580 // J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307;
581 // I \u0328 (Į) } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0328 \u0307;
582 // I \u0300 (Ì) → i \u0307 \u0300;
583 // I \u0301 (Í) → i \u0307 \u0301;
584 // I \u0303 (Ĩ) → i \u0307 \u0303;
589 if r := c.src[c.pSrc]; r < utf8.RuneSelf {
591 if r != 'I' && r != 'J' {
595 p := norm.NFD.Properties(c.src[c.pSrc:])
596 if d := p.Decomposition(); len(d) >= 3 && (d[0] == 'I' || d[0] == 'J') {
597 // UTF-8 optimization: the decomposition will only have an above
598 // modifier if the last rune of the decomposition is in [U+300-U+311].
599 // In all other cases, a decomposition starting with I is always
600 // an I followed by modifiers that are not cased themselves. See A.2.
601 if d[1] == 0xCC && d[2] <= 0x91 { // A.2.4.
602 if !c.writeBytes(d[:1]) {
605 c.dst[c.pDst-1] += 'a' - 'A' // lower
607 // Assumption: modifier never changes on lowercase. See A.1.
608 // Assumption: all modifiers added have CCC = Above. See A.2.3.
609 return c.writeString("\u0307") && c.writeBytes(d[1:])
611 // In all other cases the additional modifiers will have a CCC
612 // that is less than 230 (Above). We will insert the U+0307, if
613 // needed, after these modifiers so that a string in FCD form
614 // will remain so. See A.2.2.
622 for ; i < maxIgnorable && c.next(); i++ {
623 switch c.info.cccType() {
628 return c.writeString("\u0307") && c.copy() // See A.1.
633 return i == maxIgnorable
636 // ltLowerSpan would be the same as isLower.
638 func ltUpper(f mapFunc) mapFunc {
639 return func(c *context) bool {
641 // 0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
644 // # Remove \u0307 following soft-dotteds (i, j, and the like), with possible
645 // # intervening non-230 marks.
647 // [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ;
651 // TODO: See A.5. A soft-dotted rune never has an exception. This would
652 // allow us to overload the exception bit and encode this property in
653 // info. Need to measure performance impact of this.
654 r, _ := utf8.DecodeRune(c.src[c.pSrc:])
659 if !unicode.Is(unicode.Soft_Dotted, r) {
663 // We don't need to do an NFD normalization, as a soft-dotted rune never
664 // contains U+0307. See A.3.
667 for ; i < maxIgnorable && c.next(); i++ {
668 switch c.info.cccType() {
673 if c.hasPrefix("\u0307") {
674 // We don't do a full NFC, but rather combine runes for
675 // some of the common cases. (Returning NFC or
676 // preserving normal form is neither a requirement nor
677 // a possibility anyway).
681 if c.dst[oldPDst] == 'I' && c.pDst == oldPDst+1 && c.src[c.pSrc] == 0xcc {
683 switch c.src[c.pSrc+1] {
684 case 0x80: // U+0300 COMBINING GRAVE ACCENT
685 s = "\u00cc" // U+00CC LATIN CAPITAL LETTER I WITH GRAVE
686 case 0x81: // U+0301 COMBINING ACUTE ACCENT
687 s = "\u00cd" // U+00CD LATIN CAPITAL LETTER I WITH ACUTE
688 case 0x83: // U+0303 COMBINING TILDE
689 s = "\u0128" // U+0128 LATIN CAPITAL LETTER I WITH TILDE
690 case 0x88: // U+0308 COMBINING DIAERESIS
691 s = "\u00cf" // U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS
696 return c.writeString(s)
705 return i == maxIgnorable
709 // TODO: implement ltUpperSpan (low priority: complex and infrequent).
711 func aztrUpper(f mapFunc) mapFunc {
712 return func(c *context) bool {
714 if c.src[c.pSrc] == 'i' {
715 return c.writeString("İ")
721 func aztrLower(c *context) (done bool) {
723 // # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
724 // # 0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE
726 // # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
727 // # This matches the behavior of the canonically equivalent I-dot_above
728 // # 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
729 // # When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
730 // # 0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
731 // I([^[:ccc=Not_Reordered:][:ccc=Above:]]*)\u0307 → i$1 ;
734 if c.hasPrefix("\u0130") { // İ
735 return c.writeString("i")
737 if c.src[c.pSrc] != 'I' {
741 // We ignore the lower-case I for now, but insert it later when we know
742 // which form we need.
743 start := c.pSrc + c.sz
747 // We check for up to n ignorables before \u0307. As \u0307 is an
748 // ignorable as well, n is maxIgnorable-1.
749 for ; i < maxIgnorable && c.next(); i++ {
750 switch c.info.cccType() {
752 if c.hasPrefix("\u0307") {
753 return c.writeString("i") && c.writeBytes(c.src[start:c.pSrc]) // ignore U+0307
762 // We'll write this rune after we know which starter to use.
765 if i == maxIgnorable {
768 return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done
771 // aztrLowerSpan would be the same as isLower.
773 func nlTitle(c *context) bool {
775 // # Special titlecasing for Dutch initial "ij".
777 // # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
778 // [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
779 if c.src[c.pSrc] != 'I' && c.src[c.pSrc] != 'i' {
783 if !c.writeString("I") || !c.next() {
786 if c.src[c.pSrc] == 'j' || c.src[c.pSrc] == 'J' {
787 return c.writeString("J")
793 func nlTitleSpan(c *context) bool {
795 // # Special titlecasing for Dutch initial "ij".
797 // # Fix up Ij at the beginning of a "word" (per Any-Title, notUAX #29)
798 // [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
799 if c.src[c.pSrc] != 'I' {
802 if !c.next() || c.src[c.pSrc] == 'j' {
805 if c.src[c.pSrc] != 'J' {
811 // Not part of CLDR, but see http://unicode.org/cldr/trac/ticket/7078.
812 func afnlRewrite(c *context) {
813 if c.hasPrefix("'") || c.hasPrefix("’") {