Итак, я строю язык сценариев, и одна из моих целей - удобные операции с строками. Я пробовал некоторые идеи на C++.C++ Unicode: байты, кодовые точки и графемы
- Строка как последовательность байтов и свободных функций, возвращающих векторы, содержащие индексы кодовых точек.
- Класс оболочки, который объединяет строку и вектор, содержащий индексы.
У обеих идей была проблема, и эта проблема была, что я должен вернуть. Это не может быть символ, и если бы это была строка, это было бы потрачено впустую.
Я закончил создание класса-оболочки вокруг массива char, состоящего из ровно 4 байтов: строки с 4 байтами в памяти, не более или менее.
После создания этого класса у меня возникло соблазн просто обернуть его в std::vector
его в другом классе и построить оттуда, создав таким образом строковый тип кодовых точек. Я не знаю, будет ли это хороший подход, в конечном итоге это будет гораздо удобнее, но в конечном итоге будет тратить больше места.
Итак, перед публикацией некоторого кода, вот более организованный список идей.
- My character type будет не байтом, не графемой, а скорее кодовой точкой. Я назвал его руной, как на языке Go.
- Строка как серия разложенных рун, что делает индексирование и нарезку O1.
- Поскольку руна теперь класс, а не примитивный, он может быть расширен с помощью методов для обнаружения Юникода пробельного:
mysring[0].is_whitespace()
- Я до сих пор не знаю, как обращаться с графемами.
Любопытный факт! Странная вещь о том, как я создаю прототип класса рун, заключалась в том, что он всегда печатается в UTF8. Поскольку моя руна - это не int32, а строка из 4 байтов, это приводит к некоторым интересным свойствам.
Мой код:
class rune {
char data[4] {};
public:
rune(char c) {
data[0] = c;
}
// This constructor needs a string, a position and an offset!
rune(std::string const & s, size_t p, size_t n) {
for (size_t i = 0; i < n; ++i) {
data[i] = s[p + i];
}
}
void swap(rune & other) {
rune t = *this;
*this = other;
other = t;
}
// Output as UTF8!
friend std::ostream & operator <<(std::ostream & output, rune input) {
for (size_t i = 0; i < 4; ++i) {
if (input.data[i] == '\0') {
return output;
}
output << input.data[i];
}
return output;
}
};
обработки ошибок идеи:
Я не люблю использовать исключения в C++. Моя идея состоит в том, что если конструктор не работает, инициализируйте руну как 4 '\0'
, а затем перегрузите оператор bool явным образом, чтобы вернуть false, если первый байт прогона будет '\0'
. Легко и просто использовать.
Итак, мысли? Мнения? Разные подходы?
Даже если моя строка руны много, по крайней мере, у меня есть тип руны. Маленький и быстрый для копирования. :)
Почему бы не использовать 'char32_t' для хранения "рун"? –
Как его использовать? В прошлый раз, когда я проверил, там не так много информации об этом. –
[char32_t] (http://en.cppreference.com/w/cpp/language/types) "для представления символа UTF-32, который должен быть достаточно большим, чтобы представлять любой кодовый блок UTF-32 (32 бита). Он имеет одинаковый размер, подпись и выравнивание как «std :: uint_least32_t', но является отдельным типом». –