Decode unicode data categories
This commit is contained in:
parent
8f9f05bf6d
commit
2636cb6170
3 changed files with 65 additions and 41 deletions
|
@ -49,6 +49,7 @@ def unicode_data_iter():
|
|||
yield (cpt, cpt_lower, cpt_upper, categ, bidir)
|
||||
|
||||
|
||||
# see codepoint_categ::from_index() in unicode.h
|
||||
UNICODE_CATEGORY_TO_INDEX = {
|
||||
"Cn": 0, # \p{Cn} Undefined
|
||||
"Cc": 1, # \p{Cc} Control
|
||||
|
@ -123,7 +124,7 @@ table_uppercase.sort()
|
|||
table_nfd.sort()
|
||||
|
||||
|
||||
# run length encoding
|
||||
# run length encoding, see unicode_cpt_category() in unicode.cpp
|
||||
assert (max(UNICODE_CATEGORY_TO_INDEX.values()) < 32)
|
||||
codepoint_categs_runs = [codepoint_categs[0]] # 5 bits categ + 11 bits length
|
||||
for cpt, categ in enumerate(codepoint_categs[1:], 1):
|
||||
|
|
|
@ -113,38 +113,6 @@ uint32_t unicode_cpt_from_utf8(const std::string & utf8, size_t & offset) {
|
|||
// return result;
|
||||
//}
|
||||
|
||||
static std::vector<codepoint_flags> unicode_cpt_flags_array() {
|
||||
std::vector<codepoint_flags> cpt_flags(MAX_CODEPOINTS, codepoint_flags::UNDEFINED);
|
||||
|
||||
assert (unicode_ranges_flags.front().first == 0);
|
||||
assert (unicode_ranges_flags.back().first == MAX_CODEPOINTS);
|
||||
for (size_t i = 1; i < unicode_ranges_flags.size(); ++i) {
|
||||
const auto range_ini = unicode_ranges_flags[i-1]; // codepoint_ini, flags
|
||||
const auto range_end = unicode_ranges_flags[i]; // codepoint_end, flags
|
||||
for (uint32_t cpt = range_ini.first; cpt < range_end.first; ++cpt) {
|
||||
cpt_flags[cpt] = range_ini.second;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cpt : unicode_set_whitespace) {
|
||||
cpt_flags[cpt].is_whitespace = true;
|
||||
}
|
||||
|
||||
for (auto p : unicode_map_lowercase) {
|
||||
cpt_flags[p.second].is_lowercase = true;
|
||||
}
|
||||
|
||||
for (auto p : unicode_map_uppercase) {
|
||||
cpt_flags[p.second].is_uppercase = true;
|
||||
}
|
||||
|
||||
for (auto &range : unicode_ranges_nfd) { // start, last, nfd
|
||||
cpt_flags[range.nfd].is_nfd = true;
|
||||
}
|
||||
|
||||
return cpt_flags;
|
||||
}
|
||||
|
||||
static std::unordered_map<uint8_t, std::string> unicode_byte_to_utf8_map() {
|
||||
std::unordered_map<uint8_t, std::string> map;
|
||||
for (int ch = 0x21; ch <= 0x7E; ++ch) { // u'!' to u'~'
|
||||
|
@ -606,19 +574,48 @@ std::vector<uint32_t> unicode_cpts_from_utf8(const std::string & utf8) {
|
|||
return result;
|
||||
}
|
||||
|
||||
codepoint_flags unicode_cpt_flags(const uint32_t cp) {
|
||||
static const codepoint_flags undef(codepoint_flags::UNDEFINED);
|
||||
static const auto cpt_flags = unicode_cpt_flags_array();
|
||||
return cp < cpt_flags.size() ? cpt_flags[cp] : undef;
|
||||
codepoint_categ unicode_cpt_category(const uint32_t cp) {
|
||||
static const std::vector<codepoint_categ> cpt_categs = [] {
|
||||
std::vector<codepoint_categ> cpt_categs(MAX_CODEPOINTS, codepoint_categ::UNDEF);
|
||||
uint32_t cpt = 0;
|
||||
for (uint16_t rle : unicode_rle_codepoints_categs) {
|
||||
const uint32_t index = rle & 31;
|
||||
const uint32_t count = rle >> 5;
|
||||
const auto categ = codepoint_categ::from_index(index);
|
||||
//printf( "Codepoints 0x%05X to 0x%05X categ %s\n", cpt, cpt + count, categ.c_str());
|
||||
for (uint32_t i = 0; i <= count; ++i) {
|
||||
cpt_categs[cpt++] = categ;
|
||||
}
|
||||
}
|
||||
assert (cpt == MAX_CODEPOINTS);
|
||||
|
||||
for (auto cpt : unicode_set_whitespace) {
|
||||
cpt_categs[cpt].set_flag(codepoint_categ::WHITESPACE);
|
||||
}
|
||||
|
||||
for (auto p : unicode_map_lowercase) {
|
||||
cpt_categs[cpt].set_flag(codepoint_categ::LOWERCASE);
|
||||
}
|
||||
|
||||
for (auto p : unicode_map_uppercase) {
|
||||
cpt_categs[cpt].set_flag(codepoint_categ::UPPERCASE);
|
||||
}
|
||||
|
||||
//for (auto &range : unicode_ranges_nfd) { // start, last, nfd
|
||||
// cpt_categs[cpt].set_flag(codepoint_categ::NORM_NFD);
|
||||
//}
|
||||
|
||||
return cpt_categs;
|
||||
}();
|
||||
return cp < cpt_categs.size() ? cpt_categs[cp] : codepoint_categ{};
|
||||
}
|
||||
|
||||
codepoint_flags unicode_cpt_flags(const std::string & utf8) {
|
||||
static const codepoint_flags undef(codepoint_flags::UNDEFINED);
|
||||
codepoint_categ unicode_cpt_category(const std::string & utf8) {
|
||||
if (utf8.empty()) {
|
||||
return undef; // undefined
|
||||
return codepoint_categ{}; // undefined
|
||||
}
|
||||
size_t offset = 0;
|
||||
return unicode_cpt_flags(unicode_cpt_from_utf8(utf8, offset));
|
||||
return unicode_cpt_category(unicode_cpt_from_utf8(utf8, offset));
|
||||
}
|
||||
|
||||
std::string unicode_byte_to_utf8(uint8_t byte) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
struct codepoint_categ {
|
||||
enum _category : uint16_t {
|
||||
|
@ -59,6 +61,18 @@ struct codepoint_categ {
|
|||
|
||||
inline codepoint_categ(const uint16_t categ=0) : encoded{categ} {}
|
||||
|
||||
static codepoint_categ from_index(int index) {
|
||||
static const std::array<codepoint_categ, 32> table = {
|
||||
UNDEF, Cc, Cf, Co, Cs, Ll, Lm, Lo, Lt, Lu, Mc, Me, Mn, Nd, Nl, No, Pc, Pd, Pe, Pf, Pi, Po, Ps, Sc, Sk, Sm, So, Zl, Zp, Zs, UNDEF, UNDEF
|
||||
};
|
||||
return (size_t)index < table.size() ? table[index] : table[0];
|
||||
}
|
||||
|
||||
inline void set_flag(_flags flags, bool value = true) {
|
||||
flags = (_flags) (flags & ~SUBMASK); // ignore category bits
|
||||
encoded = value ? (encoded | flags) : (encoded & ~flags);
|
||||
}
|
||||
|
||||
inline uint8_t get_category() const { return encoded & MASK; }
|
||||
inline uint8_t get_subcategory() const { return encoded & SUBMASK; }
|
||||
|
||||
|
@ -107,6 +121,18 @@ struct codepoint_categ {
|
|||
inline auto is_Zp() const { return (encoded & SUBMASK) == Zp; }
|
||||
inline auto is_Zs() const { return (encoded & SUBMASK) == Zs; }
|
||||
|
||||
const char * c_str() const {
|
||||
static const std::map<uint16_t, const char *> map = {
|
||||
{UNDEF, "UNDEF"}, {C, "C"}, {L, "L"}, {M, "M"}, {N, "N"}, {P, "P"}, {S, "S"}, {Z, "Z"},
|
||||
{Cc, "Cc"}, {Cf, "Cf"}, {Co, "Co"}, {Cs, "Cs"}, {Ll, "Ll"}, {Lm, "Lm"}, {Lo, "Lo"}, {Lt, "Lt"},
|
||||
{Lu, "Lu"}, {Mc, "Mc"}, {Me, "Me"}, {Mn, "Mn"}, {Nd, "Nd"}, {Nl, "Nl"}, {No, "No"}, {Pc, "Pc"},
|
||||
{Pd, "Pd"}, {Pe, "Pe"}, {Pf, "Pf"}, {Pi, "Pi"}, {Po, "Po"}, {Ps, "Ps"}, {Sc, "Sc"}, {Sk, "Sk"},
|
||||
{Sm, "Sm"}, {So, "So"}, {Zl, "Zl"}, {Zp, "Zp"}, {Zs, "Zs"},
|
||||
};
|
||||
const auto it = map.find(encoded & SUBMASK);
|
||||
return it == map.end() ? "INVALID" : it->second;
|
||||
}
|
||||
|
||||
uint16_t encoded;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue