Unicode sequences, @typeface, and the font/typeface distinction

A run of Unicode code points now needs one pair of carets, not one pair
each: ^9053 53EF 9053^ renders the characters adjacently, and a single
character inside such a run stands for itself.  An invalid code point is
an error naming the position that wrote it, rather than an apology
rendered into the finished document; noncharacters are refused alongside
surrogates; and a code point that lands on a Klammertext special is safe
through the re-reads that assemble a document.  The character tables now
produce the precomposed form, so a diacritic written as ^a" and one typed
directly are the same text to a search or a copy-paste.

"kdesc -u" describes how to write a Unicode character, with tables of
glyphs beside the codes that produce them.  It is new and not yet
complete: it predates the sequence form and the typeface klammer below.

A typeface and a style are no longer both called "font".  A typeface is a
family resolved by name; a style code is the one letter naming a type
style.  So @document takes :serif_typeface and its siblings, a table takes
:style, captions take :caption_style and :caption_size, the uniform scale
is :text_scale, and the command is "kdesc --typeface".  This renames
arguments a document may already use; an old name is a located error
rather than a silent omission.

@typeface sets a passage in another typeface for the length of that
passage:

    @typeface Noto Sans Egyptian Hieroglyphs | ^132AA 133CF^ :scale 1.5 @

Writing the klammer is the whole declaration -- the document resolves the
typeface, embeds it in what it produces, and carries its license along.
Two typefaces for scripts no text font covers now ship with Klammertext:
Noto Sans Egyptian Hieroglyphs and Noto Sans Cuneiform.  Every typeface in
the distribution now carries its license file.

(from dev 61e598698891)
This commit is contained in:
ack committed 2026-08-25 23:30:55 +02:00
1 parent 37b6ba1c4f
commit af29bbf7ac
47 files changed
+1921 -135

No files matched your search

