// Package unicodedata provides additional lookup functions for unicode // properties, not covered by the standard package unicode.
package unicodedata import ( ) // GeneralCategory is an enum storing the Unicode General Category of a rune. type GeneralCategory uint8 // LookupGeneralCategory returns the unicode general categorie of the rune, // or [Unassigned] if not found. func ( rune) GeneralCategory { return GeneralCategory(gcLookup()) } // IsMark returns true for Spacing_Mark, Enclosing_Mark, Nonspacing_Mark func ( GeneralCategory) () bool { return == Mc || == Me || == Mn } // IsLetter returns true for Lowercase_Letter, Modifier_Letter, Other_Letter, Titlecase_Letter, Uppercase_Letter func ( GeneralCategory) () bool { return == Ll || == Lm || == Lo || == Lt || == Lu } // LookupCombiningClass returns the class used for the Canonical Ordering Algorithm in the Unicode Standard, // defaulting to 0. // // From http://www.unicode.org/reports/tr44/#Canonical_Combining_Class: // "This property could be considered either an enumerated property or a numeric property: // the principal use of the property is in terms of the numeric values. // For the property value names associated with different numeric values, // see DerivedCombiningClass.txt and Canonical Combining Class Values." func ( rune) uint8 { return cccLookup() } // LineBreak is a flag storing the Unicode Line Break Property. // // See https://unicode.org/reports/tr14/#Properties type LineBreak uint64 // LookupLineBreak returns the break class for the rune, // or 0 (the XX, Unknown class) func ( rune) LineBreak { := lbLookup() if == 0 { return 0 } return 1 << ( - 1) } // GraphemeBreak is a flag storing the Unicode Grapheme Cluster Break Property. // // See https://unicode.org/reports/tr29/#Grapheme_Cluster_Break_Property_Values type GraphemeBreak uint16 // LookupGraphemeBreak returns the grapheme break property for the rune, or 0. func ( rune) GraphemeBreak { := gbLookup() if == 0 { return 0 } return 1 << ( - 1) } // WordBreak is a flag storing the Unicode Word Break Property. // // See https://unicode.org/reports/tr29/#Table_Word_Break_Property_Values type WordBreak uint16 // LookupWordBreak returns the word break property for the rune, or 0. func ( rune) WordBreak { := wbLookup() if == 0 { return 0 } return 1 << ( - 1) } // IsWord returns true for all the runes we may found in a word, // that is either a Number (Nd, Nl, No) or a rune with the Alphabetic property func ( rune) bool { return wordLookup() == 1 } // IndicConjunctBreak is a flag storing the Indic_Conjunct_Break property used for UAX29, rule GB9c. type IndicConjunctBreak uint8 // LookupIndicConjunctBreak return the value of the Indic_Conjunct_Break, // or zero. func ( rune) IndicConjunctBreak { := indicCBLookup() if == 0 { return 0 } return 1 << ( - 1) } // LookupMirrorChar finds the mirrored equivalent of a character as defined in // the file BidiMirroring.txt of the Unicode Character Database available at // http://www.unicode.org/Public/UNIDATA/BidiMirroring.txt. // // If the input character is declared as a mirroring character in the // Unicode standard and has a mirrored equivalent, it is returned. // Otherwise the input character itself is returned func ( rune) rune { return + rune(mirLookup()) } func ( rune) bool { return emojiLookup() == 1 } // IsLargeEastAsian matches runes with East_Asian_Width property of // F, W or H, and is used for UAX14, rule LB30. func ( rune) bool { return eastAsianWidthLookup() == 1 } // Algorithmic hangul syllables [de]composition, used // in Compose and Decompose, but also exported for additional shaper // processing. const ( HangulSBase = 0xAC00 HangulLBase = 0x1100 HangulVBase = 0x1161 HangulTBase = 0x11A7 HangulSCount = 11172 HangulLCount = 19 HangulVCount = 21 HangulTCount = 28 HangulNCount = HangulVCount * HangulTCount ) func decomposeHangul( rune) (, rune, bool) { := - HangulSBase if < 0 || >= HangulSCount { return 0, 0, false } if %HangulTCount != 0 { // LV,T return HangulSBase + (/HangulTCount)*HangulTCount, HangulTBase + ( % HangulTCount), true } // L,V return HangulLBase + ( / HangulNCount), HangulVBase + (%HangulNCount)/HangulTCount, true } func composeHangul(, rune) (rune, bool) { if >= HangulSBase && < (HangulSBase+HangulSCount) && > HangulTBase && < (HangulTBase+HangulTCount) && (-HangulSBase)%HangulTCount == 0 { // LV,T return + ( - HangulTBase), true } else if >= HangulLBase && < (HangulLBase+HangulLCount) && >= HangulVBase && < (HangulVBase+HangulVCount) { // L,V := - HangulLBase := - HangulVBase return HangulSBase + *HangulNCount + *HangulTCount, true } return 0, false } // Decompose decomposes an input Unicode code point, // returning the two decomposed code points, if successful. // It returns `false` otherwise. func ( rune) (, rune, bool) { if , , = decomposeHangul(); { return , , true } := int(dmLookup()) // If no data, there's no decomposition. if == 0 { return , 0, false } -- /* Check if it's a single-character decomposition. */ if < len(dm1P0Map)+len(dm1P2Map) { /* Single-character decompositions currently are only in plane 0 or plane 2. */ if < len(dm1P0Map) { /* Plane 0. */ = rune(dm1P0Map[]) } else { /* Plane 2. */ -= len(dm1P0Map) = 0x20000 | rune(dm1P2Map[]) } = 0 return , , true } -= len(dm1P0Map) + len(dm1P2Map) /* Otherwise they are encoded either in a 32bit array or a 64bit array. */ if < len(dm2U32Map) { /* 32bit array. */ := dm2U32Map[] = rune( >> 21) // HB_CODEPOINT_DECODE3_11_7_14_1(v) = rune(>>14)&0x007F | 0x0300 // HB_CODEPOINT_DECODE3_11_7_14_2(v) return , , true } -= len(dm2U32Map) /* 64bit array. */ := dm2U64Map[] = rune( >> 42) // HB_CODEPOINT_DECODE3_1(v) = rune(( >> 21) & 0x1FFFFF) // HB_CODEPOINT_DECODE3_2(v) return , , true } // Compose composes a sequence of two input Unicode code // points by canonical equivalence, returning the composed code, if successful. // It returns `false` otherwise func (, rune) (rune, bool) { // Hangul is handled algorithmically. if , := composeHangul(, ); { return , true } var rune if (&0x7FFFF800) == 0x0000 && (&0x7FFFFF80) == 0x0300 { // If "a" is small enough and "b" is in the U+0300 range, // the composition data is encoded in a 32bit array sorted by "a,b" pair. := uint32((()&0x07FF)<<21 | (&0x007F)<<14) // HB_CODEPOINT_ENCODE3_11_7_14(a, b, 0) const uint32 = (0x1FFFFF&0x07FF)<<21 | (0x1FFFFF&0x007F)<<14 // HB_CODEPOINT_ENCODE3_11_7_14(0x1FFFFFu, 0x1FFFFFu, 0) := sort.Search(len(dm2U32Map), func( int) bool { return dm2U32Map[]& >= }) if !( < len(dm2U32Map) && dm2U32Map[]& == ) { return 0, false } := dm2U32Map[] = rune( & 0x3FFF) // HB_CODEPOINT_DECODE3_11_7_14_3(v) } else { // Otherwise it is stored in a 64bit array sorted by "a,b" pair. := uint64()<<42 | uint64()<<21 // HB_CODEPOINT_ENCODE3(a, b, 0) const = uint64(0x1FFFFF)<<42 | uint64(0x1FFFFF)<<21 // HB_CODEPOINT_ENCODE3(0x1FFFFFu, 0x1FFFFFu, 0); := sort.Search(len(dm2U64Map), func( int) bool { return dm2U64Map[]& >= }) if !( < len(dm2U64Map) && dm2U64Map[]& == ) { return 0, false } := dm2U64Map[] = rune( & 0x1FFFFF) // HB_CODEPOINT_DECODE3_3(v) } return , != 0 } // LookupVerticalOrientation returns the prefered orientation // for the given script. func ( language.Script) ScriptVerticalOrientation { for , := range uprightOrMixedScripts { if .script == { return } } // all other scripts have full R (sideways) return ScriptVerticalOrientation{exceptions: nil, script: , isMainSideways: true} } // Orientation returns the prefered orientation // for the given rune. // If the rune does not belong to this script, the default orientation of this script // is returned (regardless of the actual script of the given rune). func ( ScriptVerticalOrientation) ( rune) ( bool) { if .exceptions == nil || !unicode.Is(.exceptions, ) { return .isMainSideways } return !.isMainSideways }