| 1081 | } |
| 1082 | |
| 1083 | std::vector<std::string> unicode_regex_split(const std::string & text, const std::vector<std::string> & regex_exprs, bool byte_encode) { |
| 1084 | // unicode categories |
| 1085 | static const std::map<std::string, int> k_ucat_enum = { |
| 1086 | { "\\p{N}", unicode_cpt_flags::NUMBER }, |
| 1087 | { "\\p{L}", unicode_cpt_flags::LETTER }, |
| 1088 | { "\\p{P}", unicode_cpt_flags::PUNCTUATION }, |
| 1089 | { "\\p{M}", unicode_cpt_flags::ACCENT_MARK }, |
| 1090 | { "\\p{S}", unicode_cpt_flags::SYMBOL }, |
| 1091 | { "\\p{Lu}", unicode_cpt_flags::LETTER }, // Uppercase letter |
| 1092 | { "\\p{Ll}", unicode_cpt_flags::LETTER }, // Lowercase letter |
| 1093 | { "\\p{Lt}", unicode_cpt_flags::LETTER }, // Titlecase letter |
| 1094 | { "\\p{Lm}", unicode_cpt_flags::LETTER }, // Modifier letter |
| 1095 | { "\\p{Lo}", unicode_cpt_flags::LETTER }, // Other letter |
| 1096 | }; |
| 1097 | |
| 1098 | static const std::map<int, int> k_ucat_cpt = { |
| 1099 | { unicode_cpt_flags::NUMBER, 0xD1 }, |
| 1100 | { unicode_cpt_flags::LETTER, 0xD2 }, |
| 1101 | { unicode_cpt_flags::PUNCTUATION, 0xD3 }, |
| 1102 | { unicode_cpt_flags::ACCENT_MARK, 0xD4 }, |
| 1103 | { unicode_cpt_flags::SYMBOL, 0xD5 }, |
| 1104 | }; |
| 1105 | |
| 1106 | static const std::map<int, std::string> k_ucat_map = { |
| 1107 | { unicode_cpt_flags::NUMBER, "\x30-\x39" }, // 0-9 |
| 1108 | { unicode_cpt_flags::LETTER, "\x41-\x5A\x61-\x7A" }, // A-Za-z |
| 1109 | { unicode_cpt_flags::PUNCTUATION, "\x21-\x23\x25-\x2A\x2C-\x2F\x3A-\x3B\x3F-\x40\\\x5B-\\\x5D\x5F\\\x7B\\\x7D" }, // !-#%-*,-/:-;?-@\[-\]_\{\} |
| 1110 | { unicode_cpt_flags::ACCENT_MARK, "" }, // no sub-128 codepoints |
| 1111 | { unicode_cpt_flags::SYMBOL, "\\\x24\\\x2B\x3C-\x3E\x5E\x60\\\x7C" }, // $+<=>^`| |
| 1112 | }; |
| 1113 | |
| 1114 | // compute collapsed codepoints only if needed by at least one regex |
| 1115 | bool need_collapse = false; |
| 1116 | for (const auto & regex_expr : regex_exprs) { |
| 1117 | // search for unicode categories |
| 1118 | for (const auto & ucat : k_ucat_enum) { |
| 1119 | if (std::string::npos != regex_expr.find(ucat.first)) { |
| 1120 | need_collapse = true; |
| 1121 | break; |
| 1122 | } |
| 1123 | } |
| 1124 | } |
| 1125 | |
| 1126 | const auto cpts = unicode_cpts_from_utf8(text); |
| 1127 | |
| 1128 | // generate a "collapsed" representation of the text, where all codepoints are replaced by a single byte |
| 1129 | // ref: https://github.com/ggml-org/llama.cpp/pull/6920#issuecomment-2081479935 |
| 1130 | std::string text_collapsed; |
| 1131 | if (need_collapse) { |
| 1132 | // collapse all unicode categories |
| 1133 | text_collapsed.resize(cpts.size()); |
| 1134 | |
| 1135 | for (size_t i = 0; i < cpts.size(); ++i) { |
| 1136 | // keep single-byte codepoints as is |
| 1137 | if (cpts[i] < 128) { |
| 1138 | text_collapsed[i] = cpts[i]; |
| 1139 | continue; |
| 1140 | } |
no test coverage detected