+2 -2
View File
@@ -63,11 +63,11 @@ public:
// next -/-- token (zero or more). get(name) returns the words
// space-joined; given(name) distinguishes "--name with no words"
// from an absent --name. Used for subcommand-style interfaces
// (kdesc --font install <dir>).
// (kdesc --typeface install <dir>).
// A variadic option: the words after the flag, up to the next one.
// `parameter` is shown in the usage line as "[<parameter>]" -- an option
// whose words are a free argument (a search phrase) should name it, so
// the usage says what may follow; a subcommand-style option (--font,
// the usage says what may follow; a subcommand-style option (--typeface,
// --coverage) leaves it empty and documents its words in its own help.
void var(const std::string& name, const std::string& desc,
const std::string& parameter = "");
+97 -10
View File
@@ -2,9 +2,26 @@
#include "util.h"
#include "character.h"
#include "precomposed.h"
#include "error.h"
#include "target.h"
#include "log.h"
#include "show.h"
// A base letter composed with a combining mark. The PRECOMPOSED (NFC)
// code point is emitted where one exists -- that is the byte sequence
// editors and input methods produce for direct entry, so ^a" and a typed
// ä compare equal (search, copy-paste); the tables formerly emitted
// base + combining mark, which renders identically but is a different
// string. Pairs with no precomposed form keep the combining fallback.
// The table is GENERATED: doc/make_precomposed_table.py -> precomposed.h.
static std::string compose(const std::string& base, const std::string& mark_cp)
{
auto it = precomposed.find(base + mark_cp);
if (it != precomposed.end()) return it->second;
return base + utf8char(std::stoi(mark_cp, nullptr, 16));
}
inline
std::string klammertext_special_characters { "@|*^#" };
@@ -44,6 +61,24 @@ std::string utf8char(int cp)
}
bool valid_codepoint(int cp)
{
if (cp < 0 || cp > 0x10FFFF) return false;
if (0xD800 <= cp && cp <= 0xDFFF) return false; // surrogates
if (0xFDD0 <= cp && cp <= 0xFDEF) return false; // noncharacters
if ((cp & 0xFFFE) == 0xFFFE) return false; // U+xFFFE / U+xFFFF
return true;
}
std::string invalid_codepoint_reason(int cp)
{
if (cp < 0 || cp > 0x10FFFF)
return "beyond U+10FFFF, the top of the Unicode range";
if (0xD800 <= cp && cp <= 0xDFFF)
return "a surrogate (U+D800-U+DFFF), not a character";
return "a noncharacter, reserved by Unicode for internal use";
}
std::string unicode_hex_to_char(std::string s, int width=4) //, std::string marker)
{
(void)K::log(4, s);
@@ -82,7 +117,7 @@ std::string process_diacritics(std::string s)
std::regex hit { regex_escape((*p)[0].str()) };
std::string ch = (*p)[1].str();
std::string d = (*p)[2].str();
result = std::regex_replace(result, hit, ch + unicode_hex_to_char(diacritics[d].first));
result = std::regex_replace(result, hit, compose(ch, diacritics[d].first));
}
return result;
}
@@ -124,15 +159,14 @@ std::string process_pinyin(std::string s)
std::string vowel = (*p)[1].str();
std::string tone = (*p)[2].str();
result = std::regex_replace(result, hit,
vowel + unicode_hex_to_char(pinyin_tones[tone].first));
compose(vowel, pinyin_tones[tone].first));
}
return result;
}
std::string process_unicode_codepoint(std::string s)
std::string process_unicode_codepoint(std::string s, const Locator& loc = Locator::none())
{
(void)K::log(4);
//return std::regex_replace(s, unicode_re, hidehat + "$1" + hidehat);
std::string result {s};
std::sregex_iterator end {};
for (std::sregex_iterator p { s.begin(), s.end(), unicode_re }; p!= end; ++p) {
@@ -141,8 +175,22 @@ std::string process_unicode_codepoint(std::string s)
// its argument at a fixed width, and its 4-digit default truncated a
// 5-digit code point to its first four digits (^13000^ rendered as
// U+1300 followed by a literal "0").
int cp = std::stoi((*p)[1].str(), nullptr, 16);
// An invalid code point is a located ERROR, not text in the document
// (the no-warn-and-continue policy): a generator's typo must not
// produce a finished-looking document with an apology embedded
// where a character should be.
if (!valid_codepoint(cp)) {
throw Parsing_error("Invalid Unicode code point \"" + (*p)[0].str()
+ "\": " + invalid_codepoint_reason(cp), loc);
}
// A code point that lands on a Klammertext structural character
// (@ | # ^ : *) is hidden as its KTESC marker, exactly as the
// quoted form of that character would be -- a bare "@" from
// ^0040^ would otherwise be re-interpreted when the text is
// re-katomized (@document :text, the @eval read-back).
result = std::regex_replace(result, hit_re,
utf8char(std::stoi((*p)[1].str(), nullptr, 16)));
hide_structural_characters(utf8char(cp)));
}
return result;
@@ -154,7 +202,7 @@ std::string process_unicode_codepoint(std::string s)
std::string encode(const std::string& s)
std::string encode(const std::string& s, const Locator& loc)
{
if (s.find("^") == std::string::npos)
return s;
@@ -177,7 +225,7 @@ std::string encode(const std::string& s)
result = process_extended_latin(result);
if (dbg) std::cout << "extended_latin: " << result << "\n";
result = process_unicode_codepoint(result);
result = process_unicode_codepoint(result, loc);
if (dbg) std::cout << "unicode: " << result << "\n";
result = process_diacritics(result);
@@ -225,7 +273,7 @@ void diacritics_examples(const std::string& kt_filename)
<< " @i-Displayed | @i-Written | @i-Name\n";
else
std::cout << boldblack
<< "\nDiacritics (with typical base characters)\n" << black;
<< "\nDiacritics (with typical base characters)\n\n" << black;
std::string line_sep = "|| @line@ ";
for (char symbol : diacritic_symbols_order) {
@@ -260,7 +308,7 @@ void extended_latin_examples(const std::string& kt_filename)
kt << "@table :caption " << title << " |\n"
<< " @i-Displayed | @i-Written | @i-Name\n";
else
std::cout << "\n" << boldblack << title << black << "\n";
std::cout << "\n" << boldblack << title << black << "\n\n";
std::string line_sep = "|| @line@ ";
for (const std::string& symbol : extended_latin_symbols) {
@@ -291,7 +339,7 @@ void pinyin_examples(const std::string& kt_filename)
<< " @i-Displayed | @i-Written | @i-Name\n";
else
std::cout << boldblack
<< "\nMandarin pinyin tones (using vowel \"a\")\n" << black;
<< "\nMandarin pinyin tones (using vowel \"a\")\n\n" << black;
std::string line_sep = "|| @line@ ";
for (auto [symbol, codename] : pinyin_tones) {
@@ -309,6 +357,45 @@ void pinyin_examples(const std::string& kt_filename)
write_kt_example_file(kt, kt_filename);
}
void unicode_examples(const std::string& kt_filename)
{
std::stringstream kt {};
bool write_kt_file = kt_filename.size() != 0;
std::cout << boldblack << "\nIncluding Unicode in Klammertext files\n\n" << black
<< "To specify a wide variety of different letter forms, the Unicode Standard\n"
<< "defines a large set of \"code points\" organized by groups. To include a\n"
<< "Unicode character in Klammertext, you surround its hexadecimal number with\n"
<< "the \"^\" character. For example, the Cyrillic captial letter \"I\" is \"И\",\n"
<< "included in Klammertext as ^0418^.\n\n"
<< "To search for Unicode characters by their description, see:\n"
<< " https://www.fileformat.info/info/unicode/char/search.htm\n";
std::cout << "\n⟐ Examples of Chinese characters\n\n"
<< " Pinyin\n";
for (auto chr : dao) {
std::string code = "^" + chr[1] + "^";
std::cout << " " << process_unicode_codepoint(code) << " "
<< code << " "
<< chr[0] << "\n";
}
std::cout << "\n⟐ Examples of Egyptian hieroglyphs\n\n";
std::cout << std::setw(16) << " " << "Sound Gardiner\n";
for (auto glyph : ptolemy) {
std::cout << " " << std::setw(4) << process_unicode_codepoint("^" + glyph[2] + "^") << " "
<< "^" + glyph[2] + "^ "
<< std::setw(4)
<< glyph[1] << " "
<< std::setw(4)
<< glyph[0] << "\n";
}
std::cout << "\nSee: https://en.wikipedia.org/wiki/List_of_Egyptian_hieroglyphs\n"
<< "The Unicode codepoint in the second column of the \"List of hieroglyphs\"\n"
<< "table is the number in the ^...^ code used by Klammertext.\n\n";
}
void show_special_characters()
{
std::cout << std::setfill(' ');
+45 -3
View File
@@ -11,6 +11,8 @@
#include <regex>
#include <unistd.h>
#include "locator.h"
// ^UUUU^ — a Unicode code point in hex, 4 to 6 digits (^263A^ is the BMP,
// ^13000^ EGYPTIAN HIEROGLYPH A001, ^10FFFD^ the top of the range), or a
// single digit. Lengths 2-3 are NOT accepted: two- and three-letter
@@ -89,21 +91,61 @@ std::map<std::string, std::pair<std::string, std::string>> pinyin_tones {
{"3", {"030C", "falling-rising"}},
{"4", {"0300", "falling"}}};
inline
std::vector<std::vector<std::string>> ptolemy {
{"Q3", "P", "132AA"},
{"X1", "t", "133CF"},
{"V4", "o/wa", "13371"},
{"E23", "l/r", "130ED"},
{"Aa15", "m", "1340D"},
{"M17A", "e/y", "131CC"},
{"S29", "s", "132F4"}};
/*
道 (dào): U+9053
可 (kě): U+53EF
道 (dào): U+9053
非 (fēi): U+975E
常 (cháng): U+5E38
道 (dào): U+9053
*/
inline
std::vector<std::vector<std::string>> dao {
{"dào", "9053"},
{"kě", "53EF"},
{"dào", "9053"},
{"fēi", "975E"},
{"cháng", "5E38"},
{"dào", "9053"}};
inline
bool is_tty() { return isatty(fileno(stdout)); }
//const char* italic_on() { return tty() ? "\033[3m" : ""; }
//const char* italic_off() { return tty() ? "\033[0m" : ""; }
inline
const std::string italic_on() { return is_tty() ? "\033[3m" : ""; }
inline
const std::string italic_off() { return is_tty() ? "\033[0m" : ""; }
std::string encode(const std::string& s, const Locator& loc);
std::string encode(const std::string& s);
// UTF-8 encoding of one code point (to U+10FFFF; surrogates and values
// above the range yield an "Invalid Unicode: N" text). Used by the
// character tables here and by the ^UUUU UUUU ...^ sequence pass
// (process_unicode_sequences in katom_list.cpp).
std::string utf8char(int cp);
// Whether cp may be written in a ^...^ form: within the Unicode range,
// not a surrogate, and not a NONCHARACTER (U+FDD0-U+FDEF and the last two
// code points of every plane) -- the standard reserves those for internal
// use, never for interchange. An invalid code point in a document is a
// located Parsing_error (the no-warn-and-continue policy; the in-band
// "Invalid Unicode" text is no longer reachable from input).
bool valid_codepoint(int cp);
std::string invalid_codepoint_reason(int cp);
void diacritics_examples(const std::string& kt_filename = "");
void extended_latin_examples(const std::string& kt_filename = "");
void pinyin_examples(const std::string& kt_filename = "");
void unicode_examples(const std::string& kt_filename = "");
void show_special_characters();
+8 -8
View File
@@ -206,7 +206,7 @@ static void extract_font_metrics(Resolved_font& font)
}
}
Resolved_font resolve_font(const std::string& family_name)
Resolved_font resolve_font(const std::string& family_name, const Locator& loc)
{
if (family_name.empty())
return {};
@@ -222,26 +222,26 @@ Resolved_font resolve_font(const std::string& family_name)
if (!font.family_name.empty()) {
extract_font_metrics(font);
// A DERIVED value: an installed font may shadow a default one, and
// which directory won is not readable from ":serif_font Whatever".
// which directory won is not readable from ":serif_typeface Whatever".
// The commonest font question -- "why does it not look like the
// one I installed?" -- is answered by this line.
(void)K::log(1, "Font \"" + family_name + "\": " + base + "/" + dir_name);
(void)K::log(1, "Typeface \"" + family_name + "\": " + base + "/" + dir_name);
return font;
}
}
std::stringstream ss {};
ss << "The font \"" << family_name << "\" is not installed.\n\n"
<< "Available fonts:\n";
ss << "The typeface \"" << family_name << "\" is not installed.\n\n"
<< "Available typefaces:\n";
for (const std::string& name : available_font_families()) {
ss << " " << name << "\n";
}
ss << "\nFonts are searched in the directories of the KLAMMERTEXT_FONTS\n"
ss << "\nTypefaces are searched in the directories of the KLAMMERTEXT_FONTS\n"
<< "environment variable (colon-separated; default $HOME/.klammertext/fonts)\n"
<< "and then in the default font set. To install a font,\n"
<< "and then in the default set. To install a typeface,\n"
<< "place its files as <fonts-dir>/" << dir_name << "/*.ttf with a\n"
<< "<fonts-dir>/" << dir_name << ".css declaring its @font-face variants.";
throw Argument_error(ss.str());
throw Argument_error(ss.str(), loc);
}
+6 -1
View File
@@ -3,6 +3,7 @@
// The Klammertext font store (infrastructure; see font_store.cpp).
#include <string>
#include "locator.h"
#include <vector>
struct Resolved_font {
@@ -27,7 +28,11 @@ std::vector<std::string> installed_font_dirs();
std::string default_font_dir();
// Every installable font family found across those directories.
std::vector<std::string> available_font_families();
Resolved_font resolve_font(const std::string& family_name);
// The Locator is the DOCUMENT location to blame when the typeface is not
// installed: without it the "not installed" error cites font_store.cpp,
// a source location no user can act on (the no-.cpp-location rule).
Resolved_font resolve_font(const std::string& family_name,
const Locator& loc = Locator::none());
void install_resolved_font(const Resolved_font& font, std::string output_dir);
// One font file classified by its internal metadata (name table, OS/2).
+154 -1
View File
@@ -281,11 +281,164 @@ void encode_nonascii_characters(katom_list& katoms)
{
for (Katom& k : katoms) {
if (is_nonascii(k)) {
k.m_text = encode(k.m_text);
k.m_text = encode(k.m_text, k.m_loc);
}
}
}
// Unicode sequences
// ^UUUU UUUU ...^ -- a whitespace-delimited sequence of Unicode code
// points between ONE pair of carets: ^9053 53EF 9053^ renders the three
// characters adjacently. The single-token form ^UUUU^ is the katomizer's
// nonascii katom, resolved by encode(); a sequence cannot be a katom at
// all, because whitespace is preserved as separate katoms and no katom
// spans it. So the tokens arrive as word katoms -- the opener "^"+hex,
// the closer hex+"^", bare hex between, separated by SPACE katoms only (a
// newline aborts: a sequence is one line; so does any other katom, which
// is also what enforces "no space inside the delimiters' elbows": a bare
// "^" is not an opener) -- and are assembled here. Each token is 4-6 hex
// digits, the same rule as the single form. The rendered characters
// replace the opening katom's text; the other members are marked
// replaced. Skipped inside @@/@@@ definition spans and
// @eval/@read/@cond argument spans (code keeps its carets -- the rule the
// string-level single-form pass cannot honor) and for literal katoms
// (verbatim content; mark_literal_* run before this).
namespace {
bool hex_token(const std::string& s)
{
if (s.size() < 4 || s.size() > 6) return false;
for (char c : s) {
bool hex = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
if (!hex) return false;
}
return true;
}
// A sequence token is a 4-6-digit hex code point or a SINGLE character
// standing for itself ("^" excluded -- a lone caret cannot say which
// caret closes). The single-character reading exists only inside a
// sequence; ^s^ alone stays the mnemonic.
bool shape_token(const std::string& s)
{
return hex_token(s) || (s.size() == 1 && s[0] != '^');
}
// Render one scanned token. A hex token is validated -- an invalid code
// point is a located error, not text in the document -- and a structural
// character in the result is hidden as its KTESC marker. A single
// character behaves exactly as if quoted with "^": alphanumerics stand
// bare, anything else becomes its marker.
std::string render_token(const std::string& s, const Locator& loc)
{
if (hex_token(s)) {
int cp = std::stoi(s, nullptr, 16);
if (!valid_codepoint(cp)) {
throw Parsing_error(
"Invalid Unicode code point \"" + s + "\" in a ^...^ sequence: "
+ invalid_codepoint_reason(cp), loc);
}
return hide_structural_characters(utf8char(cp));
}
char c = s[0];
bool alnum = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z');
return alnum ? s : Target::escape_marker(s);
}
} // namespace
void process_unicode_sequences(katom_list& katoms)
{
(void)K::log(4);
int definition_depth = 0;
int code_depth = 0; // inside an @eval/@read/@cond span
std::vector<bool> apply_is_code; // one entry per open application
for (size_t i = 0; i < katoms.size(); ++i) {
Katom& k = katoms[i];
switch (k.m_type) {
case katom_t::define_begin:
case katom_t::machine_begin:
++definition_depth;
continue;
case katom_t::define_end:
case katom_t::machine_end:
if (definition_depth > 0) --definition_depth;
continue;
case katom_t::eval_begin:
case katom_t::read_begin:
case katom_t::cond_begin:
apply_is_code.push_back(true);
++code_depth;
continue;
case katom_t::apply_begin:
apply_is_code.push_back(false);
continue;
case katom_t::apply_end:
if (!apply_is_code.empty()) {
if (apply_is_code.back()) --code_depth;
apply_is_code.pop_back();
}
continue;
default:
break;
}
if (definition_depth > 0 || code_depth > 0) continue;
if (k.m_type != katom_t::word && k.m_type != katom_t::text) continue;
// The opener: "^" + one token, nothing else.
if (k.m_text.size() < 2 || k.m_text[0] != '^') continue;
if (!shape_token(k.m_text.substr(1))) continue;
// Phase 1 -- SCAN by shape only, no validation: an unclosed run
// must fall through untouched (it may be innocent prose about hex),
// so an invalid code point may only error once the sequence has
// actually closed. Tokens are word katoms separated by SPACE
// katoms; any other katom (a newline included: one line only)
// aborts.
std::vector<std::pair<std::string, const Locator*>> tokens {
{ k.m_text.substr(1), &k.m_loc } };
std::vector<size_t> members {};
bool closed = false;
size_t j = i + 1;
for (; j < katoms.size(); ++j) {
Katom& t = katoms[j];
if (t.m_type == katom_t::space) {
members.push_back(j);
continue;
}
if (t.m_type != katom_t::word && t.m_type != katom_t::text) break;
const std::string& s = t.m_text;
if (s.size() >= 2 && s.back() == '^'
&& shape_token(s.substr(0, s.size() - 1))) {
tokens.push_back({ s.substr(0, s.size() - 1), &t.m_loc });
members.push_back(j);
closed = true;
++j;
break;
}
if (shape_token(s)) {
tokens.push_back({ s, &t.m_loc });
members.push_back(j);
continue;
}
break;
}
if (!closed) continue;
// Phase 2 -- render, validating each code point at its own katom.
std::string rendered {};
for (const auto& [text, loc] : tokens) {
rendered += render_token(text, *loc);
}
k.m_text = rendered;
k.m_unparsed = false;
for (size_t m : members) {
mark_as_replaced(katoms[m]);
}
i = j - 1;
}
}
// Literal
void mark_literal_katoms(katom_list& katoms)
+1
View File
@@ -46,6 +46,7 @@ find_span_katoms(
std::vector<Katom>::iterator kbegin, std::vector<Katom>::iterator kend, const Katom& begin, const Katom& end);
void encode_nonascii_characters(std::vector<Katom>& katoms);
void process_unicode_sequences(std::vector<Katom>& katoms);
void mark_literal_katoms(std::vector<Katom>& katoms);
void hide_special_katoms(std::vector<Katom>& katoms);
void mark_ignored_katoms(std::vector<Katom>& katoms);
+22
View File
@@ -135,3 +135,25 @@ std::string locator_summary(std::vector<Locator> locators)
}
return "";
}
// Parse "[<file>:<line>.<column>]" -- see the declaration in locator.h.
// Scanned from the RIGHT, because a pathname may itself contain ":" and
// "." while the line and column never do.
Locator Locator::from_string(const std::string& s)
{
if (s.size() < 6 || s.front() != '[' || s.back() != ']')
return Locator::none();
std::string body = s.substr(1, s.size() - 2);
size_t dot = body.rfind('.');
if (dot == std::string::npos) return Locator::none();
size_t colon = body.rfind(':', dot);
if (colon == std::string::npos) return Locator::none();
try {
int line = std::stoi(body.substr(colon + 1, dot - colon - 1));
int chr = std::stoi(body.substr(dot + 1));
// str() prints m_chr + 1; undo that so a round trip is exact.
return Locator(fs::path(body.substr(0, colon)), line, chr - 1);
} catch (const std::exception&) {
return Locator::none();
}
}
+7
View File
@@ -32,6 +32,13 @@ public:
// errors (found by the error gallery, 2026-08-22). Locator() is for
// logging; errors either carry a real document location or this.
static Locator none() { return Locator(fs::path{}, -1, -1); }
// The inverse of str(): "[<file>:<line>.<column>]" back to a Locator.
// A klammer implementation receives its position as the STATE value
// K_loc, which is that string; without this it can only pass a
// default-constructed Locator, which captures the C++ source location
// and prints a file no user can act on. Anything unparseable gives
// none() -- a missing location beats a wrong one.
static Locator from_string(const std::string& s);
std::string str(bool relative = false) const;
std::string desc(bool relative = false) const;
std::string abbrev(bool include_chr=true) const;
+5
View File
@@ -435,6 +435,11 @@ void Machine::process_katoms(
{
mark_literal_klammer_content(katoms);
if (literal) mark_literal_katoms(katoms);
// Sequences BEFORE the quoted-punctuation hiding: a single-character
// token such as the "-" in ^9053 - 53EF^ must reach the sequence pass
// as written; an unmatched run falls through untouched and the hiding
// then treats its ^P pairs normally.
if (nonascii) process_unicode_sequences(katoms);
hide_special_katoms(katoms);
if (nonascii) encode_nonascii_characters(katoms);
if (ignore) mark_ignored_katoms(katoms);
+250
View File
@@ -0,0 +1,250 @@
#pragma once
// GENERATED by doc/make_precomposed_table.py -- do not edit.
// (base letter + combining code point) -> precomposed UTF-8.
#include <map>
#include <string>
inline
const std::map<std::string, std::string> precomposed {
{"a0300", "\xc3\xa0"}, // LATIN SMALL LETTER A WITH GRAVE
{"a0301", "\xc3\xa1"}, // LATIN SMALL LETTER A WITH ACUTE
{"a0302", "\xc3\xa2"}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
{"a0303", "\xc3\xa3"}, // LATIN SMALL LETTER A WITH TILDE
{"a0304", "\xc4\x81"}, // LATIN SMALL LETTER A WITH MACRON
{"a0308", "\xc3\xa4"}, // LATIN SMALL LETTER A WITH DIAERESIS
{"a0306", "\xc4\x83"}, // LATIN SMALL LETTER A WITH BREVE
{"a0307", "\xc8\xa7"}, // LATIN SMALL LETTER A WITH DOT ABOVE
{"a030A", "\xc3\xa5"}, // LATIN SMALL LETTER A WITH RING ABOVE
{"a030C", "\xc7\x8e"}, // LATIN SMALL LETTER A WITH CARON
{"b0307", "\xe1\xb8\x83"}, // LATIN SMALL LETTER B WITH DOT ABOVE
{"c0301", "\xc4\x87"}, // LATIN SMALL LETTER C WITH ACUTE
{"c0302", "\xc4\x89"}, // LATIN SMALL LETTER C WITH CIRCUMFLEX
{"c0307", "\xc4\x8b"}, // LATIN SMALL LETTER C WITH DOT ABOVE
{"c030C", "\xc4\x8d"}, // LATIN SMALL LETTER C WITH CARON
{"c0327", "\xc3\xa7"}, // LATIN SMALL LETTER C WITH CEDILLA
{"d0307", "\xe1\xb8\x8b"}, // LATIN SMALL LETTER D WITH DOT ABOVE
{"d030C", "\xc4\x8f"}, // LATIN SMALL LETTER D WITH CARON
{"d0327", "\xe1\xb8\x91"}, // LATIN SMALL LETTER D WITH CEDILLA
{"e0300", "\xc3\xa8"}, // LATIN SMALL LETTER E WITH GRAVE
{"e0301", "\xc3\xa9"}, // LATIN SMALL LETTER E WITH ACUTE
{"e0302", "\xc3\xaa"}, // LATIN SMALL LETTER E WITH CIRCUMFLEX
{"e0303", "\xe1\xba\xbd"}, // LATIN SMALL LETTER E WITH TILDE
{"e0304", "\xc4\x93"}, // LATIN SMALL LETTER E WITH MACRON
{"e0308", "\xc3\xab"}, // LATIN SMALL LETTER E WITH DIAERESIS
{"e0306", "\xc4\x95"}, // LATIN SMALL LETTER E WITH BREVE
{"e0307", "\xc4\x97"}, // LATIN SMALL LETTER E WITH DOT ABOVE
{"e030C", "\xc4\x9b"}, // LATIN SMALL LETTER E WITH CARON
{"e0327", "\xc8\xa9"}, // LATIN SMALL LETTER E WITH CEDILLA
{"f0307", "\xe1\xb8\x9f"}, // LATIN SMALL LETTER F WITH DOT ABOVE
{"g0301", "\xc7\xb5"}, // LATIN SMALL LETTER G WITH ACUTE
{"g0302", "\xc4\x9d"}, // LATIN SMALL LETTER G WITH CIRCUMFLEX
{"g0304", "\xe1\xb8\xa1"}, // LATIN SMALL LETTER G WITH MACRON
{"g0306", "\xc4\x9f"}, // LATIN SMALL LETTER G WITH BREVE
{"g0307", "\xc4\xa1"}, // LATIN SMALL LETTER G WITH DOT ABOVE
{"g030C", "\xc7\xa7"}, // LATIN SMALL LETTER G WITH CARON
{"g0327", "\xc4\xa3"}, // LATIN SMALL LETTER G WITH CEDILLA
{"h0302", "\xc4\xa5"}, // LATIN SMALL LETTER H WITH CIRCUMFLEX
{"h0308", "\xe1\xb8\xa7"}, // LATIN SMALL LETTER H WITH DIAERESIS
{"h0307", "\xe1\xb8\xa3"}, // LATIN SMALL LETTER H WITH DOT ABOVE
{"h030C", "\xc8\x9f"}, // LATIN SMALL LETTER H WITH CARON
{"h0327", "\xe1\xb8\xa9"}, // LATIN SMALL LETTER H WITH CEDILLA
{"i0300", "\xc3\xac"}, // LATIN SMALL LETTER I WITH GRAVE
{"i0301", "\xc3\xad"}, // LATIN SMALL LETTER I WITH ACUTE
{"i0302", "\xc3\xae"}, // LATIN SMALL LETTER I WITH CIRCUMFLEX
{"i0303", "\xc4\xa9"}, // LATIN SMALL LETTER I WITH TILDE
{"i0304", "\xc4\xab"}, // LATIN SMALL LETTER I WITH MACRON
{"i0308", "\xc3\xaf"}, // LATIN SMALL LETTER I WITH DIAERESIS
{"i0306", "\xc4\xad"}, // LATIN SMALL LETTER I WITH BREVE
{"i030C", "\xc7\x90"}, // LATIN SMALL LETTER I WITH CARON
{"j0302", "\xc4\xb5"}, // LATIN SMALL LETTER J WITH CIRCUMFLEX
{"j030C", "\xc7\xb0"}, // LATIN SMALL LETTER J WITH CARON
{"k0301", "\xe1\xb8\xb1"}, // LATIN SMALL LETTER K WITH ACUTE
{"k030C", "\xc7\xa9"}, // LATIN SMALL LETTER K WITH CARON
{"k0327", "\xc4\xb7"}, // LATIN SMALL LETTER K WITH CEDILLA
{"l0301", "\xc4\xba"}, // LATIN SMALL LETTER L WITH ACUTE
{"l030C", "\xc4\xbe"}, // LATIN SMALL LETTER L WITH CARON
{"l0327", "\xc4\xbc"}, // LATIN SMALL LETTER L WITH CEDILLA
{"m0301", "\xe1\xb8\xbf"}, // LATIN SMALL LETTER M WITH ACUTE
{"m0307", "\xe1\xb9\x81"}, // LATIN SMALL LETTER M WITH DOT ABOVE
{"n0300", "\xc7\xb9"}, // LATIN SMALL LETTER N WITH GRAVE
{"n0301", "\xc5\x84"}, // LATIN SMALL LETTER N WITH ACUTE
{"n0303", "\xc3\xb1"}, // LATIN SMALL LETTER N WITH TILDE
{"n0307", "\xe1\xb9\x85"}, // LATIN SMALL LETTER N WITH DOT ABOVE
{"n030C", "\xc5\x88"}, // LATIN SMALL LETTER N WITH CARON
{"n0327", "\xc5\x86"}, // LATIN SMALL LETTER N WITH CEDILLA
{"o0300", "\xc3\xb2"}, // LATIN SMALL LETTER O WITH GRAVE
{"o0301", "\xc3\xb3"}, // LATIN SMALL LETTER O WITH ACUTE
{"o0302", "\xc3\xb4"}, // LATIN SMALL LETTER O WITH CIRCUMFLEX
{"o0303", "\xc3\xb5"}, // LATIN SMALL LETTER O WITH TILDE
{"o0304", "\xc5\x8d"}, // LATIN SMALL LETTER O WITH MACRON
{"o0308", "\xc3\xb6"}, // LATIN SMALL LETTER O WITH DIAERESIS
{"o0306", "\xc5\x8f"}, // LATIN SMALL LETTER O WITH BREVE
{"o0307", "\xc8\xaf"}, // LATIN SMALL LETTER O WITH DOT ABOVE
{"o030C", "\xc7\x92"}, // LATIN SMALL LETTER O WITH CARON
{"o030B", "\xc5\x91"}, // LATIN SMALL LETTER O WITH DOUBLE ACUTE
{"p0301", "\xe1\xb9\x95"}, // LATIN SMALL LETTER P WITH ACUTE
{"p0307", "\xe1\xb9\x97"}, // LATIN SMALL LETTER P WITH DOT ABOVE
{"r0301", "\xc5\x95"}, // LATIN SMALL LETTER R WITH ACUTE
{"r0307", "\xe1\xb9\x99"}, // LATIN SMALL LETTER R WITH DOT ABOVE
{"r030C", "\xc5\x99"}, // LATIN SMALL LETTER R WITH CARON
{"r0327", "\xc5\x97"}, // LATIN SMALL LETTER R WITH CEDILLA
{"s0301", "\xc5\x9b"}, // LATIN SMALL LETTER S WITH ACUTE
{"s0302", "\xc5\x9d"}, // LATIN SMALL LETTER S WITH CIRCUMFLEX
{"s0307", "\xe1\xb9\xa1"}, // LATIN SMALL LETTER S WITH DOT ABOVE
{"s030C", "\xc5\xa1"}, // LATIN SMALL LETTER S WITH CARON
{"s0327", "\xc5\x9f"}, // LATIN SMALL LETTER S WITH CEDILLA
{"t0308", "\xe1\xba\x97"}, // LATIN SMALL LETTER T WITH DIAERESIS
{"t0307", "\xe1\xb9\xab"}, // LATIN SMALL LETTER T WITH DOT ABOVE
{"t030C", "\xc5\xa5"}, // LATIN SMALL LETTER T WITH CARON
{"t0327", "\xc5\xa3"}, // LATIN SMALL LETTER T WITH CEDILLA
{"u0300", "\xc3\xb9"}, // LATIN SMALL LETTER U WITH GRAVE
{"u0301", "\xc3\xba"}, // LATIN SMALL LETTER U WITH ACUTE
{"u0302", "\xc3\xbb"}, // LATIN SMALL LETTER U WITH CIRCUMFLEX
{"u0303", "\xc5\xa9"}, // LATIN SMALL LETTER U WITH TILDE
{"u0304", "\xc5\xab"}, // LATIN SMALL LETTER U WITH MACRON
{"u0308", "\xc3\xbc"}, // LATIN SMALL LETTER U WITH DIAERESIS
{"u0306", "\xc5\xad"}, // LATIN SMALL LETTER U WITH BREVE
{"u030A", "\xc5\xaf"}, // LATIN SMALL LETTER U WITH RING ABOVE
{"u030C", "\xc7\x94"}, // LATIN SMALL LETTER U WITH CARON
{"u030B", "\xc5\xb1"}, // LATIN SMALL LETTER U WITH DOUBLE ACUTE
{"v0303", "\xe1\xb9\xbd"}, // LATIN SMALL LETTER V WITH TILDE
{"w0300", "\xe1\xba\x81"}, // LATIN SMALL LETTER W WITH GRAVE
{"w0301", "\xe1\xba\x83"}, // LATIN SMALL LETTER W WITH ACUTE
{"w0302", "\xc5\xb5"}, // LATIN SMALL LETTER W WITH CIRCUMFLEX
{"w0308", "\xe1\xba\x85"}, // LATIN SMALL LETTER W WITH DIAERESIS
{"w0307", "\xe1\xba\x87"}, // LATIN SMALL LETTER W WITH DOT ABOVE
{"w030A", "\xe1\xba\x98"}, // LATIN SMALL LETTER W WITH RING ABOVE
{"x0308", "\xe1\xba\x8d"}, // LATIN SMALL LETTER X WITH DIAERESIS
{"x0307", "\xe1\xba\x8b"}, // LATIN SMALL LETTER X WITH DOT ABOVE
{"y0300", "\xe1\xbb\xb3"}, // LATIN SMALL LETTER Y WITH GRAVE
{"y0301", "\xc3\xbd"}, // LATIN SMALL LETTER Y WITH ACUTE
{"y0302", "\xc5\xb7"}, // LATIN SMALL LETTER Y WITH CIRCUMFLEX
{"y0303", "\xe1\xbb\xb9"}, // LATIN SMALL LETTER Y WITH TILDE
{"y0304", "\xc8\xb3"}, // LATIN SMALL LETTER Y WITH MACRON
{"y0308", "\xc3\xbf"}, // LATIN SMALL LETTER Y WITH DIAERESIS
{"y0307", "\xe1\xba\x8f"}, // LATIN SMALL LETTER Y WITH DOT ABOVE
{"y030A", "\xe1\xba\x99"}, // LATIN SMALL LETTER Y WITH RING ABOVE
{"z0301", "\xc5\xba"}, // LATIN SMALL LETTER Z WITH ACUTE
{"z0302", "\xe1\xba\x91"}, // LATIN SMALL LETTER Z WITH CIRCUMFLEX
{"z0307", "\xc5\xbc"}, // LATIN SMALL LETTER Z WITH DOT ABOVE
{"z030C", "\xc5\xbe"}, // LATIN SMALL LETTER Z WITH CARON
{"A0300", "\xc3\x80"}, // LATIN CAPITAL LETTER A WITH GRAVE
{"A0301", "\xc3\x81"}, // LATIN CAPITAL LETTER A WITH ACUTE
{"A0302", "\xc3\x82"}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
{"A0303", "\xc3\x83"}, // LATIN CAPITAL LETTER A WITH TILDE
{"A0304", "\xc4\x80"}, // LATIN CAPITAL LETTER A WITH MACRON
{"A0308", "\xc3\x84"}, // LATIN CAPITAL LETTER A WITH DIAERESIS
{"A0306", "\xc4\x82"}, // LATIN CAPITAL LETTER A WITH BREVE
{"A0307", "\xc8\xa6"}, // LATIN CAPITAL LETTER A WITH DOT ABOVE
{"A030A", "\xc3\x85"}, // LATIN CAPITAL LETTER A WITH RING ABOVE
{"A030C", "\xc7\x8d"}, // LATIN CAPITAL LETTER A WITH CARON
{"B0307", "\xe1\xb8\x82"}, // LATIN CAPITAL LETTER B WITH DOT ABOVE
{"C0301", "\xc4\x86"}, // LATIN CAPITAL LETTER C WITH ACUTE
{"C0302", "\xc4\x88"}, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
{"C0307", "\xc4\x8a"}, // LATIN CAPITAL LETTER C WITH DOT ABOVE
{"C030C", "\xc4\x8c"}, // LATIN CAPITAL LETTER C WITH CARON
{"C0327", "\xc3\x87"}, // LATIN CAPITAL LETTER C WITH CEDILLA
{"D0307", "\xe1\xb8\x8a"}, // LATIN CAPITAL LETTER D WITH DOT ABOVE
{"D030C", "\xc4\x8e"}, // LATIN CAPITAL LETTER D WITH CARON
{"D0327", "\xe1\xb8\x90"}, // LATIN CAPITAL LETTER D WITH CEDILLA
{"E0300", "\xc3\x88"}, // LATIN CAPITAL LETTER E WITH GRAVE
{"E0301", "\xc3\x89"}, // LATIN CAPITAL LETTER E WITH ACUTE
{"E0302", "\xc3\x8a"}, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
{"E0303", "\xe1\xba\xbc"}, // LATIN CAPITAL LETTER E WITH TILDE
{"E0304", "\xc4\x92"}, // LATIN CAPITAL LETTER E WITH MACRON
{"E0308", "\xc3\x8b"}, // LATIN CAPITAL LETTER E WITH DIAERESIS
{"E0306", "\xc4\x94"}, // LATIN CAPITAL LETTER E WITH BREVE
{"E0307", "\xc4\x96"}, // LATIN CAPITAL LETTER E WITH DOT ABOVE
{"E030C", "\xc4\x9a"}, // LATIN CAPITAL LETTER E WITH CARON
{"E0327", "\xc8\xa8"}, // LATIN CAPITAL LETTER E WITH CEDILLA
{"F0307", "\xe1\xb8\x9e"}, // LATIN CAPITAL LETTER F WITH DOT ABOVE
{"G0301", "\xc7\xb4"}, // LATIN CAPITAL LETTER G WITH ACUTE
{"G0302", "\xc4\x9c"}, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
{"G0304", "\xe1\xb8\xa0"}, // LATIN CAPITAL LETTER G WITH MACRON
{"G0306", "\xc4\x9e"}, // LATIN CAPITAL LETTER G WITH BREVE
{"G0307", "\xc4\xa0"}, // LATIN CAPITAL LETTER G WITH DOT ABOVE
{"G030C", "\xc7\xa6"}, // LATIN CAPITAL LETTER G WITH CARON
{"G0327", "\xc4\xa2"}, // LATIN CAPITAL LETTER G WITH CEDILLA
{"H0302", "\xc4\xa4"}, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
{"H0308", "\xe1\xb8\xa6"}, // LATIN CAPITAL LETTER H WITH DIAERESIS
{"H0307", "\xe1\xb8\xa2"}, // LATIN CAPITAL LETTER H WITH DOT ABOVE
{"H030C", "\xc8\x9e"}, // LATIN CAPITAL LETTER H WITH CARON
{"H0327", "\xe1\xb8\xa8"}, // LATIN CAPITAL LETTER H WITH CEDILLA
{"I0300", "\xc3\x8c"}, // LATIN CAPITAL LETTER I WITH GRAVE
{"I0301", "\xc3\x8d"}, // LATIN CAPITAL LETTER I WITH ACUTE
{"I0302", "\xc3\x8e"}, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
{"I0303", "\xc4\xa8"}, // LATIN CAPITAL LETTER I WITH TILDE
{"I0304", "\xc4\xaa"}, // LATIN CAPITAL LETTER I WITH MACRON
{"I0308", "\xc3\x8f"}, // LATIN CAPITAL LETTER I WITH DIAERESIS
{"I0306", "\xc4\xac"}, // LATIN CAPITAL LETTER I WITH BREVE
{"I0307", "\xc4\xb0"}, // LATIN CAPITAL LETTER I WITH DOT ABOVE
{"I030C", "\xc7\x8f"}, // LATIN CAPITAL LETTER I WITH CARON
{"J0302", "\xc4\xb4"}, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
{"K0301", "\xe1\xb8\xb0"}, // LATIN CAPITAL LETTER K WITH ACUTE
{"K030C", "\xc7\xa8"}, // LATIN CAPITAL LETTER K WITH CARON
{"K0327", "\xc4\xb6"}, // LATIN CAPITAL LETTER K WITH CEDILLA
{"L0301", "\xc4\xb9"}, // LATIN CAPITAL LETTER L WITH ACUTE
{"L030C", "\xc4\xbd"}, // LATIN CAPITAL LETTER L WITH CARON
{"L0327", "\xc4\xbb"}, // LATIN CAPITAL LETTER L WITH CEDILLA
{"M0301", "\xe1\xb8\xbe"}, // LATIN CAPITAL LETTER M WITH ACUTE
{"M0307", "\xe1\xb9\x80"}, // LATIN CAPITAL LETTER M WITH DOT ABOVE
{"N0300", "\xc7\xb8"}, // LATIN CAPITAL LETTER N WITH GRAVE
{"N0301", "\xc5\x83"}, // LATIN CAPITAL LETTER N WITH ACUTE
{"N0303", "\xc3\x91"}, // LATIN CAPITAL LETTER N WITH TILDE
{"N0307", "\xe1\xb9\x84"}, // LATIN CAPITAL LETTER N WITH DOT ABOVE
{"N030C", "\xc5\x87"}, // LATIN CAPITAL LETTER N WITH CARON
{"N0327", "\xc5\x85"}, // LATIN CAPITAL LETTER N WITH CEDILLA
{"O0300", "\xc3\x92"}, // LATIN CAPITAL LETTER O WITH GRAVE
{"O0301", "\xc3\x93"}, // LATIN CAPITAL LETTER O WITH ACUTE
{"O0302", "\xc3\x94"}, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
{"O0303", "\xc3\x95"}, // LATIN CAPITAL LETTER O WITH TILDE
{"O0304", "\xc5\x8c"}, // LATIN CAPITAL LETTER O WITH MACRON
{"O0308", "\xc3\x96"}, // LATIN CAPITAL LETTER O WITH DIAERESIS
{"O0306", "\xc5\x8e"}, // LATIN CAPITAL LETTER O WITH BREVE
{"O0307", "\xc8\xae"}, // LATIN CAPITAL LETTER O WITH DOT ABOVE
{"O030C", "\xc7\x91"}, // LATIN CAPITAL LETTER O WITH CARON
{"O030B", "\xc5\x90"}, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
{"P0301", "\xe1\xb9\x94"}, // LATIN CAPITAL LETTER P WITH ACUTE
{"P0307", "\xe1\xb9\x96"}, // LATIN CAPITAL LETTER P WITH DOT ABOVE
{"R0301", "\xc5\x94"}, // LATIN CAPITAL LETTER R WITH ACUTE
{"R0307", "\xe1\xb9\x98"}, // LATIN CAPITAL LETTER R WITH DOT ABOVE
{"R030C", "\xc5\x98"}, // LATIN CAPITAL LETTER R WITH CARON
{"R0327", "\xc5\x96"}, // LATIN CAPITAL LETTER R WITH CEDILLA
{"S0301", "\xc5\x9a"}, // LATIN CAPITAL LETTER S WITH ACUTE
{"S0302", "\xc5\x9c"}, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
{"S0307", "\xe1\xb9\xa0"}, // LATIN CAPITAL LETTER S WITH DOT ABOVE
{"S030C", "\xc5\xa0"}, // LATIN CAPITAL LETTER S WITH CARON
{"S0327", "\xc5\x9e"}, // LATIN CAPITAL LETTER S WITH CEDILLA
{"T0307", "\xe1\xb9\xaa"}, // LATIN CAPITAL LETTER T WITH DOT ABOVE
{"T030C", "\xc5\xa4"}, // LATIN CAPITAL LETTER T WITH CARON
{"T0327", "\xc5\xa2"}, // LATIN CAPITAL LETTER T WITH CEDILLA
{"U0300", "\xc3\x99"}, // LATIN CAPITAL LETTER U WITH GRAVE
{"U0301", "\xc3\x9a"}, // LATIN CAPITAL LETTER U WITH ACUTE
{"U0302", "\xc3\x9b"}, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
{"U0303", "\xc5\xa8"}, // LATIN CAPITAL LETTER U WITH TILDE
{"U0304", "\xc5\xaa"}, // LATIN CAPITAL LETTER U WITH MACRON
{"U0308", "\xc3\x9c"}, // LATIN CAPITAL LETTER U WITH DIAERESIS
{"U0306", "\xc5\xac"}, // LATIN CAPITAL LETTER U WITH BREVE
{"U030A", "\xc5\xae"}, // LATIN CAPITAL LETTER U WITH RING ABOVE
{"U030C", "\xc7\x93"}, // LATIN CAPITAL LETTER U WITH CARON
{"U030B", "\xc5\xb0"}, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
{"V0303", "\xe1\xb9\xbc"}, // LATIN CAPITAL LETTER V WITH TILDE
{"W0300", "\xe1\xba\x80"}, // LATIN CAPITAL LETTER W WITH GRAVE
{"W0301", "\xe1\xba\x82"}, // LATIN CAPITAL LETTER W WITH ACUTE
{"W0302", "\xc5\xb4"}, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
{"W0308", "\xe1\xba\x84"}, // LATIN CAPITAL LETTER W WITH DIAERESIS
{"W0307", "\xe1\xba\x86"}, // LATIN CAPITAL LETTER W WITH DOT ABOVE
{"X0308", "\xe1\xba\x8c"}, // LATIN CAPITAL LETTER X WITH DIAERESIS
{"X0307", "\xe1\xba\x8a"}, // LATIN CAPITAL LETTER X WITH DOT ABOVE
{"Y0300", "\xe1\xbb\xb2"}, // LATIN CAPITAL LETTER Y WITH GRAVE
{"Y0301", "\xc3\x9d"}, // LATIN CAPITAL LETTER Y WITH ACUTE
{"Y0302", "\xc5\xb6"}, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
{"Y0303", "\xe1\xbb\xb8"}, // LATIN CAPITAL LETTER Y WITH TILDE
{"Y0304", "\xc8\xb2"}, // LATIN CAPITAL LETTER Y WITH MACRON
{"Y0308", "\xc5\xb8"}, // LATIN CAPITAL LETTER Y WITH DIAERESIS
{"Y0307", "\xe1\xba\x8e"}, // LATIN CAPITAL LETTER Y WITH DOT ABOVE
{"Z0301", "\xc5\xb9"}, // LATIN CAPITAL LETTER Z WITH ACUTE
{"Z0302", "\xe1\xba\x90"}, // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
{"Z0307", "\xc5\xbb"}, // LATIN CAPITAL LETTER Z WITH DOT ABOVE
{"Z030C", "\xc5\xbd"}, // LATIN CAPITAL LETTER Z WITH CARON
};