From 74d528afe20a46da2e932c7e28253ac7bb9fbe4f Mon Sep 17 00:00:00 2001 From: Samuel Kelemen Date: Fri, 12 Jun 2026 13:36:23 +0200 Subject: [PATCH] feat(uax34): add Named Character Sequences --- uax34/NamedSequences.txt | 613 ++++++++++++++++++++++++++++++ uax34/README.md | 97 +++++ uax34/example_test.go | 24 ++ uax34/generate_named_sequences.go | 181 +++++++++ uax34/named_sequences_data.go | 480 +++++++++++++++++++++++ uax34/uax34.go | 125 ++++++ uax34/uax34_test.go | 239 ++++++++++++ 7 files changed, 1759 insertions(+) create mode 100644 uax34/NamedSequences.txt create mode 100644 uax34/README.md create mode 100644 uax34/example_test.go create mode 100644 uax34/generate_named_sequences.go create mode 100644 uax34/named_sequences_data.go create mode 100644 uax34/uax34.go create mode 100644 uax34/uax34_test.go diff --git a/uax34/NamedSequences.txt b/uax34/NamedSequences.txt new file mode 100644 index 0000000..378bf4a --- /dev/null +++ b/uax34/NamedSequences.txt @@ -0,0 +1,613 @@ +# NamedSequences-17.0.0.txt +# Date: 2025-07-30 +# © 2025 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see https://www.unicode.org/reports/tr44/ +# +# Unicode Named Character Sequences +# +# This file is a normative contributory data file in the Unicode +# Character Database. +# +# Format: +# Name of Sequence; Code Point Sequence for USI +# +# Code point sequences in the Unicode Character Database +# use spaces as delimiters. The corresponding format for a +# UCS Sequence Identifier (USI) in ISO/IEC 10646 uses +# comma delimitation and angle brackets. Thus, a Unicode +# named character sequence of the form: +# +# EXAMPLE NAME;1000 1001 1002 +# +# in this data file, would correspond to an ISO/IEC 10646 USI +# as follows: +# +# <1000, 1001, 1002> +# +# For more information, see UAX #34: Unicode Named Character +# Sequences, at https://www.unicode.org/reports/tr34/ +# +# Note: The order of entries in this file is not significant. +# However, entries are generally in script order corresponding +# to block order in the Unicode Standard, to make it easier +# to find entries in the list. + +# ================================================ + +# Named keycap sequences for telephone keypad (used for emoji) +# Provisional, 2015-05-05 +# FE0F added to the sequences, 2016-05-11 +# Approved 2017-05-12 + +KEYCAP NUMBER SIGN;0023 FE0F 20E3 +KEYCAP ASTERISK;002A FE0F 20E3 +KEYCAP DIGIT ZERO;0030 FE0F 20E3 +KEYCAP DIGIT ONE;0031 FE0F 20E3 +KEYCAP DIGIT TWO;0032 FE0F 20E3 +KEYCAP DIGIT THREE;0033 FE0F 20E3 +KEYCAP DIGIT FOUR;0034 FE0F 20E3 +KEYCAP DIGIT FIVE;0035 FE0F 20E3 +KEYCAP DIGIT SIX;0036 FE0F 20E3 +KEYCAP DIGIT SEVEN;0037 FE0F 20E3 +KEYCAP DIGIT EIGHT;0038 FE0F 20E3 +KEYCAP DIGIT NINE;0039 FE0F 20E3 + +# Latin letter plus accent combinations. +# These are part of the original set of approved named sequences +# for Unicode 4.1. 2005. +# Subgroupings of this original set are identified here by +# purpose and source. + +# Subset 1: Originally requested for a Latin orthography +# of Hausa. See WG2 N1143 and UTC/1996-005. (6 total) + +LATIN CAPITAL LETTER A WITH MACRON AND GRAVE;0100 0300 +LATIN SMALL LETTER A WITH MACRON AND GRAVE;0101 0300 +LATIN CAPITAL LETTER I WITH MACRON AND GRAVE;012A 0300 +LATIN SMALL LETTER I WITH MACRON AND GRAVE;012B 0300 +LATIN CAPITAL LETTER U WITH MACRON AND GRAVE;016A 0300 +LATIN SMALL LETTER U WITH MACRON AND GRAVE;016B 0300 + +# Subset 2: Originally requested for a Latin orthography +# of Yoruba. See WG2 N1143 and UTC/1996-005. (14 total) + +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW;0045 0329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW;0065 0329 +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND GRAVE;00C8 0329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND GRAVE;00E8 0329 +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND ACUTE;00C9 0329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND ACUTE;00E9 0329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW;004F 0329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW;006F 0329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND GRAVE;00D2 0329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND GRAVE;00F2 0329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND ACUTE;00D3 0329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND ACUTE;00F3 0329 +LATIN CAPITAL LETTER S WITH VERTICAL LINE BELOW;0053 0329 +LATIN SMALL LETTER S WITH VERTICAL LINE BELOW;0073 0329 + +# Subset 3: Originally requested for Pinyin forms noted +# in HKSCS. See L2/02-423 and WG2 N2513. (4 total) + +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND MACRON;00CA 0304 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND MACRON;00EA 0304 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND CARON;00CA 030C +LATIN SMALL LETTER E WITH CIRCUMFLEX AND CARON;00EA 030C + +# Subset 4: Prominent use cases pulled from examples +# for Lithuanian and Tagalog in +# Unicode 4.0 and early drafts of UAX #34. (2 total) + +LATIN SMALL LETTER I WITH DOT ABOVE AND ACUTE;0069 0307 0301 +LATIN SMALL LETTER NG WITH TILDE ABOVE;006E 0360 0067 + +# Additions for Lithuanian. +# Provisional 2006-05-18, Approved 2007-10-19 + +LATIN CAPITAL LETTER A WITH OGONEK AND ACUTE;0104 0301 +LATIN SMALL LETTER A WITH OGONEK AND ACUTE;0105 0301 +LATIN CAPITAL LETTER A WITH OGONEK AND TILDE;0104 0303 +LATIN SMALL LETTER A WITH OGONEK AND TILDE;0105 0303 +LATIN CAPITAL LETTER E WITH OGONEK AND ACUTE;0118 0301 +LATIN SMALL LETTER E WITH OGONEK AND ACUTE;0119 0301 +LATIN CAPITAL LETTER E WITH OGONEK AND TILDE;0118 0303 +LATIN SMALL LETTER E WITH OGONEK AND TILDE;0119 0303 +LATIN CAPITAL LETTER E WITH DOT ABOVE AND ACUTE;0116 0301 +LATIN SMALL LETTER E WITH DOT ABOVE AND ACUTE;0117 0301 +LATIN CAPITAL LETTER E WITH DOT ABOVE AND TILDE;0116 0303 +LATIN SMALL LETTER E WITH DOT ABOVE AND TILDE;0117 0303 +LATIN SMALL LETTER I WITH DOT ABOVE AND GRAVE;0069 0307 0300 +LATIN SMALL LETTER I WITH DOT ABOVE AND TILDE;0069 0307 0303 +LATIN CAPITAL LETTER I WITH OGONEK AND ACUTE;012E 0301 +LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND ACUTE;012F 0307 0301 +LATIN CAPITAL LETTER I WITH OGONEK AND TILDE;012E 0303 +LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND TILDE;012F 0307 0303 +LATIN CAPITAL LETTER J WITH TILDE;004A 0303 +LATIN SMALL LETTER J WITH DOT ABOVE AND TILDE;006A 0307 0303 +LATIN CAPITAL LETTER L WITH TILDE;004C 0303 +LATIN SMALL LETTER L WITH TILDE;006C 0303 +LATIN CAPITAL LETTER M WITH TILDE;004D 0303 +LATIN SMALL LETTER M WITH TILDE;006D 0303 +LATIN CAPITAL LETTER R WITH TILDE;0052 0303 +LATIN SMALL LETTER R WITH TILDE;0072 0303 +LATIN CAPITAL LETTER U WITH OGONEK AND ACUTE;0172 0301 +LATIN SMALL LETTER U WITH OGONEK AND ACUTE;0173 0301 +LATIN CAPITAL LETTER U WITH OGONEK AND TILDE;0172 0303 +LATIN SMALL LETTER U WITH OGONEK AND TILDE;0173 0303 +LATIN CAPITAL LETTER U WITH MACRON AND ACUTE;016A 0301 +LATIN SMALL LETTER U WITH MACRON AND ACUTE;016B 0301 +LATIN CAPITAL LETTER U WITH MACRON AND TILDE;016A 0303 +LATIN SMALL LETTER U WITH MACRON AND TILDE;016B 0303 + +# Entries for JIS X 0213 compatibility mapping. +# Provisional 2008-11-07, Approved 2010-05-14 + +LATIN SMALL LETTER AE WITH GRAVE;00E6 0300 +LATIN SMALL LETTER OPEN O WITH GRAVE;0254 0300 +LATIN SMALL LETTER OPEN O WITH ACUTE;0254 0301 +LATIN SMALL LETTER TURNED V WITH GRAVE;028C 0300 +LATIN SMALL LETTER TURNED V WITH ACUTE;028C 0301 +LATIN SMALL LETTER SCHWA WITH GRAVE;0259 0300 +LATIN SMALL LETTER SCHWA WITH ACUTE;0259 0301 +LATIN SMALL LETTER HOOKED SCHWA WITH GRAVE;025A 0300 +LATIN SMALL LETTER HOOKED SCHWA WITH ACUTE;025A 0301 + +# Entries for Uyghur and Chagatai. +# Provisional N/A, Approved 2012-11-08 + +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF;0626 0627 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH WAW;0626 0648 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA;0626 0649 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH OE;0626 06C6 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH U;0626 06C7 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH YU;0626 06C8 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH E;0626 06D0 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH AE;0626 06D5 +ARABIC SEQUENCE NOON WITH KEHEH;0646 06A9 + +# Entries that correspond to Indic characters with nuktas +# that are also listed in CompositionExclusions.txt. +# These characters decompose for normalized text, even +# in NFC. Having named sequences for these helps in +# certain specifications, including Label Generation Rules (LGR) +# for Internationalized Domain Names (IDN). +# +# Provisional 2020-01-16, Approved 2021-07-27 + +DEVANAGARI SEQUENCE FOR LETTER QA; 0915 093C +DEVANAGARI SEQUENCE FOR LETTER KHHA; 0916 093C +DEVANAGARI SEQUENCE FOR LETTER GHHA; 0917 093C +DEVANAGARI SEQUENCE FOR LETTER ZA; 091C 093C +DEVANAGARI SEQUENCE FOR LETTER DDDHA; 0921 093C +DEVANAGARI SEQUENCE FOR LETTER RHA; 0922 093C +DEVANAGARI SEQUENCE FOR LETTER FA; 092B 093C +DEVANAGARI SEQUENCE FOR LETTER YYA; 092F 093C +BENGALI SEQUENCE FOR LETTER RRA; 09A1 09BC +BENGALI SEQUENCE FOR LETTER RHA; 09A2 09BC +BENGALI SEQUENCE FOR LETTER YYA; 09AF 09BC +GURMUKHI SEQUENCE FOR LETTER LLA; 0A32 0A3C +GURMUKHI SEQUENCE FOR LETTER SHA; 0A38 0A3C +GURMUKHI SEQUENCE FOR LETTER KHHA; 0A16 0A3C +GURMUKHI SEQUENCE FOR LETTER GHHA; 0A17 0A3C +GURMUKHI SEQUENCE FOR LETTER ZA; 0A1C 0A3C +GURMUKHI SEQUENCE FOR LETTER FA; 0A2B 0A3C +ORIYA SEQUENCE FOR LETTER RRA; 0B21 0B3C +ORIYA SEQUENCE FOR LETTER RHA; 0B22 0B3C + +# Entry for a Bangla entity. +# Provisional 2009-08-10, Approved 2010-05-14 +# +# Note that this same sequence is also used for the ASSAMESE LETTER KSSA. + +BENGALI LETTER KHINYA;0995 09CD 09B7 + +# Additions for Tamil. +# Provisional 2008-02-08, Approved 2009-08-14 +# +# A visual display of the Tamil named character sequences is available +# in the documentation for the Unicode Standard. +# See the "Tamil" section in the core specification. + +TAMIL CONSONANT K; 0B95 0BCD +TAMIL CONSONANT NG; 0B99 0BCD +TAMIL CONSONANT C; 0B9A 0BCD +TAMIL CONSONANT NY; 0B9E 0BCD +TAMIL CONSONANT TT; 0B9F 0BCD +TAMIL CONSONANT NN; 0BA3 0BCD +TAMIL CONSONANT T; 0BA4 0BCD +TAMIL CONSONANT N; 0BA8 0BCD +TAMIL CONSONANT P; 0BAA 0BCD +TAMIL CONSONANT M; 0BAE 0BCD +TAMIL CONSONANT Y; 0BAF 0BCD +TAMIL CONSONANT R; 0BB0 0BCD +TAMIL CONSONANT L; 0BB2 0BCD +TAMIL CONSONANT V; 0BB5 0BCD +TAMIL CONSONANT LLL;0BB4 0BCD +TAMIL CONSONANT LL; 0BB3 0BCD +TAMIL CONSONANT RR; 0BB1 0BCD +TAMIL CONSONANT NNN;0BA9 0BCD +TAMIL CONSONANT J; 0B9C 0BCD +TAMIL CONSONANT SH; 0BB6 0BCD +TAMIL CONSONANT SS; 0BB7 0BCD +TAMIL CONSONANT S; 0BB8 0BCD +TAMIL CONSONANT H; 0BB9 0BCD +TAMIL CONSONANT KSS;0B95 0BCD 0BB7 0BCD + +TAMIL SYLLABLE KAA; 0B95 0BBE +TAMIL SYLLABLE KI; 0B95 0BBF +TAMIL SYLLABLE KII; 0B95 0BC0 +TAMIL SYLLABLE KU; 0B95 0BC1 +TAMIL SYLLABLE KUU; 0B95 0BC2 +TAMIL SYLLABLE KE; 0B95 0BC6 +TAMIL SYLLABLE KEE; 0B95 0BC7 +TAMIL SYLLABLE KAI; 0B95 0BC8 +TAMIL SYLLABLE KO; 0B95 0BCA +TAMIL SYLLABLE KOO; 0B95 0BCB +TAMIL SYLLABLE KAU; 0B95 0BCC + +TAMIL SYLLABLE NGAA; 0B99 0BBE +TAMIL SYLLABLE NGI; 0B99 0BBF +TAMIL SYLLABLE NGII; 0B99 0BC0 +TAMIL SYLLABLE NGU; 0B99 0BC1 +TAMIL SYLLABLE NGUU; 0B99 0BC2 +TAMIL SYLLABLE NGE; 0B99 0BC6 +TAMIL SYLLABLE NGEE; 0B99 0BC7 +TAMIL SYLLABLE NGAI; 0B99 0BC8 +TAMIL SYLLABLE NGO; 0B99 0BCA +TAMIL SYLLABLE NGOO; 0B99 0BCB +TAMIL SYLLABLE NGAU; 0B99 0BCC + +TAMIL SYLLABLE CAA; 0B9A 0BBE +TAMIL SYLLABLE CI; 0B9A 0BBF +TAMIL SYLLABLE CII; 0B9A 0BC0 +TAMIL SYLLABLE CU; 0B9A 0BC1 +TAMIL SYLLABLE CUU; 0B9A 0BC2 +TAMIL SYLLABLE CE; 0B9A 0BC6 +TAMIL SYLLABLE CEE; 0B9A 0BC7 +TAMIL SYLLABLE CAI; 0B9A 0BC8 +TAMIL SYLLABLE CO; 0B9A 0BCA +TAMIL SYLLABLE COO; 0B9A 0BCB +TAMIL SYLLABLE CAU; 0B9A 0BCC + +TAMIL SYLLABLE NYAA; 0B9E 0BBE +TAMIL SYLLABLE NYI; 0B9E 0BBF +TAMIL SYLLABLE NYII; 0B9E 0BC0 +TAMIL SYLLABLE NYU; 0B9E 0BC1 +TAMIL SYLLABLE NYUU; 0B9E 0BC2 +TAMIL SYLLABLE NYE; 0B9E 0BC6 +TAMIL SYLLABLE NYEE; 0B9E 0BC7 +TAMIL SYLLABLE NYAI; 0B9E 0BC8 +TAMIL SYLLABLE NYO; 0B9E 0BCA +TAMIL SYLLABLE NYOO; 0B9E 0BCB +TAMIL SYLLABLE NYAU; 0B9E 0BCC + +TAMIL SYLLABLE TTAA; 0B9F 0BBE +TAMIL SYLLABLE TTI; 0B9F 0BBF +TAMIL SYLLABLE TTII; 0B9F 0BC0 +TAMIL SYLLABLE TTU; 0B9F 0BC1 +TAMIL SYLLABLE TTUU; 0B9F 0BC2 +TAMIL SYLLABLE TTE; 0B9F 0BC6 +TAMIL SYLLABLE TTEE; 0B9F 0BC7 +TAMIL SYLLABLE TTAI; 0B9F 0BC8 +TAMIL SYLLABLE TTO; 0B9F 0BCA +TAMIL SYLLABLE TTOO; 0B9F 0BCB +TAMIL SYLLABLE TTAU; 0B9F 0BCC + +TAMIL SYLLABLE NNAA; 0BA3 0BBE +TAMIL SYLLABLE NNI; 0BA3 0BBF +TAMIL SYLLABLE NNII; 0BA3 0BC0 +TAMIL SYLLABLE NNU; 0BA3 0BC1 +TAMIL SYLLABLE NNUU; 0BA3 0BC2 +TAMIL SYLLABLE NNE; 0BA3 0BC6 +TAMIL SYLLABLE NNEE; 0BA3 0BC7 +TAMIL SYLLABLE NNAI; 0BA3 0BC8 +TAMIL SYLLABLE NNO; 0BA3 0BCA +TAMIL SYLLABLE NNOO; 0BA3 0BCB +TAMIL SYLLABLE NNAU; 0BA3 0BCC + +TAMIL SYLLABLE TAA; 0BA4 0BBE +TAMIL SYLLABLE TI; 0BA4 0BBF +TAMIL SYLLABLE TII; 0BA4 0BC0 +TAMIL SYLLABLE TU; 0BA4 0BC1 +TAMIL SYLLABLE TUU; 0BA4 0BC2 +TAMIL SYLLABLE TE; 0BA4 0BC6 +TAMIL SYLLABLE TEE; 0BA4 0BC7 +TAMIL SYLLABLE TAI; 0BA4 0BC8 +TAMIL SYLLABLE TO; 0BA4 0BCA +TAMIL SYLLABLE TOO; 0BA4 0BCB +TAMIL SYLLABLE TAU; 0BA4 0BCC + +TAMIL SYLLABLE NAA; 0BA8 0BBE +TAMIL SYLLABLE NI; 0BA8 0BBF +TAMIL SYLLABLE NII; 0BA8 0BC0 +TAMIL SYLLABLE NU; 0BA8 0BC1 +TAMIL SYLLABLE NUU; 0BA8 0BC2 +TAMIL SYLLABLE NE; 0BA8 0BC6 +TAMIL SYLLABLE NEE; 0BA8 0BC7 +TAMIL SYLLABLE NAI; 0BA8 0BC8 +TAMIL SYLLABLE NO; 0BA8 0BCA +TAMIL SYLLABLE NOO; 0BA8 0BCB +TAMIL SYLLABLE NAU; 0BA8 0BCC + +TAMIL SYLLABLE PAA; 0BAA 0BBE +TAMIL SYLLABLE PI; 0BAA 0BBF +TAMIL SYLLABLE PII; 0BAA 0BC0 +TAMIL SYLLABLE PU; 0BAA 0BC1 +TAMIL SYLLABLE PUU; 0BAA 0BC2 +TAMIL SYLLABLE PE; 0BAA 0BC6 +TAMIL SYLLABLE PEE; 0BAA 0BC7 +TAMIL SYLLABLE PAI; 0BAA 0BC8 +TAMIL SYLLABLE PO; 0BAA 0BCA +TAMIL SYLLABLE POO; 0BAA 0BCB +TAMIL SYLLABLE PAU; 0BAA 0BCC + +TAMIL SYLLABLE MAA; 0BAE 0BBE +TAMIL SYLLABLE MI; 0BAE 0BBF +TAMIL SYLLABLE MII; 0BAE 0BC0 +TAMIL SYLLABLE MU; 0BAE 0BC1 +TAMIL SYLLABLE MUU; 0BAE 0BC2 +TAMIL SYLLABLE ME; 0BAE 0BC6 +TAMIL SYLLABLE MEE; 0BAE 0BC7 +TAMIL SYLLABLE MAI; 0BAE 0BC8 +TAMIL SYLLABLE MO; 0BAE 0BCA +TAMIL SYLLABLE MOO; 0BAE 0BCB +TAMIL SYLLABLE MAU; 0BAE 0BCC + +TAMIL SYLLABLE YAA; 0BAF 0BBE +TAMIL SYLLABLE YI; 0BAF 0BBF +TAMIL SYLLABLE YII; 0BAF 0BC0 +TAMIL SYLLABLE YU; 0BAF 0BC1 +TAMIL SYLLABLE YUU; 0BAF 0BC2 +TAMIL SYLLABLE YE; 0BAF 0BC6 +TAMIL SYLLABLE YEE; 0BAF 0BC7 +TAMIL SYLLABLE YAI; 0BAF 0BC8 +TAMIL SYLLABLE YO; 0BAF 0BCA +TAMIL SYLLABLE YOO; 0BAF 0BCB +TAMIL SYLLABLE YAU; 0BAF 0BCC + +TAMIL SYLLABLE RAA; 0BB0 0BBE +TAMIL SYLLABLE RI; 0BB0 0BBF +TAMIL SYLLABLE RII; 0BB0 0BC0 +TAMIL SYLLABLE RU; 0BB0 0BC1 +TAMIL SYLLABLE RUU; 0BB0 0BC2 +TAMIL SYLLABLE RE; 0BB0 0BC6 +TAMIL SYLLABLE REE; 0BB0 0BC7 +TAMIL SYLLABLE RAI; 0BB0 0BC8 +TAMIL SYLLABLE RO; 0BB0 0BCA +TAMIL SYLLABLE ROO; 0BB0 0BCB +TAMIL SYLLABLE RAU; 0BB0 0BCC + +TAMIL SYLLABLE LAA; 0BB2 0BBE +TAMIL SYLLABLE LI; 0BB2 0BBF +TAMIL SYLLABLE LII; 0BB2 0BC0 +TAMIL SYLLABLE LU; 0BB2 0BC1 +TAMIL SYLLABLE LUU; 0BB2 0BC2 +TAMIL SYLLABLE LE; 0BB2 0BC6 +TAMIL SYLLABLE LEE; 0BB2 0BC7 +TAMIL SYLLABLE LAI; 0BB2 0BC8 +TAMIL SYLLABLE LO; 0BB2 0BCA +TAMIL SYLLABLE LOO; 0BB2 0BCB +TAMIL SYLLABLE LAU; 0BB2 0BCC + +TAMIL SYLLABLE VAA; 0BB5 0BBE +TAMIL SYLLABLE VI; 0BB5 0BBF +TAMIL SYLLABLE VII; 0BB5 0BC0 +TAMIL SYLLABLE VU; 0BB5 0BC1 +TAMIL SYLLABLE VUU; 0BB5 0BC2 +TAMIL SYLLABLE VE; 0BB5 0BC6 +TAMIL SYLLABLE VEE; 0BB5 0BC7 +TAMIL SYLLABLE VAI; 0BB5 0BC8 +TAMIL SYLLABLE VO; 0BB5 0BCA +TAMIL SYLLABLE VOO; 0BB5 0BCB +TAMIL SYLLABLE VAU; 0BB5 0BCC + +TAMIL SYLLABLE LLLAA; 0BB4 0BBE +TAMIL SYLLABLE LLLI; 0BB4 0BBF +TAMIL SYLLABLE LLLII; 0BB4 0BC0 +TAMIL SYLLABLE LLLU; 0BB4 0BC1 +TAMIL SYLLABLE LLLUU; 0BB4 0BC2 +TAMIL SYLLABLE LLLE; 0BB4 0BC6 +TAMIL SYLLABLE LLLEE; 0BB4 0BC7 +TAMIL SYLLABLE LLLAI; 0BB4 0BC8 +TAMIL SYLLABLE LLLO; 0BB4 0BCA +TAMIL SYLLABLE LLLOO; 0BB4 0BCB +TAMIL SYLLABLE LLLAU; 0BB4 0BCC + +TAMIL SYLLABLE LLAA; 0BB3 0BBE +TAMIL SYLLABLE LLI; 0BB3 0BBF +TAMIL SYLLABLE LLII; 0BB3 0BC0 +TAMIL SYLLABLE LLU; 0BB3 0BC1 +TAMIL SYLLABLE LLUU; 0BB3 0BC2 +TAMIL SYLLABLE LLE; 0BB3 0BC6 +TAMIL SYLLABLE LLEE; 0BB3 0BC7 +TAMIL SYLLABLE LLAI; 0BB3 0BC8 +TAMIL SYLLABLE LLO; 0BB3 0BCA +TAMIL SYLLABLE LLOO; 0BB3 0BCB +TAMIL SYLLABLE LLAU; 0BB3 0BCC + +TAMIL SYLLABLE RRAA; 0BB1 0BBE +TAMIL SYLLABLE RRI; 0BB1 0BBF +TAMIL SYLLABLE RRII; 0BB1 0BC0 +TAMIL SYLLABLE RRU; 0BB1 0BC1 +TAMIL SYLLABLE RRUU; 0BB1 0BC2 +TAMIL SYLLABLE RRE; 0BB1 0BC6 +TAMIL SYLLABLE RREE; 0BB1 0BC7 +TAMIL SYLLABLE RRAI; 0BB1 0BC8 +TAMIL SYLLABLE RRO; 0BB1 0BCA +TAMIL SYLLABLE RROO; 0BB1 0BCB +TAMIL SYLLABLE RRAU; 0BB1 0BCC + +TAMIL SYLLABLE NNNAA; 0BA9 0BBE +TAMIL SYLLABLE NNNI; 0BA9 0BBF +TAMIL SYLLABLE NNNII; 0BA9 0BC0 +TAMIL SYLLABLE NNNU; 0BA9 0BC1 +TAMIL SYLLABLE NNNUU; 0BA9 0BC2 +TAMIL SYLLABLE NNNE; 0BA9 0BC6 +TAMIL SYLLABLE NNNEE; 0BA9 0BC7 +TAMIL SYLLABLE NNNAI; 0BA9 0BC8 +TAMIL SYLLABLE NNNO; 0BA9 0BCA +TAMIL SYLLABLE NNNOO; 0BA9 0BCB +TAMIL SYLLABLE NNNAU; 0BA9 0BCC + +TAMIL SYLLABLE JAA; 0B9C 0BBE +TAMIL SYLLABLE JI; 0B9C 0BBF +TAMIL SYLLABLE JII; 0B9C 0BC0 +TAMIL SYLLABLE JU; 0B9C 0BC1 +TAMIL SYLLABLE JUU; 0B9C 0BC2 +TAMIL SYLLABLE JE; 0B9C 0BC6 +TAMIL SYLLABLE JEE; 0B9C 0BC7 +TAMIL SYLLABLE JAI; 0B9C 0BC8 +TAMIL SYLLABLE JO; 0B9C 0BCA +TAMIL SYLLABLE JOO; 0B9C 0BCB +TAMIL SYLLABLE JAU; 0B9C 0BCC + +TAMIL SYLLABLE SHAA; 0BB6 0BBE +TAMIL SYLLABLE SHI; 0BB6 0BBF +TAMIL SYLLABLE SHII; 0BB6 0BC0 +TAMIL SYLLABLE SHU; 0BB6 0BC1 +TAMIL SYLLABLE SHUU; 0BB6 0BC2 +TAMIL SYLLABLE SHE; 0BB6 0BC6 +TAMIL SYLLABLE SHEE; 0BB6 0BC7 +TAMIL SYLLABLE SHAI; 0BB6 0BC8 +TAMIL SYLLABLE SHO; 0BB6 0BCA +TAMIL SYLLABLE SHOO; 0BB6 0BCB +TAMIL SYLLABLE SHAU; 0BB6 0BCC + +TAMIL SYLLABLE SSAA; 0BB7 0BBE +TAMIL SYLLABLE SSI; 0BB7 0BBF +TAMIL SYLLABLE SSII; 0BB7 0BC0 +TAMIL SYLLABLE SSU; 0BB7 0BC1 +TAMIL SYLLABLE SSUU; 0BB7 0BC2 +TAMIL SYLLABLE SSE; 0BB7 0BC6 +TAMIL SYLLABLE SSEE; 0BB7 0BC7 +TAMIL SYLLABLE SSAI; 0BB7 0BC8 +TAMIL SYLLABLE SSO; 0BB7 0BCA +TAMIL SYLLABLE SSOO; 0BB7 0BCB +TAMIL SYLLABLE SSAU; 0BB7 0BCC + +TAMIL SYLLABLE SAA; 0BB8 0BBE +TAMIL SYLLABLE SI; 0BB8 0BBF +TAMIL SYLLABLE SII; 0BB8 0BC0 +TAMIL SYLLABLE SU; 0BB8 0BC1 +TAMIL SYLLABLE SUU; 0BB8 0BC2 +TAMIL SYLLABLE SE; 0BB8 0BC6 +TAMIL SYLLABLE SEE; 0BB8 0BC7 +TAMIL SYLLABLE SAI; 0BB8 0BC8 +TAMIL SYLLABLE SO; 0BB8 0BCA +TAMIL SYLLABLE SOO; 0BB8 0BCB +TAMIL SYLLABLE SAU; 0BB8 0BCC + +TAMIL SYLLABLE HAA; 0BB9 0BBE +TAMIL SYLLABLE HI; 0BB9 0BBF +TAMIL SYLLABLE HII; 0BB9 0BC0 +TAMIL SYLLABLE HU; 0BB9 0BC1 +TAMIL SYLLABLE HUU; 0BB9 0BC2 +TAMIL SYLLABLE HE; 0BB9 0BC6 +TAMIL SYLLABLE HEE; 0BB9 0BC7 +TAMIL SYLLABLE HAI; 0BB9 0BC8 +TAMIL SYLLABLE HO; 0BB9 0BCA +TAMIL SYLLABLE HOO; 0BB9 0BCB +TAMIL SYLLABLE HAU; 0BB9 0BCC + +TAMIL SYLLABLE KSSA; 0B95 0BCD 0BB7 +TAMIL SYLLABLE KSSAA; 0B95 0BCD 0BB7 0BBE +TAMIL SYLLABLE KSSI; 0B95 0BCD 0BB7 0BBF +TAMIL SYLLABLE KSSII; 0B95 0BCD 0BB7 0BC0 +TAMIL SYLLABLE KSSU; 0B95 0BCD 0BB7 0BC1 +TAMIL SYLLABLE KSSUU; 0B95 0BCD 0BB7 0BC2 +TAMIL SYLLABLE KSSE; 0B95 0BCD 0BB7 0BC6 +TAMIL SYLLABLE KSSEE; 0B95 0BCD 0BB7 0BC7 +TAMIL SYLLABLE KSSAI; 0B95 0BCD 0BB7 0BC8 +TAMIL SYLLABLE KSSO; 0B95 0BCD 0BB7 0BCA +TAMIL SYLLABLE KSSOO; 0B95 0BCD 0BB7 0BCB +TAMIL SYLLABLE KSSAU; 0B95 0BCD 0BB7 0BCC + +TAMIL SYLLABLE SHRII; 0BB6 0BCD 0BB0 0BC0 + +# Sinhala medial consonants and "reph" form. +# Provisional 2010-05-13, Approved 2011-08-05 + +SINHALA CONSONANT SIGN YANSAYA;0DCA 200D 0DBA +SINHALA CONSONANT SIGN RAKAARAANSAYA;0DCA 200D 0DBB +SINHALA CONSONANT SIGN REPAYA;0DBB 0DCA 200D + +# Georgian letter plus accent sequence. +# This is part of the original set of approved named sequences +# for Unicode 4.1. 2005. + +GEORGIAN LETTER U-BRJGU;10E3 0302 + +# Khmer subjoined forms and other sequences. +# These are part of the original set of approved named sequences +# for Unicode 4.1. 2005. + +KHMER CONSONANT SIGN COENG KA;17D2 1780 +KHMER CONSONANT SIGN COENG KHA;17D2 1781 +KHMER CONSONANT SIGN COENG KO;17D2 1782 +KHMER CONSONANT SIGN COENG KHO;17D2 1783 +KHMER CONSONANT SIGN COENG NGO;17D2 1784 +KHMER CONSONANT SIGN COENG CA;17D2 1785 +KHMER CONSONANT SIGN COENG CHA;17D2 1786 +KHMER CONSONANT SIGN COENG CO;17D2 1787 +KHMER CONSONANT SIGN COENG CHO;17D2 1788 +KHMER CONSONANT SIGN COENG NYO;17D2 1789 +KHMER CONSONANT SIGN COENG DA;17D2 178A +KHMER CONSONANT SIGN COENG TTHA;17D2 178B +KHMER CONSONANT SIGN COENG DO;17D2 178C +KHMER CONSONANT SIGN COENG TTHO;17D2 178D +KHMER CONSONANT SIGN COENG NA;17D2 178E +KHMER CONSONANT SIGN COENG TA;17D2 178F +KHMER CONSONANT SIGN COENG THA;17D2 1790 +KHMER CONSONANT SIGN COENG TO;17D2 1791 +KHMER CONSONANT SIGN COENG THO;17D2 1792 +KHMER CONSONANT SIGN COENG NO;17D2 1793 +KHMER CONSONANT SIGN COENG BA;17D2 1794 +KHMER CONSONANT SIGN COENG PHA;17D2 1795 +KHMER CONSONANT SIGN COENG PO;17D2 1796 +KHMER CONSONANT SIGN COENG PHO;17D2 1797 +KHMER CONSONANT SIGN COENG MO;17D2 1798 +KHMER CONSONANT SIGN COENG YO;17D2 1799 +KHMER CONSONANT SIGN COENG RO;17D2 179A +KHMER CONSONANT SIGN COENG LO;17D2 179B +KHMER CONSONANT SIGN COENG VO;17D2 179C +KHMER CONSONANT SIGN COENG SHA;17D2 179D +KHMER CONSONANT SIGN COENG SSA;17D2 179E +KHMER CONSONANT SIGN COENG SA;17D2 179F +KHMER CONSONANT SIGN COENG HA;17D2 17A0 +KHMER CONSONANT SIGN COENG LA;17D2 17A1 +KHMER VOWEL SIGN COENG QA;17D2 17A2 +KHMER INDEPENDENT VOWEL SIGN COENG QU;17D2 17A7 +KHMER INDEPENDENT VOWEL SIGN COENG RY;17D2 17AB +KHMER INDEPENDENT VOWEL SIGN COENG RYY;17D2 17AC +KHMER INDEPENDENT VOWEL SIGN COENG QE;17D2 17AF +KHMER VOWEL SIGN OM;17BB 17C6 +KHMER VOWEL SIGN AAM;17B6 17C6 + +# Entries for JIS X 0213 compatibility mapping. +# Provisional 2008-11-07, Approved 2010-05-14 +# +# Two of these were part of the original set of approved named sequences +# for Unicode 4.1. 2005. + +HIRAGANA LETTER BIDAKUON NGA;304B 309A +HIRAGANA LETTER BIDAKUON NGI;304D 309A +HIRAGANA LETTER BIDAKUON NGU;304F 309A +HIRAGANA LETTER BIDAKUON NGE;3051 309A +HIRAGANA LETTER BIDAKUON NGO;3053 309A +KATAKANA LETTER BIDAKUON NGA;30AB 309A +KATAKANA LETTER BIDAKUON NGI;30AD 309A +KATAKANA LETTER BIDAKUON NGU;30AF 309A +KATAKANA LETTER BIDAKUON NGE;30B1 309A +KATAKANA LETTER BIDAKUON NGO;30B3 309A +KATAKANA LETTER AINU CE;30BB 309A +KATAKANA LETTER AINU TU;30C4 309A +KATAKANA LETTER AINU TO;30C8 309A +KATAKANA LETTER AINU P;31F7 309A +MODIFIER LETTER EXTRA-HIGH EXTRA-LOW CONTOUR TONE BAR;02E5 02E9 +MODIFIER LETTER EXTRA-LOW EXTRA-HIGH CONTOUR TONE BAR;02E9 02E5 + +# EOF diff --git a/uax34/README.md b/uax34/README.md new file mode 100644 index 0000000..7cd34d3 --- /dev/null +++ b/uax34/README.md @@ -0,0 +1,97 @@ +# UAX #34: Unicode Named Character Sequences + +Implementation of [UAX #34 (Unicode Named Character Sequences)](https://www.unicode.org/reports/tr34/) for resolving the unique names assigned to sequences of two or more code points. + +## Overview + +A *Named Character Sequence* assigns a unique name to a sequence of two or more code points. Names use the same restricted character set as Unicode character names (`A-Z`, `0-9`, space, and hyphen). For example, the name `KEYCAP NUMBER SIGN` denotes the three code point sequence `U+0023 U+FE0F U+20E3`. + +This package provides forward lookup (name → sequence), reverse lookup (sequence → name), and iteration over the full set, backed by a generated table from the normative `NamedSequences.txt`. + +## Installation + +```bash +go get github.com/SCKelemen/unicode/v6/uax34 +``` + +## Quick Start + +```go +package main + +import ( + "fmt" + + "github.com/SCKelemen/unicode/v6/uax34" +) + +func main() { + // Resolve a name to its code point sequence. + seq, ok := uax34.Lookup("KEYCAP NUMBER SIGN") + fmt.Println(seq, ok) // [35 65039 8419] true + + // Resolve a code point sequence back to its name. + name, ok := uax34.Name([]rune{0x0023, 0xFE0F, 0x20E3}) + fmt.Println(name, ok) // KEYCAP NUMBER SIGN true + + // Total number of named sequences. + fmt.Println(uax34.Count()) // 461 + + // Iterate over every named sequence, sorted by name. + for _, s := range uax34.All() { + fmt.Println(s.Name, s.Runes) + } +} +``` + +## API Reference + +#### `Lookup(name string) (seq []rune, ok bool)` +Returns the code point sequence for the named character sequence with the given name. The returned slice is a copy. `ok` reports whether `name` is a defined Named Character Sequence. + +#### `Name(seq []rune) (name string, ok bool)` +Returns the unique name of the given code point sequence. The match must be exact: proper prefixes and supersequences do not match. + +#### `Count() int` +Returns the number of Named Character Sequences. + +#### `All() []Sequence` +Returns every Named Character Sequence, sorted ascending by name. The returned slices are copies. + +```go +type Sequence struct { + Name string // unique name (A-Z, 0-9, space, hyphen) + Runes []rune // the code point sequence the name denotes +} +``` + +## Semantics + +In `NamedSequences.txt` every name is unique and, for a given Unicode version, each code point sequence maps to exactly one name. `Lookup` and `Name` therefore form a bijection between names and sequences. The generator verifies this invariant when the table is built and fails loudly if a future data file ever violates it. + +The provisional file `NamedSequencesProv.txt` is **not** normative and is intentionally excluded. + +## Conformance + +This implementation follows UAX #34 and is built from Unicode 17.0.0 data: + +- Data source: [`NamedSequences.txt`](https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt) (461 named sequences) +- `TestDataFileConsistency` validates the generated table against the committed `NamedSequences.txt`. +- `TestOfficialNamedSequences` downloads the official file and verifies every entry round-trips through `Lookup` and `Name`. + +## Code Generation + +The `named_sequences_data.go` file is generated from Unicode data: + +```bash +cd uax34 +go run generate_named_sequences.go +``` + +The generator is version-pinned to Unicode 17.0.0, produces deterministic (name-sorted) output, and formats the result with `go/format`. It has no external dependencies. + +## References + +- [UAX #34: Unicode Named Character Sequences](https://www.unicode.org/reports/tr34/) +- [NamedSequences.txt](https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt) +- [UAX #44: Unicode Character Database](https://www.unicode.org/reports/tr44/) diff --git a/uax34/example_test.go b/uax34/example_test.go new file mode 100644 index 0000000..653fd9f --- /dev/null +++ b/uax34/example_test.go @@ -0,0 +1,24 @@ +package uax34_test + +import ( + "fmt" + + "github.com/SCKelemen/unicode/v6/uax34" +) + +func ExampleLookup() { + seq, ok := uax34.Lookup("KEYCAP NUMBER SIGN") + fmt.Printf("%v %t\n", seq, ok) + // Output: [35 65039 8419] true +} + +func ExampleName() { + name, ok := uax34.Name([]rune{0x0023, 0xFE0F, 0x20E3}) + fmt.Printf("%q %t\n", name, ok) + // Output: "KEYCAP NUMBER SIGN" true +} + +func ExampleCount() { + fmt.Println(uax34.Count()) + // Output: 461 +} diff --git a/uax34/generate_named_sequences.go b/uax34/generate_named_sequences.go new file mode 100644 index 0000000..94cd6d3 --- /dev/null +++ b/uax34/generate_named_sequences.go @@ -0,0 +1,181 @@ +//go:build ignore +// +build ignore + +// This program generates named_sequences_data.go from NamedSequences.txt. +// Run with: go run generate_named_sequences.go +// +// NamedSequences-17.0.0.txt format (after stripping '#' comments): +// +// KEYCAP NUMBER SIGN;0023 FE0F 20E3 +// LATIN SMALL LETTER A WITH MACRON AND GRAVE;0101 0300 +// +// Field 0: the name of the sequence (A-Z, 0-9, space, hyphen). +// Field 1: the code point sequence (two or more space-separated hex values). +// +// Only the normative NamedSequences.txt is processed. The provisional file +// NamedSequencesProv.txt is intentionally ignored, per UAX #34. +// +// Reference: https://www.unicode.org/reports/tr34/ +package main + +import ( + "bufio" + "bytes" + "fmt" + "go/format" + "io" + "log" + "net/http" + "os" + "sort" + "strconv" + "strings" +) + +const ( + namedSequencesURL = "https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt" + namedSequencesVersion = "17.0.0" +) + +type namedSequence struct { + name string + seq []rune +} + +func main() { + fmt.Println("Downloading Unicode NamedSequences data file...") + + entries, err := downloadAndParse(namedSequencesURL) + if err != nil { + fmt.Fprintf(os.Stderr, "Error parsing NamedSequences.txt: %v\n", err) + os.Exit(1) + } + + // Sort by name for deterministic, binary-searchable output. Names are + // unique in NamedSequences.txt, so name order is a total order. + sort.Slice(entries, func(i, j int) bool { + return entries[i].name < entries[j].name + }) + + fmt.Printf("Parsed %d named character sequences\n", len(entries)) + + if err := generateCode(entries); err != nil { + fmt.Fprintf(os.Stderr, "Error generating code: %v\n", err) + os.Exit(1) + } + fmt.Println("Successfully generated named_sequences_data.go") +} + +func downloadAndParse(url string) ([]namedSequence, error) { + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("download: %w", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("download: status %d", resp.StatusCode) + } + return parse(resp.Body) +} + +func parse(r io.Reader) ([]namedSequence, error) { + var entries []namedSequence + seenName := make(map[string]bool) + seenSeq := make(map[string]string) // sequence key -> first name, for verification + + scanner := bufio.NewScanner(r) + lineNum := 0 + for scanner.Scan() { + lineNum++ + raw := scanner.Text() + // Strip comments beginning with '#'. + if hash := strings.IndexByte(raw, '#'); hash >= 0 { + raw = raw[:hash] + } + line := strings.TrimSpace(raw) + if line == "" { + continue + } + + parts := strings.Split(line, ";") + if len(parts) < 2 { + continue + } + + name := strings.TrimSpace(parts[0]) + fields := strings.Fields(parts[1]) + if name == "" || len(fields) < 2 { + // Named sequences are, by definition, two or more code points. + log.Fatalf("line %d: malformed entry %q (need a name and >=2 code points)", lineNum, line) + } + + seq := make([]rune, 0, len(fields)) + for _, f := range fields { + v, err := strconv.ParseInt(f, 16, 32) + if err != nil { + log.Fatalf("line %d: bad code point %q: %v", lineNum, f, err) + } + seq = append(seq, rune(v)) + } + + // Names are the unique key of the file. Fail loudly if that ever changes. + if seenName[name] { + log.Fatalf("line %d: duplicate name %q — generator assumes unique names", lineNum, name) + } + seenName[name] = true + + // Verify the (sequence -> name) mapping is a bijection so reverse + // lookup is well defined. Fail loudly if a sequence is ever reused. + key := string(seq) + if prev, ok := seenSeq[key]; ok { + log.Fatalf("line %d: sequence for %q also names %q — reverse lookup would be ambiguous", lineNum, name, prev) + } + seenSeq[key] = name + + entries = append(entries, namedSequence{name: name, seq: seq}) + } + if err := scanner.Err(); err != nil { + return nil, err + } + return entries, nil +} + +func generateCode(entries []namedSequence) error { + var buf bytes.Buffer + + fmt.Fprintf(&buf, "// Code generated by generate_named_sequences.go. DO NOT EDIT.\n") + fmt.Fprintf(&buf, "// Source: Unicode NamedSequences-%s.txt\n", namedSequencesVersion) + fmt.Fprintf(&buf, "\npackage uax34\n\n") + + fmt.Fprintf(&buf, "// namedSequence pairs a Named Character Sequence name with its\n") + fmt.Fprintf(&buf, "// code point sequence (two or more code points).\n") + fmt.Fprintf(&buf, "type namedSequence struct {\n") + fmt.Fprintf(&buf, "\tname string\n") + fmt.Fprintf(&buf, "\tseq []rune\n") + fmt.Fprintf(&buf, "}\n\n") + + fmt.Fprintf(&buf, "// namedSequenceData lists every normative Named Character Sequence from\n") + fmt.Fprintf(&buf, "// NamedSequences.txt, sorted ascending by name so the table supports\n") + fmt.Fprintf(&buf, "// binary search and yields deterministic output. Names are unique and\n") + fmt.Fprintf(&buf, "// each sequence maps to exactly one name (a bijection).\n") + fmt.Fprintf(&buf, "// Total entries: %d\n", len(entries)) + fmt.Fprintf(&buf, "var namedSequenceData = []namedSequence{\n") + for _, e := range entries { + fmt.Fprintf(&buf, "\t{%q, []rune{", e.name) + for i, r := range e.seq { + if i > 0 { + fmt.Fprintf(&buf, ", ") + } + fmt.Fprintf(&buf, "0x%04X", r) + } + fmt.Fprintf(&buf, "}},\n") + } + fmt.Fprintf(&buf, "}\n") + + src, err := format.Source(buf.Bytes()) + if err != nil { + return fmt.Errorf("format generated source: %w", err) + } + + return os.WriteFile("named_sequences_data.go", src, 0o644) +} diff --git a/uax34/named_sequences_data.go b/uax34/named_sequences_data.go new file mode 100644 index 0000000..9cd1658 --- /dev/null +++ b/uax34/named_sequences_data.go @@ -0,0 +1,480 @@ +// Code generated by generate_named_sequences.go. DO NOT EDIT. +// Source: Unicode NamedSequences-17.0.0.txt + +package uax34 + +// namedSequence pairs a Named Character Sequence name with its +// code point sequence (two or more code points). +type namedSequence struct { + name string + seq []rune +} + +// namedSequenceData lists every normative Named Character Sequence from +// NamedSequences.txt, sorted ascending by name so the table supports +// binary search and yields deterministic output. Names are unique and +// each sequence maps to exactly one name (a bijection). +// Total entries: 461 +var namedSequenceData = []namedSequence{ + {"ARABIC SEQUENCE NOON WITH KEHEH", []rune{0x0646, 0x06A9}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH AE", []rune{0x0626, 0x06D5}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF", []rune{0x0626, 0x0627}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA", []rune{0x0626, 0x0649}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH E", []rune{0x0626, 0x06D0}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH OE", []rune{0x0626, 0x06C6}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH U", []rune{0x0626, 0x06C7}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH WAW", []rune{0x0626, 0x0648}}, + {"ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH YU", []rune{0x0626, 0x06C8}}, + {"BENGALI LETTER KHINYA", []rune{0x0995, 0x09CD, 0x09B7}}, + {"BENGALI SEQUENCE FOR LETTER RHA", []rune{0x09A2, 0x09BC}}, + {"BENGALI SEQUENCE FOR LETTER RRA", []rune{0x09A1, 0x09BC}}, + {"BENGALI SEQUENCE FOR LETTER YYA", []rune{0x09AF, 0x09BC}}, + {"DEVANAGARI SEQUENCE FOR LETTER DDDHA", []rune{0x0921, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER FA", []rune{0x092B, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER GHHA", []rune{0x0917, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER KHHA", []rune{0x0916, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER QA", []rune{0x0915, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER RHA", []rune{0x0922, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER YYA", []rune{0x092F, 0x093C}}, + {"DEVANAGARI SEQUENCE FOR LETTER ZA", []rune{0x091C, 0x093C}}, + {"GEORGIAN LETTER U-BRJGU", []rune{0x10E3, 0x0302}}, + {"GURMUKHI SEQUENCE FOR LETTER FA", []rune{0x0A2B, 0x0A3C}}, + {"GURMUKHI SEQUENCE FOR LETTER GHHA", []rune{0x0A17, 0x0A3C}}, + {"GURMUKHI SEQUENCE FOR LETTER KHHA", []rune{0x0A16, 0x0A3C}}, + {"GURMUKHI SEQUENCE FOR LETTER LLA", []rune{0x0A32, 0x0A3C}}, + {"GURMUKHI SEQUENCE FOR LETTER SHA", []rune{0x0A38, 0x0A3C}}, + {"GURMUKHI SEQUENCE FOR LETTER ZA", []rune{0x0A1C, 0x0A3C}}, + {"HIRAGANA LETTER BIDAKUON NGA", []rune{0x304B, 0x309A}}, + {"HIRAGANA LETTER BIDAKUON NGE", []rune{0x3051, 0x309A}}, + {"HIRAGANA LETTER BIDAKUON NGI", []rune{0x304D, 0x309A}}, + {"HIRAGANA LETTER BIDAKUON NGO", []rune{0x3053, 0x309A}}, + {"HIRAGANA LETTER BIDAKUON NGU", []rune{0x304F, 0x309A}}, + {"KATAKANA LETTER AINU CE", []rune{0x30BB, 0x309A}}, + {"KATAKANA LETTER AINU P", []rune{0x31F7, 0x309A}}, + {"KATAKANA LETTER AINU TO", []rune{0x30C8, 0x309A}}, + {"KATAKANA LETTER AINU TU", []rune{0x30C4, 0x309A}}, + {"KATAKANA LETTER BIDAKUON NGA", []rune{0x30AB, 0x309A}}, + {"KATAKANA LETTER BIDAKUON NGE", []rune{0x30B1, 0x309A}}, + {"KATAKANA LETTER BIDAKUON NGI", []rune{0x30AD, 0x309A}}, + {"KATAKANA LETTER BIDAKUON NGO", []rune{0x30B3, 0x309A}}, + {"KATAKANA LETTER BIDAKUON NGU", []rune{0x30AF, 0x309A}}, + {"KEYCAP ASTERISK", []rune{0x002A, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT EIGHT", []rune{0x0038, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT FIVE", []rune{0x0035, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT FOUR", []rune{0x0034, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT NINE", []rune{0x0039, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT ONE", []rune{0x0031, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT SEVEN", []rune{0x0037, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT SIX", []rune{0x0036, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT THREE", []rune{0x0033, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT TWO", []rune{0x0032, 0xFE0F, 0x20E3}}, + {"KEYCAP DIGIT ZERO", []rune{0x0030, 0xFE0F, 0x20E3}}, + {"KEYCAP NUMBER SIGN", []rune{0x0023, 0xFE0F, 0x20E3}}, + {"KHMER CONSONANT SIGN COENG BA", []rune{0x17D2, 0x1794}}, + {"KHMER CONSONANT SIGN COENG CA", []rune{0x17D2, 0x1785}}, + {"KHMER CONSONANT SIGN COENG CHA", []rune{0x17D2, 0x1786}}, + {"KHMER CONSONANT SIGN COENG CHO", []rune{0x17D2, 0x1788}}, + {"KHMER CONSONANT SIGN COENG CO", []rune{0x17D2, 0x1787}}, + {"KHMER CONSONANT SIGN COENG DA", []rune{0x17D2, 0x178A}}, + {"KHMER CONSONANT SIGN COENG DO", []rune{0x17D2, 0x178C}}, + {"KHMER CONSONANT SIGN COENG HA", []rune{0x17D2, 0x17A0}}, + {"KHMER CONSONANT SIGN COENG KA", []rune{0x17D2, 0x1780}}, + {"KHMER CONSONANT SIGN COENG KHA", []rune{0x17D2, 0x1781}}, + {"KHMER CONSONANT SIGN COENG KHO", []rune{0x17D2, 0x1783}}, + {"KHMER CONSONANT SIGN COENG KO", []rune{0x17D2, 0x1782}}, + {"KHMER CONSONANT SIGN COENG LA", []rune{0x17D2, 0x17A1}}, + {"KHMER CONSONANT SIGN COENG LO", []rune{0x17D2, 0x179B}}, + {"KHMER CONSONANT SIGN COENG MO", []rune{0x17D2, 0x1798}}, + {"KHMER CONSONANT SIGN COENG NA", []rune{0x17D2, 0x178E}}, + {"KHMER CONSONANT SIGN COENG NGO", []rune{0x17D2, 0x1784}}, + {"KHMER CONSONANT SIGN COENG NO", []rune{0x17D2, 0x1793}}, + {"KHMER CONSONANT SIGN COENG NYO", []rune{0x17D2, 0x1789}}, + {"KHMER CONSONANT SIGN COENG PHA", []rune{0x17D2, 0x1795}}, + {"KHMER CONSONANT SIGN COENG PHO", []rune{0x17D2, 0x1797}}, + {"KHMER CONSONANT SIGN COENG PO", []rune{0x17D2, 0x1796}}, + {"KHMER CONSONANT SIGN COENG RO", []rune{0x17D2, 0x179A}}, + {"KHMER CONSONANT SIGN COENG SA", []rune{0x17D2, 0x179F}}, + {"KHMER CONSONANT SIGN COENG SHA", []rune{0x17D2, 0x179D}}, + {"KHMER CONSONANT SIGN COENG SSA", []rune{0x17D2, 0x179E}}, + {"KHMER CONSONANT SIGN COENG TA", []rune{0x17D2, 0x178F}}, + {"KHMER CONSONANT SIGN COENG THA", []rune{0x17D2, 0x1790}}, + {"KHMER CONSONANT SIGN COENG THO", []rune{0x17D2, 0x1792}}, + {"KHMER CONSONANT SIGN COENG TO", []rune{0x17D2, 0x1791}}, + {"KHMER CONSONANT SIGN COENG TTHA", []rune{0x17D2, 0x178B}}, + {"KHMER CONSONANT SIGN COENG TTHO", []rune{0x17D2, 0x178D}}, + {"KHMER CONSONANT SIGN COENG VO", []rune{0x17D2, 0x179C}}, + {"KHMER CONSONANT SIGN COENG YO", []rune{0x17D2, 0x1799}}, + {"KHMER INDEPENDENT VOWEL SIGN COENG QE", []rune{0x17D2, 0x17AF}}, + {"KHMER INDEPENDENT VOWEL SIGN COENG QU", []rune{0x17D2, 0x17A7}}, + {"KHMER INDEPENDENT VOWEL SIGN COENG RY", []rune{0x17D2, 0x17AB}}, + {"KHMER INDEPENDENT VOWEL SIGN COENG RYY", []rune{0x17D2, 0x17AC}}, + {"KHMER VOWEL SIGN AAM", []rune{0x17B6, 0x17C6}}, + {"KHMER VOWEL SIGN COENG QA", []rune{0x17D2, 0x17A2}}, + {"KHMER VOWEL SIGN OM", []rune{0x17BB, 0x17C6}}, + {"LATIN CAPITAL LETTER A WITH MACRON AND GRAVE", []rune{0x0100, 0x0300}}, + {"LATIN CAPITAL LETTER A WITH OGONEK AND ACUTE", []rune{0x0104, 0x0301}}, + {"LATIN CAPITAL LETTER A WITH OGONEK AND TILDE", []rune{0x0104, 0x0303}}, + {"LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND CARON", []rune{0x00CA, 0x030C}}, + {"LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND MACRON", []rune{0x00CA, 0x0304}}, + {"LATIN CAPITAL LETTER E WITH DOT ABOVE AND ACUTE", []rune{0x0116, 0x0301}}, + {"LATIN CAPITAL LETTER E WITH DOT ABOVE AND TILDE", []rune{0x0116, 0x0303}}, + {"LATIN CAPITAL LETTER E WITH OGONEK AND ACUTE", []rune{0x0118, 0x0301}}, + {"LATIN CAPITAL LETTER E WITH OGONEK AND TILDE", []rune{0x0118, 0x0303}}, + {"LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW", []rune{0x0045, 0x0329}}, + {"LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND ACUTE", []rune{0x00C9, 0x0329}}, + {"LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND GRAVE", []rune{0x00C8, 0x0329}}, + {"LATIN CAPITAL LETTER I WITH MACRON AND GRAVE", []rune{0x012A, 0x0300}}, + {"LATIN CAPITAL LETTER I WITH OGONEK AND ACUTE", []rune{0x012E, 0x0301}}, + {"LATIN CAPITAL LETTER I WITH OGONEK AND TILDE", []rune{0x012E, 0x0303}}, + {"LATIN CAPITAL LETTER J WITH TILDE", []rune{0x004A, 0x0303}}, + {"LATIN CAPITAL LETTER L WITH TILDE", []rune{0x004C, 0x0303}}, + {"LATIN CAPITAL LETTER M WITH TILDE", []rune{0x004D, 0x0303}}, + {"LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW", []rune{0x004F, 0x0329}}, + {"LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND ACUTE", []rune{0x00D3, 0x0329}}, + {"LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND GRAVE", []rune{0x00D2, 0x0329}}, + {"LATIN CAPITAL LETTER R WITH TILDE", []rune{0x0052, 0x0303}}, + {"LATIN CAPITAL LETTER S WITH VERTICAL LINE BELOW", []rune{0x0053, 0x0329}}, + {"LATIN CAPITAL LETTER U WITH MACRON AND ACUTE", []rune{0x016A, 0x0301}}, + {"LATIN CAPITAL LETTER U WITH MACRON AND GRAVE", []rune{0x016A, 0x0300}}, + {"LATIN CAPITAL LETTER U WITH MACRON AND TILDE", []rune{0x016A, 0x0303}}, + {"LATIN CAPITAL LETTER U WITH OGONEK AND ACUTE", []rune{0x0172, 0x0301}}, + {"LATIN CAPITAL LETTER U WITH OGONEK AND TILDE", []rune{0x0172, 0x0303}}, + {"LATIN SMALL LETTER A WITH MACRON AND GRAVE", []rune{0x0101, 0x0300}}, + {"LATIN SMALL LETTER A WITH OGONEK AND ACUTE", []rune{0x0105, 0x0301}}, + {"LATIN SMALL LETTER A WITH OGONEK AND TILDE", []rune{0x0105, 0x0303}}, + {"LATIN SMALL LETTER AE WITH GRAVE", []rune{0x00E6, 0x0300}}, + {"LATIN SMALL LETTER E WITH CIRCUMFLEX AND CARON", []rune{0x00EA, 0x030C}}, + {"LATIN SMALL LETTER E WITH CIRCUMFLEX AND MACRON", []rune{0x00EA, 0x0304}}, + {"LATIN SMALL LETTER E WITH DOT ABOVE AND ACUTE", []rune{0x0117, 0x0301}}, + {"LATIN SMALL LETTER E WITH DOT ABOVE AND TILDE", []rune{0x0117, 0x0303}}, + {"LATIN SMALL LETTER E WITH OGONEK AND ACUTE", []rune{0x0119, 0x0301}}, + {"LATIN SMALL LETTER E WITH OGONEK AND TILDE", []rune{0x0119, 0x0303}}, + {"LATIN SMALL LETTER E WITH VERTICAL LINE BELOW", []rune{0x0065, 0x0329}}, + {"LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND ACUTE", []rune{0x00E9, 0x0329}}, + {"LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND GRAVE", []rune{0x00E8, 0x0329}}, + {"LATIN SMALL LETTER HOOKED SCHWA WITH ACUTE", []rune{0x025A, 0x0301}}, + {"LATIN SMALL LETTER HOOKED SCHWA WITH GRAVE", []rune{0x025A, 0x0300}}, + {"LATIN SMALL LETTER I WITH DOT ABOVE AND ACUTE", []rune{0x0069, 0x0307, 0x0301}}, + {"LATIN SMALL LETTER I WITH DOT ABOVE AND GRAVE", []rune{0x0069, 0x0307, 0x0300}}, + {"LATIN SMALL LETTER I WITH DOT ABOVE AND TILDE", []rune{0x0069, 0x0307, 0x0303}}, + {"LATIN SMALL LETTER I WITH MACRON AND GRAVE", []rune{0x012B, 0x0300}}, + {"LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND ACUTE", []rune{0x012F, 0x0307, 0x0301}}, + {"LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND TILDE", []rune{0x012F, 0x0307, 0x0303}}, + {"LATIN SMALL LETTER J WITH DOT ABOVE AND TILDE", []rune{0x006A, 0x0307, 0x0303}}, + {"LATIN SMALL LETTER L WITH TILDE", []rune{0x006C, 0x0303}}, + {"LATIN SMALL LETTER M WITH TILDE", []rune{0x006D, 0x0303}}, + {"LATIN SMALL LETTER NG WITH TILDE ABOVE", []rune{0x006E, 0x0360, 0x0067}}, + {"LATIN SMALL LETTER O WITH VERTICAL LINE BELOW", []rune{0x006F, 0x0329}}, + {"LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND ACUTE", []rune{0x00F3, 0x0329}}, + {"LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND GRAVE", []rune{0x00F2, 0x0329}}, + {"LATIN SMALL LETTER OPEN O WITH ACUTE", []rune{0x0254, 0x0301}}, + {"LATIN SMALL LETTER OPEN O WITH GRAVE", []rune{0x0254, 0x0300}}, + {"LATIN SMALL LETTER R WITH TILDE", []rune{0x0072, 0x0303}}, + {"LATIN SMALL LETTER S WITH VERTICAL LINE BELOW", []rune{0x0073, 0x0329}}, + {"LATIN SMALL LETTER SCHWA WITH ACUTE", []rune{0x0259, 0x0301}}, + {"LATIN SMALL LETTER SCHWA WITH GRAVE", []rune{0x0259, 0x0300}}, + {"LATIN SMALL LETTER TURNED V WITH ACUTE", []rune{0x028C, 0x0301}}, + {"LATIN SMALL LETTER TURNED V WITH GRAVE", []rune{0x028C, 0x0300}}, + {"LATIN SMALL LETTER U WITH MACRON AND ACUTE", []rune{0x016B, 0x0301}}, + {"LATIN SMALL LETTER U WITH MACRON AND GRAVE", []rune{0x016B, 0x0300}}, + {"LATIN SMALL LETTER U WITH MACRON AND TILDE", []rune{0x016B, 0x0303}}, + {"LATIN SMALL LETTER U WITH OGONEK AND ACUTE", []rune{0x0173, 0x0301}}, + {"LATIN SMALL LETTER U WITH OGONEK AND TILDE", []rune{0x0173, 0x0303}}, + {"MODIFIER LETTER EXTRA-HIGH EXTRA-LOW CONTOUR TONE BAR", []rune{0x02E5, 0x02E9}}, + {"MODIFIER LETTER EXTRA-LOW EXTRA-HIGH CONTOUR TONE BAR", []rune{0x02E9, 0x02E5}}, + {"ORIYA SEQUENCE FOR LETTER RHA", []rune{0x0B22, 0x0B3C}}, + {"ORIYA SEQUENCE FOR LETTER RRA", []rune{0x0B21, 0x0B3C}}, + {"SINHALA CONSONANT SIGN RAKAARAANSAYA", []rune{0x0DCA, 0x200D, 0x0DBB}}, + {"SINHALA CONSONANT SIGN REPAYA", []rune{0x0DBB, 0x0DCA, 0x200D}}, + {"SINHALA CONSONANT SIGN YANSAYA", []rune{0x0DCA, 0x200D, 0x0DBA}}, + {"TAMIL CONSONANT C", []rune{0x0B9A, 0x0BCD}}, + {"TAMIL CONSONANT H", []rune{0x0BB9, 0x0BCD}}, + {"TAMIL CONSONANT J", []rune{0x0B9C, 0x0BCD}}, + {"TAMIL CONSONANT K", []rune{0x0B95, 0x0BCD}}, + {"TAMIL CONSONANT KSS", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BCD}}, + {"TAMIL CONSONANT L", []rune{0x0BB2, 0x0BCD}}, + {"TAMIL CONSONANT LL", []rune{0x0BB3, 0x0BCD}}, + {"TAMIL CONSONANT LLL", []rune{0x0BB4, 0x0BCD}}, + {"TAMIL CONSONANT M", []rune{0x0BAE, 0x0BCD}}, + {"TAMIL CONSONANT N", []rune{0x0BA8, 0x0BCD}}, + {"TAMIL CONSONANT NG", []rune{0x0B99, 0x0BCD}}, + {"TAMIL CONSONANT NN", []rune{0x0BA3, 0x0BCD}}, + {"TAMIL CONSONANT NNN", []rune{0x0BA9, 0x0BCD}}, + {"TAMIL CONSONANT NY", []rune{0x0B9E, 0x0BCD}}, + {"TAMIL CONSONANT P", []rune{0x0BAA, 0x0BCD}}, + {"TAMIL CONSONANT R", []rune{0x0BB0, 0x0BCD}}, + {"TAMIL CONSONANT RR", []rune{0x0BB1, 0x0BCD}}, + {"TAMIL CONSONANT S", []rune{0x0BB8, 0x0BCD}}, + {"TAMIL CONSONANT SH", []rune{0x0BB6, 0x0BCD}}, + {"TAMIL CONSONANT SS", []rune{0x0BB7, 0x0BCD}}, + {"TAMIL CONSONANT T", []rune{0x0BA4, 0x0BCD}}, + {"TAMIL CONSONANT TT", []rune{0x0B9F, 0x0BCD}}, + {"TAMIL CONSONANT V", []rune{0x0BB5, 0x0BCD}}, + {"TAMIL CONSONANT Y", []rune{0x0BAF, 0x0BCD}}, + {"TAMIL SYLLABLE CAA", []rune{0x0B9A, 0x0BBE}}, + {"TAMIL SYLLABLE CAI", []rune{0x0B9A, 0x0BC8}}, + {"TAMIL SYLLABLE CAU", []rune{0x0B9A, 0x0BCC}}, + {"TAMIL SYLLABLE CE", []rune{0x0B9A, 0x0BC6}}, + {"TAMIL SYLLABLE CEE", []rune{0x0B9A, 0x0BC7}}, + {"TAMIL SYLLABLE CI", []rune{0x0B9A, 0x0BBF}}, + {"TAMIL SYLLABLE CII", []rune{0x0B9A, 0x0BC0}}, + {"TAMIL SYLLABLE CO", []rune{0x0B9A, 0x0BCA}}, + {"TAMIL SYLLABLE COO", []rune{0x0B9A, 0x0BCB}}, + {"TAMIL SYLLABLE CU", []rune{0x0B9A, 0x0BC1}}, + {"TAMIL SYLLABLE CUU", []rune{0x0B9A, 0x0BC2}}, + {"TAMIL SYLLABLE HAA", []rune{0x0BB9, 0x0BBE}}, + {"TAMIL SYLLABLE HAI", []rune{0x0BB9, 0x0BC8}}, + {"TAMIL SYLLABLE HAU", []rune{0x0BB9, 0x0BCC}}, + {"TAMIL SYLLABLE HE", []rune{0x0BB9, 0x0BC6}}, + {"TAMIL SYLLABLE HEE", []rune{0x0BB9, 0x0BC7}}, + {"TAMIL SYLLABLE HI", []rune{0x0BB9, 0x0BBF}}, + {"TAMIL SYLLABLE HII", []rune{0x0BB9, 0x0BC0}}, + {"TAMIL SYLLABLE HO", []rune{0x0BB9, 0x0BCA}}, + {"TAMIL SYLLABLE HOO", []rune{0x0BB9, 0x0BCB}}, + {"TAMIL SYLLABLE HU", []rune{0x0BB9, 0x0BC1}}, + {"TAMIL SYLLABLE HUU", []rune{0x0BB9, 0x0BC2}}, + {"TAMIL SYLLABLE JAA", []rune{0x0B9C, 0x0BBE}}, + {"TAMIL SYLLABLE JAI", []rune{0x0B9C, 0x0BC8}}, + {"TAMIL SYLLABLE JAU", []rune{0x0B9C, 0x0BCC}}, + {"TAMIL SYLLABLE JE", []rune{0x0B9C, 0x0BC6}}, + {"TAMIL SYLLABLE JEE", []rune{0x0B9C, 0x0BC7}}, + {"TAMIL SYLLABLE JI", []rune{0x0B9C, 0x0BBF}}, + {"TAMIL SYLLABLE JII", []rune{0x0B9C, 0x0BC0}}, + {"TAMIL SYLLABLE JO", []rune{0x0B9C, 0x0BCA}}, + {"TAMIL SYLLABLE JOO", []rune{0x0B9C, 0x0BCB}}, + {"TAMIL SYLLABLE JU", []rune{0x0B9C, 0x0BC1}}, + {"TAMIL SYLLABLE JUU", []rune{0x0B9C, 0x0BC2}}, + {"TAMIL SYLLABLE KAA", []rune{0x0B95, 0x0BBE}}, + {"TAMIL SYLLABLE KAI", []rune{0x0B95, 0x0BC8}}, + {"TAMIL SYLLABLE KAU", []rune{0x0B95, 0x0BCC}}, + {"TAMIL SYLLABLE KE", []rune{0x0B95, 0x0BC6}}, + {"TAMIL SYLLABLE KEE", []rune{0x0B95, 0x0BC7}}, + {"TAMIL SYLLABLE KI", []rune{0x0B95, 0x0BBF}}, + {"TAMIL SYLLABLE KII", []rune{0x0B95, 0x0BC0}}, + {"TAMIL SYLLABLE KO", []rune{0x0B95, 0x0BCA}}, + {"TAMIL SYLLABLE KOO", []rune{0x0B95, 0x0BCB}}, + {"TAMIL SYLLABLE KSSA", []rune{0x0B95, 0x0BCD, 0x0BB7}}, + {"TAMIL SYLLABLE KSSAA", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BBE}}, + {"TAMIL SYLLABLE KSSAI", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC8}}, + {"TAMIL SYLLABLE KSSAU", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BCC}}, + {"TAMIL SYLLABLE KSSE", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC6}}, + {"TAMIL SYLLABLE KSSEE", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC7}}, + {"TAMIL SYLLABLE KSSI", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BBF}}, + {"TAMIL SYLLABLE KSSII", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC0}}, + {"TAMIL SYLLABLE KSSO", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BCA}}, + {"TAMIL SYLLABLE KSSOO", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BCB}}, + {"TAMIL SYLLABLE KSSU", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC1}}, + {"TAMIL SYLLABLE KSSUU", []rune{0x0B95, 0x0BCD, 0x0BB7, 0x0BC2}}, + {"TAMIL SYLLABLE KU", []rune{0x0B95, 0x0BC1}}, + {"TAMIL SYLLABLE KUU", []rune{0x0B95, 0x0BC2}}, + {"TAMIL SYLLABLE LAA", []rune{0x0BB2, 0x0BBE}}, + {"TAMIL SYLLABLE LAI", []rune{0x0BB2, 0x0BC8}}, + {"TAMIL SYLLABLE LAU", []rune{0x0BB2, 0x0BCC}}, + {"TAMIL SYLLABLE LE", []rune{0x0BB2, 0x0BC6}}, + {"TAMIL SYLLABLE LEE", []rune{0x0BB2, 0x0BC7}}, + {"TAMIL SYLLABLE LI", []rune{0x0BB2, 0x0BBF}}, + {"TAMIL SYLLABLE LII", []rune{0x0BB2, 0x0BC0}}, + {"TAMIL SYLLABLE LLAA", []rune{0x0BB3, 0x0BBE}}, + {"TAMIL SYLLABLE LLAI", []rune{0x0BB3, 0x0BC8}}, + {"TAMIL SYLLABLE LLAU", []rune{0x0BB3, 0x0BCC}}, + {"TAMIL SYLLABLE LLE", []rune{0x0BB3, 0x0BC6}}, + {"TAMIL SYLLABLE LLEE", []rune{0x0BB3, 0x0BC7}}, + {"TAMIL SYLLABLE LLI", []rune{0x0BB3, 0x0BBF}}, + {"TAMIL SYLLABLE LLII", []rune{0x0BB3, 0x0BC0}}, + {"TAMIL SYLLABLE LLLAA", []rune{0x0BB4, 0x0BBE}}, + {"TAMIL SYLLABLE LLLAI", []rune{0x0BB4, 0x0BC8}}, + {"TAMIL SYLLABLE LLLAU", []rune{0x0BB4, 0x0BCC}}, + {"TAMIL SYLLABLE LLLE", []rune{0x0BB4, 0x0BC6}}, + {"TAMIL SYLLABLE LLLEE", []rune{0x0BB4, 0x0BC7}}, + {"TAMIL SYLLABLE LLLI", []rune{0x0BB4, 0x0BBF}}, + {"TAMIL SYLLABLE LLLII", []rune{0x0BB4, 0x0BC0}}, + {"TAMIL SYLLABLE LLLO", []rune{0x0BB4, 0x0BCA}}, + {"TAMIL SYLLABLE LLLOO", []rune{0x0BB4, 0x0BCB}}, + {"TAMIL SYLLABLE LLLU", []rune{0x0BB4, 0x0BC1}}, + {"TAMIL SYLLABLE LLLUU", []rune{0x0BB4, 0x0BC2}}, + {"TAMIL SYLLABLE LLO", []rune{0x0BB3, 0x0BCA}}, + {"TAMIL SYLLABLE LLOO", []rune{0x0BB3, 0x0BCB}}, + {"TAMIL SYLLABLE LLU", []rune{0x0BB3, 0x0BC1}}, + {"TAMIL SYLLABLE LLUU", []rune{0x0BB3, 0x0BC2}}, + {"TAMIL SYLLABLE LO", []rune{0x0BB2, 0x0BCA}}, + {"TAMIL SYLLABLE LOO", []rune{0x0BB2, 0x0BCB}}, + {"TAMIL SYLLABLE LU", []rune{0x0BB2, 0x0BC1}}, + {"TAMIL SYLLABLE LUU", []rune{0x0BB2, 0x0BC2}}, + {"TAMIL SYLLABLE MAA", []rune{0x0BAE, 0x0BBE}}, + {"TAMIL SYLLABLE MAI", []rune{0x0BAE, 0x0BC8}}, + {"TAMIL SYLLABLE MAU", []rune{0x0BAE, 0x0BCC}}, + {"TAMIL SYLLABLE ME", []rune{0x0BAE, 0x0BC6}}, + {"TAMIL SYLLABLE MEE", []rune{0x0BAE, 0x0BC7}}, + {"TAMIL SYLLABLE MI", []rune{0x0BAE, 0x0BBF}}, + {"TAMIL SYLLABLE MII", []rune{0x0BAE, 0x0BC0}}, + {"TAMIL SYLLABLE MO", []rune{0x0BAE, 0x0BCA}}, + {"TAMIL SYLLABLE MOO", []rune{0x0BAE, 0x0BCB}}, + {"TAMIL SYLLABLE MU", []rune{0x0BAE, 0x0BC1}}, + {"TAMIL SYLLABLE MUU", []rune{0x0BAE, 0x0BC2}}, + {"TAMIL SYLLABLE NAA", []rune{0x0BA8, 0x0BBE}}, + {"TAMIL SYLLABLE NAI", []rune{0x0BA8, 0x0BC8}}, + {"TAMIL SYLLABLE NAU", []rune{0x0BA8, 0x0BCC}}, + {"TAMIL SYLLABLE NE", []rune{0x0BA8, 0x0BC6}}, + {"TAMIL SYLLABLE NEE", []rune{0x0BA8, 0x0BC7}}, + {"TAMIL SYLLABLE NGAA", []rune{0x0B99, 0x0BBE}}, + {"TAMIL SYLLABLE NGAI", []rune{0x0B99, 0x0BC8}}, + {"TAMIL SYLLABLE NGAU", []rune{0x0B99, 0x0BCC}}, + {"TAMIL SYLLABLE NGE", []rune{0x0B99, 0x0BC6}}, + {"TAMIL SYLLABLE NGEE", []rune{0x0B99, 0x0BC7}}, + {"TAMIL SYLLABLE NGI", []rune{0x0B99, 0x0BBF}}, + {"TAMIL SYLLABLE NGII", []rune{0x0B99, 0x0BC0}}, + {"TAMIL SYLLABLE NGO", []rune{0x0B99, 0x0BCA}}, + {"TAMIL SYLLABLE NGOO", []rune{0x0B99, 0x0BCB}}, + {"TAMIL SYLLABLE NGU", []rune{0x0B99, 0x0BC1}}, + {"TAMIL SYLLABLE NGUU", []rune{0x0B99, 0x0BC2}}, + {"TAMIL SYLLABLE NI", []rune{0x0BA8, 0x0BBF}}, + {"TAMIL SYLLABLE NII", []rune{0x0BA8, 0x0BC0}}, + {"TAMIL SYLLABLE NNAA", []rune{0x0BA3, 0x0BBE}}, + {"TAMIL SYLLABLE NNAI", []rune{0x0BA3, 0x0BC8}}, + {"TAMIL SYLLABLE NNAU", []rune{0x0BA3, 0x0BCC}}, + {"TAMIL SYLLABLE NNE", []rune{0x0BA3, 0x0BC6}}, + {"TAMIL SYLLABLE NNEE", []rune{0x0BA3, 0x0BC7}}, + {"TAMIL SYLLABLE NNI", []rune{0x0BA3, 0x0BBF}}, + {"TAMIL SYLLABLE NNII", []rune{0x0BA3, 0x0BC0}}, + {"TAMIL SYLLABLE NNNAA", []rune{0x0BA9, 0x0BBE}}, + {"TAMIL SYLLABLE NNNAI", []rune{0x0BA9, 0x0BC8}}, + {"TAMIL SYLLABLE NNNAU", []rune{0x0BA9, 0x0BCC}}, + {"TAMIL SYLLABLE NNNE", []rune{0x0BA9, 0x0BC6}}, + {"TAMIL SYLLABLE NNNEE", []rune{0x0BA9, 0x0BC7}}, + {"TAMIL SYLLABLE NNNI", []rune{0x0BA9, 0x0BBF}}, + {"TAMIL SYLLABLE NNNII", []rune{0x0BA9, 0x0BC0}}, + {"TAMIL SYLLABLE NNNO", []rune{0x0BA9, 0x0BCA}}, + {"TAMIL SYLLABLE NNNOO", []rune{0x0BA9, 0x0BCB}}, + {"TAMIL SYLLABLE NNNU", []rune{0x0BA9, 0x0BC1}}, + {"TAMIL SYLLABLE NNNUU", []rune{0x0BA9, 0x0BC2}}, + {"TAMIL SYLLABLE NNO", []rune{0x0BA3, 0x0BCA}}, + {"TAMIL SYLLABLE NNOO", []rune{0x0BA3, 0x0BCB}}, + {"TAMIL SYLLABLE NNU", []rune{0x0BA3, 0x0BC1}}, + {"TAMIL SYLLABLE NNUU", []rune{0x0BA3, 0x0BC2}}, + {"TAMIL SYLLABLE NO", []rune{0x0BA8, 0x0BCA}}, + {"TAMIL SYLLABLE NOO", []rune{0x0BA8, 0x0BCB}}, + {"TAMIL SYLLABLE NU", []rune{0x0BA8, 0x0BC1}}, + {"TAMIL SYLLABLE NUU", []rune{0x0BA8, 0x0BC2}}, + {"TAMIL SYLLABLE NYAA", []rune{0x0B9E, 0x0BBE}}, + {"TAMIL SYLLABLE NYAI", []rune{0x0B9E, 0x0BC8}}, + {"TAMIL SYLLABLE NYAU", []rune{0x0B9E, 0x0BCC}}, + {"TAMIL SYLLABLE NYE", []rune{0x0B9E, 0x0BC6}}, + {"TAMIL SYLLABLE NYEE", []rune{0x0B9E, 0x0BC7}}, + {"TAMIL SYLLABLE NYI", []rune{0x0B9E, 0x0BBF}}, + {"TAMIL SYLLABLE NYII", []rune{0x0B9E, 0x0BC0}}, + {"TAMIL SYLLABLE NYO", []rune{0x0B9E, 0x0BCA}}, + {"TAMIL SYLLABLE NYOO", []rune{0x0B9E, 0x0BCB}}, + {"TAMIL SYLLABLE NYU", []rune{0x0B9E, 0x0BC1}}, + {"TAMIL SYLLABLE NYUU", []rune{0x0B9E, 0x0BC2}}, + {"TAMIL SYLLABLE PAA", []rune{0x0BAA, 0x0BBE}}, + {"TAMIL SYLLABLE PAI", []rune{0x0BAA, 0x0BC8}}, + {"TAMIL SYLLABLE PAU", []rune{0x0BAA, 0x0BCC}}, + {"TAMIL SYLLABLE PE", []rune{0x0BAA, 0x0BC6}}, + {"TAMIL SYLLABLE PEE", []rune{0x0BAA, 0x0BC7}}, + {"TAMIL SYLLABLE PI", []rune{0x0BAA, 0x0BBF}}, + {"TAMIL SYLLABLE PII", []rune{0x0BAA, 0x0BC0}}, + {"TAMIL SYLLABLE PO", []rune{0x0BAA, 0x0BCA}}, + {"TAMIL SYLLABLE POO", []rune{0x0BAA, 0x0BCB}}, + {"TAMIL SYLLABLE PU", []rune{0x0BAA, 0x0BC1}}, + {"TAMIL SYLLABLE PUU", []rune{0x0BAA, 0x0BC2}}, + {"TAMIL SYLLABLE RAA", []rune{0x0BB0, 0x0BBE}}, + {"TAMIL SYLLABLE RAI", []rune{0x0BB0, 0x0BC8}}, + {"TAMIL SYLLABLE RAU", []rune{0x0BB0, 0x0BCC}}, + {"TAMIL SYLLABLE RE", []rune{0x0BB0, 0x0BC6}}, + {"TAMIL SYLLABLE REE", []rune{0x0BB0, 0x0BC7}}, + {"TAMIL SYLLABLE RI", []rune{0x0BB0, 0x0BBF}}, + {"TAMIL SYLLABLE RII", []rune{0x0BB0, 0x0BC0}}, + {"TAMIL SYLLABLE RO", []rune{0x0BB0, 0x0BCA}}, + {"TAMIL SYLLABLE ROO", []rune{0x0BB0, 0x0BCB}}, + {"TAMIL SYLLABLE RRAA", []rune{0x0BB1, 0x0BBE}}, + {"TAMIL SYLLABLE RRAI", []rune{0x0BB1, 0x0BC8}}, + {"TAMIL SYLLABLE RRAU", []rune{0x0BB1, 0x0BCC}}, + {"TAMIL SYLLABLE RRE", []rune{0x0BB1, 0x0BC6}}, + {"TAMIL SYLLABLE RREE", []rune{0x0BB1, 0x0BC7}}, + {"TAMIL SYLLABLE RRI", []rune{0x0BB1, 0x0BBF}}, + {"TAMIL SYLLABLE RRII", []rune{0x0BB1, 0x0BC0}}, + {"TAMIL SYLLABLE RRO", []rune{0x0BB1, 0x0BCA}}, + {"TAMIL SYLLABLE RROO", []rune{0x0BB1, 0x0BCB}}, + {"TAMIL SYLLABLE RRU", []rune{0x0BB1, 0x0BC1}}, + {"TAMIL SYLLABLE RRUU", []rune{0x0BB1, 0x0BC2}}, + {"TAMIL SYLLABLE RU", []rune{0x0BB0, 0x0BC1}}, + {"TAMIL SYLLABLE RUU", []rune{0x0BB0, 0x0BC2}}, + {"TAMIL SYLLABLE SAA", []rune{0x0BB8, 0x0BBE}}, + {"TAMIL SYLLABLE SAI", []rune{0x0BB8, 0x0BC8}}, + {"TAMIL SYLLABLE SAU", []rune{0x0BB8, 0x0BCC}}, + {"TAMIL SYLLABLE SE", []rune{0x0BB8, 0x0BC6}}, + {"TAMIL SYLLABLE SEE", []rune{0x0BB8, 0x0BC7}}, + {"TAMIL SYLLABLE SHAA", []rune{0x0BB6, 0x0BBE}}, + {"TAMIL SYLLABLE SHAI", []rune{0x0BB6, 0x0BC8}}, + {"TAMIL SYLLABLE SHAU", []rune{0x0BB6, 0x0BCC}}, + {"TAMIL SYLLABLE SHE", []rune{0x0BB6, 0x0BC6}}, + {"TAMIL SYLLABLE SHEE", []rune{0x0BB6, 0x0BC7}}, + {"TAMIL SYLLABLE SHI", []rune{0x0BB6, 0x0BBF}}, + {"TAMIL SYLLABLE SHII", []rune{0x0BB6, 0x0BC0}}, + {"TAMIL SYLLABLE SHO", []rune{0x0BB6, 0x0BCA}}, + {"TAMIL SYLLABLE SHOO", []rune{0x0BB6, 0x0BCB}}, + {"TAMIL SYLLABLE SHRII", []rune{0x0BB6, 0x0BCD, 0x0BB0, 0x0BC0}}, + {"TAMIL SYLLABLE SHU", []rune{0x0BB6, 0x0BC1}}, + {"TAMIL SYLLABLE SHUU", []rune{0x0BB6, 0x0BC2}}, + {"TAMIL SYLLABLE SI", []rune{0x0BB8, 0x0BBF}}, + {"TAMIL SYLLABLE SII", []rune{0x0BB8, 0x0BC0}}, + {"TAMIL SYLLABLE SO", []rune{0x0BB8, 0x0BCA}}, + {"TAMIL SYLLABLE SOO", []rune{0x0BB8, 0x0BCB}}, + {"TAMIL SYLLABLE SSAA", []rune{0x0BB7, 0x0BBE}}, + {"TAMIL SYLLABLE SSAI", []rune{0x0BB7, 0x0BC8}}, + {"TAMIL SYLLABLE SSAU", []rune{0x0BB7, 0x0BCC}}, + {"TAMIL SYLLABLE SSE", []rune{0x0BB7, 0x0BC6}}, + {"TAMIL SYLLABLE SSEE", []rune{0x0BB7, 0x0BC7}}, + {"TAMIL SYLLABLE SSI", []rune{0x0BB7, 0x0BBF}}, + {"TAMIL SYLLABLE SSII", []rune{0x0BB7, 0x0BC0}}, + {"TAMIL SYLLABLE SSO", []rune{0x0BB7, 0x0BCA}}, + {"TAMIL SYLLABLE SSOO", []rune{0x0BB7, 0x0BCB}}, + {"TAMIL SYLLABLE SSU", []rune{0x0BB7, 0x0BC1}}, + {"TAMIL SYLLABLE SSUU", []rune{0x0BB7, 0x0BC2}}, + {"TAMIL SYLLABLE SU", []rune{0x0BB8, 0x0BC1}}, + {"TAMIL SYLLABLE SUU", []rune{0x0BB8, 0x0BC2}}, + {"TAMIL SYLLABLE TAA", []rune{0x0BA4, 0x0BBE}}, + {"TAMIL SYLLABLE TAI", []rune{0x0BA4, 0x0BC8}}, + {"TAMIL SYLLABLE TAU", []rune{0x0BA4, 0x0BCC}}, + {"TAMIL SYLLABLE TE", []rune{0x0BA4, 0x0BC6}}, + {"TAMIL SYLLABLE TEE", []rune{0x0BA4, 0x0BC7}}, + {"TAMIL SYLLABLE TI", []rune{0x0BA4, 0x0BBF}}, + {"TAMIL SYLLABLE TII", []rune{0x0BA4, 0x0BC0}}, + {"TAMIL SYLLABLE TO", []rune{0x0BA4, 0x0BCA}}, + {"TAMIL SYLLABLE TOO", []rune{0x0BA4, 0x0BCB}}, + {"TAMIL SYLLABLE TTAA", []rune{0x0B9F, 0x0BBE}}, + {"TAMIL SYLLABLE TTAI", []rune{0x0B9F, 0x0BC8}}, + {"TAMIL SYLLABLE TTAU", []rune{0x0B9F, 0x0BCC}}, + {"TAMIL SYLLABLE TTE", []rune{0x0B9F, 0x0BC6}}, + {"TAMIL SYLLABLE TTEE", []rune{0x0B9F, 0x0BC7}}, + {"TAMIL SYLLABLE TTI", []rune{0x0B9F, 0x0BBF}}, + {"TAMIL SYLLABLE TTII", []rune{0x0B9F, 0x0BC0}}, + {"TAMIL SYLLABLE TTO", []rune{0x0B9F, 0x0BCA}}, + {"TAMIL SYLLABLE TTOO", []rune{0x0B9F, 0x0BCB}}, + {"TAMIL SYLLABLE TTU", []rune{0x0B9F, 0x0BC1}}, + {"TAMIL SYLLABLE TTUU", []rune{0x0B9F, 0x0BC2}}, + {"TAMIL SYLLABLE TU", []rune{0x0BA4, 0x0BC1}}, + {"TAMIL SYLLABLE TUU", []rune{0x0BA4, 0x0BC2}}, + {"TAMIL SYLLABLE VAA", []rune{0x0BB5, 0x0BBE}}, + {"TAMIL SYLLABLE VAI", []rune{0x0BB5, 0x0BC8}}, + {"TAMIL SYLLABLE VAU", []rune{0x0BB5, 0x0BCC}}, + {"TAMIL SYLLABLE VE", []rune{0x0BB5, 0x0BC6}}, + {"TAMIL SYLLABLE VEE", []rune{0x0BB5, 0x0BC7}}, + {"TAMIL SYLLABLE VI", []rune{0x0BB5, 0x0BBF}}, + {"TAMIL SYLLABLE VII", []rune{0x0BB5, 0x0BC0}}, + {"TAMIL SYLLABLE VO", []rune{0x0BB5, 0x0BCA}}, + {"TAMIL SYLLABLE VOO", []rune{0x0BB5, 0x0BCB}}, + {"TAMIL SYLLABLE VU", []rune{0x0BB5, 0x0BC1}}, + {"TAMIL SYLLABLE VUU", []rune{0x0BB5, 0x0BC2}}, + {"TAMIL SYLLABLE YAA", []rune{0x0BAF, 0x0BBE}}, + {"TAMIL SYLLABLE YAI", []rune{0x0BAF, 0x0BC8}}, + {"TAMIL SYLLABLE YAU", []rune{0x0BAF, 0x0BCC}}, + {"TAMIL SYLLABLE YE", []rune{0x0BAF, 0x0BC6}}, + {"TAMIL SYLLABLE YEE", []rune{0x0BAF, 0x0BC7}}, + {"TAMIL SYLLABLE YI", []rune{0x0BAF, 0x0BBF}}, + {"TAMIL SYLLABLE YII", []rune{0x0BAF, 0x0BC0}}, + {"TAMIL SYLLABLE YO", []rune{0x0BAF, 0x0BCA}}, + {"TAMIL SYLLABLE YOO", []rune{0x0BAF, 0x0BCB}}, + {"TAMIL SYLLABLE YU", []rune{0x0BAF, 0x0BC1}}, + {"TAMIL SYLLABLE YUU", []rune{0x0BAF, 0x0BC2}}, +} diff --git a/uax34/uax34.go b/uax34/uax34.go new file mode 100644 index 0000000..2c88ccc --- /dev/null +++ b/uax34/uax34.go @@ -0,0 +1,125 @@ +// Package uax34 implements Unicode Named Character Sequences (UAX #34). +// +// A Named Character Sequence assigns a unique name to a sequence of two or +// more code points. Names use the same restricted character set as Unicode +// character names (A-Z, 0-9, space, and hyphen) and are guaranteed unique. +// For example, the name "KEYCAP NUMBER SIGN" denotes the three code point +// sequence U+0023 U+FE0F U+20E3. +// +// Implements UAX #34: Unicode Named Character Sequences +// https://www.unicode.org/reports/tr34/ +// +// # Data Source +// +// The data is derived from the normative NamedSequences.txt file in the +// Unicode Character Database. The provisional NamedSequencesProv.txt file is +// intentionally excluded, as it is not normative. +// +// This implementation uses Unicode 17.0.0 data: +// - https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt +// +// # Semantics +// +// In NamedSequences.txt every name is unique and, for a given Unicode version, +// each code point sequence maps to exactly one name. Lookup and Name therefore +// form a bijection between names and sequences. The generator verifies this +// invariant when the table is built, failing loudly if a future data file +// ever violates it. +// +// # Usage +// +// import "github.com/SCKelemen/unicode/v6/uax34" +// +// // Resolve a name to its code point sequence. +// seq, ok := uax34.Lookup("KEYCAP NUMBER SIGN") // []rune{0x0023, 0xFE0F, 0x20E3}, true +// +// // Resolve a code point sequence back to its name. +// name, ok := uax34.Name([]rune{0x0023, 0xFE0F, 0x20E3}) // "KEYCAP NUMBER SIGN", true +// +// // Total number of named sequences. +// n := uax34.Count() +// +// // Iterate over every named sequence, sorted by name. +// for _, s := range uax34.All() { +// fmt.Println(s.Name, s.Runes) +// } +// +// # References +// +// - UAX #34: https://www.unicode.org/reports/tr34/ +// - NamedSequences.txt: https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt +// - UAX #44 (Unicode Character Database): https://www.unicode.org/reports/tr44/ +package uax34 + +import ( + "slices" + "sync" +) + +// Sequence is a single Named Character Sequence: a unique name paired with the +// sequence of two or more code points it denotes. +type Sequence struct { + // Name is the unique name of the sequence (A-Z, 0-9, space, hyphen). + Name string + // Runes is the code point sequence the name denotes. + Runes []rune +} + +// nameIndex lazily maps each code point sequence (encoded as a string of its +// runes) to its unique name, supporting reverse lookups in Name. +var ( + nameIndexOnce sync.Once + nameIndex map[string]string +) + +func buildNameIndex() { + nameIndex = make(map[string]string, len(namedSequenceData)) + for _, e := range namedSequenceData { + nameIndex[string(e.seq)] = e.name + } +} + +// Lookup returns the code point sequence for the named character sequence with +// the given name. The returned slice is a copy that the caller may modify. +// ok reports whether name is a defined Named Character Sequence. +func Lookup(name string) (seq []rune, ok bool) { + i, found := slices.BinarySearchFunc(namedSequenceData, name, + func(e namedSequence, target string) int { + switch { + case e.name < target: + return -1 + case e.name > target: + return 1 + default: + return 0 + } + }) + if !found { + return nil, false + } + return slices.Clone(namedSequenceData[i].seq), true +} + +// Name returns the unique name of the given code point sequence. ok reports +// whether seq is exactly a defined Named Character Sequence; partial matches +// and supersequences do not match. +func Name(seq []rune) (name string, ok bool) { + nameIndexOnce.Do(buildNameIndex) + name, ok = nameIndex[string(seq)] + return name, ok +} + +// Count returns the number of Named Character Sequences. +func Count() int { + return len(namedSequenceData) +} + +// All returns every Named Character Sequence, sorted ascending by name. The +// returned slices are copies that the caller may modify. +func All() []Sequence { + out := make([]Sequence, len(namedSequenceData)) + for i, e := range namedSequenceData { + out[i] = Sequence{Name: e.name, Runes: slices.Clone(e.seq)} + } + return out +} diff --git a/uax34/uax34_test.go b/uax34/uax34_test.go new file mode 100644 index 0000000..b28da80 --- /dev/null +++ b/uax34/uax34_test.go @@ -0,0 +1,239 @@ +package uax34 + +import ( + "bufio" + "io" + "net/http" + "os" + "slices" + "sort" + "strconv" + "strings" + "testing" +) + +const namedSequencesURL = "https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt" + +// fileEntry is one parsed row of NamedSequences.txt. +type fileEntry struct { + name string + seq []rune +} + +// parseNamedSequences parses NamedSequences.txt, returning every normative +// entry. It mirrors the format the generator consumes: comments begin with +// '#', and each data line is "Name;CodePointSequence". +func parseNamedSequences(t *testing.T, r io.Reader) []fileEntry { + t.Helper() + var entries []fileEntry + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := scanner.Text() + if hash := strings.IndexByte(line, '#'); hash >= 0 { + line = line[:hash] + } + line = strings.TrimSpace(line) + if line == "" { + continue + } + parts := strings.Split(line, ";") + if len(parts) < 2 { + continue + } + name := strings.TrimSpace(parts[0]) + fields := strings.Fields(parts[1]) + if name == "" || len(fields) < 2 { + t.Fatalf("malformed entry %q (need a name and >=2 code points)", line) + } + seq := make([]rune, 0, len(fields)) + for _, f := range fields { + v, err := strconv.ParseInt(f, 16, 32) + if err != nil { + t.Fatalf("bad code point %q in %q: %v", f, name, err) + } + seq = append(seq, rune(v)) + } + entries = append(entries, fileEntry{name: name, seq: seq}) + } + if err := scanner.Err(); err != nil { + t.Fatalf("scanning NamedSequences.txt: %v", err) + } + return entries +} + +// assertRoundTrip checks that every entry resolves through both Lookup and +// Name and that Count matches the number of entries in the source file. +func assertRoundTrip(t *testing.T, entries []fileEntry) { + t.Helper() + + if got := Count(); got != len(entries) { + t.Errorf("Count() = %d, want %d", got, len(entries)) + } + + for _, e := range entries { + seq, ok := Lookup(e.name) + if !ok { + t.Errorf("Lookup(%q) not found", e.name) + continue + } + if !slices.Equal(seq, e.seq) { + t.Errorf("Lookup(%q) = %v, want %v", e.name, seq, e.seq) + } + + name, ok := Name(e.seq) + if !ok { + t.Errorf("Name(%v) not found (expected %q)", e.seq, e.name) + continue + } + if name != e.name { + t.Errorf("Name(%v) = %q, want %q", e.seq, name, e.name) + } + } +} + +// TestDataFileConsistency validates the generated table against the committed +// NamedSequences.txt: every entry must round-trip through Lookup and Name, and +// Count must equal the number of entries in the file. +func TestDataFileConsistency(t *testing.T) { + file, err := os.Open("NamedSequences.txt") + if err != nil { + t.Skipf("Skipping data file consistency test: %v", err) + return + } + defer file.Close() + + entries := parseNamedSequences(t, file) + if len(entries) == 0 { + t.Fatal("parsed zero entries from NamedSequences.txt") + } + assertRoundTrip(t, entries) +} + +// TestOfficialNamedSequences downloads the official Unicode 17.0.0 +// NamedSequences.txt and verifies that every entry round-trips. It is skipped +// in short mode or when the download is unavailable. +func TestOfficialNamedSequences(t *testing.T) { + if testing.Short() { + t.Skip("Skipping official conformance test in short mode") + } + + resp, err := http.Get(namedSequencesURL) + if err != nil { + t.Skipf("Skipping official conformance test (download unavailable): %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Skipf("Skipping official conformance test (HTTP %d)", resp.StatusCode) + } + + entries := parseNamedSequences(t, resp.Body) + if len(entries) == 0 { + t.Fatal("parsed zero entries from official NamedSequences.txt") + } + assertRoundTrip(t, entries) + t.Logf("PASSED: %d/%d named sequences round-trip (100%% conformance)", len(entries), len(entries)) +} + +func TestLookupSpotChecks(t *testing.T) { + cases := []struct { + name string + want []rune + }{ + {"KEYCAP NUMBER SIGN", []rune{0x0023, 0xFE0F, 0x20E3}}, + {"LATIN SMALL LETTER A WITH MACRON AND GRAVE", []rune{0x0101, 0x0300}}, + } + for _, c := range cases { + seq, ok := Lookup(c.name) + if !ok { + t.Errorf("Lookup(%q) not found", c.name) + continue + } + if !slices.Equal(seq, c.want) { + t.Errorf("Lookup(%q) = %v, want %v", c.name, seq, c.want) + } + // Reverse lookup must return the same name. + if name, ok := Name(c.want); !ok || name != c.name { + t.Errorf("Name(%v) = %q, %v; want %q, true", c.want, name, ok, c.name) + } + } +} + +func TestLookupUnknown(t *testing.T) { + if seq, ok := Lookup("THIS IS NOT A NAMED SEQUENCE"); ok { + t.Errorf("Lookup(unknown) = %v, true; want nil, false", seq) + } + if seq, ok := Lookup(""); ok { + t.Errorf("Lookup(\"\") = %v, true; want nil, false", seq) + } +} + +func TestNameRequiresExactSequence(t *testing.T) { + // A proper prefix of a real sequence must not match. + if name, ok := Name([]rune{0x0023, 0xFE0F}); ok { + t.Errorf("Name(prefix) = %q, true; want \"\", false", name) + } + // A supersequence of a real sequence must not match. + if name, ok := Name([]rune{0x0023, 0xFE0F, 0x20E3, 0x0041}); ok { + t.Errorf("Name(supersequence) = %q, true; want \"\", false", name) + } + // An empty sequence must not match. + if name, ok := Name(nil); ok { + t.Errorf("Name(nil) = %q, true; want \"\", false", name) + } +} + +func TestCountMatchesAll(t *testing.T) { + if got, n := Count(), len(All()); got != n { + t.Errorf("Count() = %d, len(All()) = %d; want equal", got, n) + } +} + +func TestAllSortedAndComplete(t *testing.T) { + all := All() + if len(all) != Count() { + t.Fatalf("len(All()) = %d, want %d", len(all), Count()) + } + if !sort.SliceIsSorted(all, func(i, j int) bool { return all[i].Name < all[j].Name }) { + t.Error("All() is not sorted ascending by name") + } + // Every entry from All() must round-trip through Lookup. + for _, s := range all { + seq, ok := Lookup(s.Name) + if !ok { + t.Errorf("Lookup(%q) not found", s.Name) + continue + } + if !slices.Equal(seq, s.Runes) { + t.Errorf("Lookup(%q) = %v, want %v", s.Name, seq, s.Runes) + } + } +} + +// TestReturnedSlicesAreCopies ensures callers cannot mutate the internal table +// through the slices returned by Lookup and All. +func TestReturnedSlicesAreCopies(t *testing.T) { + const name = "KEYCAP NUMBER SIGN" + + seq, ok := Lookup(name) + if !ok { + t.Fatalf("Lookup(%q) not found", name) + } + seq[0] = 0xFFFF // mutate the returned copy + + seq2, _ := Lookup(name) + if seq2[0] == 0xFFFF { + t.Error("Lookup returned a slice aliasing internal data; mutation leaked") + } + + all := All() + for i := range all { + if all[i].Name == name { + all[i].Runes[0] = 0xFFFF + } + } + for _, s := range All() { + if s.Name == name && s.Runes[0] == 0xFFFF { + t.Error("All returned slices aliasing internal data; mutation leaked") + } + } +}