С С++ 11 мне нужна еще нестандартная библиотека обработки строк для текста в Unicode?
Я заметил, что метод длины std::string возвращает длину в байтах, а тот же метод в std:: u16string возвращает число двухбайтовых последовательностей.
Я также заметил, что когда символ или кодовая точка находится за пределами BMP, длина возвращает 4, а не 2.
Кроме того, escape-последовательность Unicode ограничена \unwnn, поэтому любая кодовая точка выше U + FFFF не может быть вставлена управляющей последовательностью.
Другими словами, не существует поддержки суррогатных пар или кодовых точек вне BMP.
Учитывая это, является ли принятая или рекомендуемая практика использовать нестандартную библиотеку манипуляции строками, которая понимает UTF-8, UTF-16, суррогатные пары и т.д.?
У моего компилятора есть ошибка, или я неправильно использую стандартные методы обработки строк?
Пример:
/*
* Example with the Unicode code points U+0041, U+4061, U+10196 and U+10197
*/
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
std::string example1 = u8"A䁡𐆖𐆗";
std::u16string example2 = u"A䁡𐆖𐆗";
std::cout << "Escape Example: " << "\u0041\u4061\u10196\u10197" << "\n";
std::cout << "Example: " << example1 << "\n";
std::cout << "std::string Example length: " << example1.length() << "\n";
std::cout << "std::u16string Example length: " << example2.length() << "\n";
return 0;
}
Вот результат, который я получаю при компиляции с помощью GCC 4.7:
Escape Example: A䁡မ6မ7
Example: A䁡𐆖𐆗
std::string Example length: 12
std::u16string Example length: 6
Ответы
Ответ 1
Рискуя преждевременно судить, мне кажется, что язык, используемый в стандартах, слегка неоднозначен (хотя окончательный вывод ясен, см. в конце):
В описании литералов char16_t (т.е. u"..."
таких, как в вашем примере) размер литерала определяется как:
Размер строкового литерала char16_t - это общее количество управляющих последовательностей, универсальных имен символов и других символов, плюс один для каждого символа, требующий суррогатной пары, плюс один для завершения u\0.
И в сноске далее разъясняется:
[Примечание. Размер строкового литерала char16_t - это количество единиц кода, а не количество символов. -end note]
Это подразумевает определение символа и единицы кода. Суррогатная пара - одна
характер, но два блока кода.
Однако описание метода length()
std::basic_string
(из которого получено std::u16string
):
Возвращает количество символов в строке, т.е. std:: distance (begin(), end()). Это то же самое, что и size().
Как видно, в описании length()
используется символ слова, означающий, что определение char16_t
вызывает блок кода.
Тем не менее, вывод из всего этого: Длина определяется как единицы кода, поэтому ваш компилятор соответствует стандарту, и будет продолжаться спрос на специальные библиотеки, чтобы обеспечить правильный подсчет символы.
Я использовал ссылки ниже:
- Для определения размера символов char16_t: Здесь
- Описание
std::basic_string::length()
: Здесь
Ответ 2
std::basic_string
ориентирован на код, а не ориентирован на характер. Если вам нужно иметь дело с кодовыми точками, вы можете конвертировать в char32_t, но в стандарте для более продвинутых функций Unicode ничего нет.
Также вы можете использовать escape-последовательность \UNNNNNNNN
для кодов без BMP, в дополнение к их непосредственному вводу (при условии, что вы используете исходную кодировку, которая их поддерживает).
В зависимости от ваших потребностей это может быть вся необходимая поддержка Unicode. Многим программным средствам не нужно делать больше, чем базовые манипуляции с строками, например, те, которые можно легко выполнить с помощью блоков кода напрямую. Для потребностей немного более высокого уровня вы можете конвертировать единицы кода в кодовые точки и работать над ними. Для более высоких потребностей, таких как работа над кластерами графем, потребуется дополнительная поддержка.
Я бы сказал, что это означает наличие адекватной поддержки в стандарте для представления данных Unicode и выполнения основных манипуляций. Независимо от того, какая библиотека сторонних разработчиков используется для функциональности более высокого уровня, следует использовать стандартную библиотеку. С течением времени стандарт, скорее всего, будет включать в себя и более функциональные возможности более высокого уровня.
Ответ 3
Учитывая это, является ли принятая или рекомендуемая практика использовать нестандартную библиотеку манипуляции строками, которая понимает UTF-8, UTF-16, суррогатные пары и т.д.?
Трудно говорить о рекомендуемой практике для языкового стандарта, который был создан несколько месяцев назад и еще не полностью реализован, но в целом я бы согласился: языковые и Unicode-функции на С++ 11 все еще безнадежно неадекватны (хотя они, очевидно, значительно улучшились), и для серьезной работы вам следует бросить их и использовать ICU или Boost.Locale вместо этого.
Добавление строк Unicode и функций преобразования в С++ 11 является первым шагом к реальной поддержке Unicode; время покажет, окажутся ли они полезными или они будут забыты.