С С++ 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; время покажет, окажутся ли они полезными или они будут забыты.