Unicode в С++ 11
Я делал немного чтения по теме Unicode - в частности, поддержка UTF-8 - (non) в С++ 11, и я надеялся, что гуру в Qaru могут успокоить меня, что мой понимание правильное, или указать, где я неправильно понял или пропустил что-то, если это так.
Краткий обзор
Во-первых, хорошо: вы можете определить литералы UTF-8, UTF-16 и UCS-4 в исходном коде. Кроме того, заголовок <locale>
содержит несколько реализаций std::codecvt
, которые могут конвертировать между любыми UTF-8, UTF-16, UCS-4 и многобайтовой кодировкой платформы (хотя API, кажется, мягко, меньше, чем простой). Эти реализации codecvt
могут быть imbue()
'd в потоках, чтобы вы могли выполнять преобразование при чтении или записи файла (или другого потока).
[ EDIT:. В комментариях Кубби указывает, что я не упоминал заголовок <codecvt>
, который предоставляет реализации std::codecvt
, которые не зависят от локали. Кроме того, функции std::wstring_convert
и wbuffer_convert
могут использовать эти codecvt
для прямого преобразования строк и буферов, не полагаясь на потоки.]
С++ 11 также включает заголовок C99/C11 <uchar.h>
, который содержит функции для преобразования отдельных символов из многобайтовой кодировки платформы (которая может быть или не быть UTF-8) в UCS-2 и UCS-4.
Однако, что о его масштабах. Хотя вы можете, конечно, хранить текст UTF-8 в std::string
, нет никаких способов, которые я могу увидеть, чтобы сделать что-нибудь действительно полезное с ним. Например, помимо определения литерала в вашем коде, вы не можете проверить массив байтов как содержащий допустимый UTF-8, вы не можете узнать длину (то есть число символов Юникода для некоторого определения "символ", ) UTF-8-содержащего std::string
, и вы не можете перебирать по std::string
любым способом, кроме байта.
Аналогично, даже добавление С++ 11 std::u16string
на самом деле не поддерживает UTF-16, а только более старый UCS-2 - он не поддерживает суррогатные пары, оставляя вас только BMP.
Наблюдения
Учитывая, что UTF-8 является стандартным способом обработки Unicode почти для каждой производной от Unix системы (включая Mac OS X и * Linux) и в значительной степени стал стандартом де-факто на Интернет, отсутствие поддержки в современном С++ кажется довольно серьезным упущением. Даже в Windows факт, что новый std::u16string
не поддерживает UTF-16, кажется несколько прискорбным.
* Как указано в комментариях и сделана ясная здесь, части Mac OS, полученные из BSD, используют UTF-8, а Cocoa использует UTF -16.суб >
Вопросы
Если вам это удалось, спасибо! Просто несколько быстрых вопросов, так как это переполнение стека в конце концов...
-
Является ли приведенный выше анализ правильным, или существуют ли какие-либо другие поддерживающие Unicode средства, которые мне не хватает?
-
Комитет по стандартам проделал фантастическую работу за последние пару лет, продвигая вперед C++ вперед быстрыми темпами. Они все умные люди, и я предполагаю, что они хорошо знают вышеупомянутые недостатки. Есть ли какая-то известная причина, по которой поддержка Unicode остается такой плохой в С++?
-
Идет ли кто-нибудь о любых предложениях по исправлению ситуации? Быстрый поиск на isocpp.org, похоже, ничего не показывал.
EDIT: Спасибо всем за ваши ответы. Должен признаться, что я нахожу их немного обескураживающими - похоже, статус-кво вряд ли изменится в ближайшем будущем. Если есть консенсус среди cognoscenti, кажется, что полная поддержка Unicode слишком сложна и что любое решение должно переопределить большинство ICU, чтобы считаться полезным.
Я лично не согласен с этим; Я думаю, что есть ценная средняя почва. Например, алгоритмы валидации и нормализации для UTF-8 и UTF-16 хорошо определены консорциумом Unicode и могут быть предоставлены стандартной библиотекой в виде бесплатных функций, например, в пространстве имен std::unicode
. Только они будут полезны для программ на С++, которые должны взаимодействовать с библиотеками, ожидающими ввода Unicode. Но, основываясь на ответе ниже (оттенок, надо сказать, с намеком на горечь), кажется, что предложение Puppy только для такого рода ограниченной функциональности было плохо воспринято.
Ответы
Ответ 1
Правильно ли указан вышеприведенный анализ
Посмотрим.
вы не можете проверить массив байтов как содержащий действительный UTF-8
Неправильно. std::codecvt_utf8<char32_t>::length(start, end, max_lenght)
возвращает количество действительных байтов в массиве.
вы не можете узнать длину
Частично правильно. Можно преобразовать в char32_t и узнать длину результата. Нет простого способа узнать длину без фактического преобразования (но см. Ниже). Я должен сказать, что необходимость подсчета символов (в любом смысле) возникает довольно редко.
вы не можете перебирать по std::string любым способом, кроме байта по байту
Неправильно. std::codecvt_utf8<char32_t>::length(start, end, 1)
дает вам возможность перебирать символы UTF-8 (Unicode code units) и, конечно, определять их число (это не "простой" способ подсчета количества символов, но это способ).
не поддерживает UTF-16
Неправильно. Можно преобразовать в UTF-16 и из него с помощью, например, std::codecvt_utf8_utf16<char16_t>
. Результатом преобразования в UTF-16 является, ну, UTF-16. Это не ограничивается BMP.
Демо, иллюстрирующая эти точки.
Если я пропустил какой-то другой "вы не можете", пожалуйста, укажите его, и я рассмотрю его.
Важное добавление. Эти средства устарели в С++ 17. Вероятно, это означает, что они исчезнут в какой-то будущей версии С++. Используйте их на свой страх и риск. Все эти вещи, перечисленные в оригинальном вопросе, теперь нельзя (безопасно) сделать снова, используя только стандартную библиотеку.
Ответ 2
Является ли приведенный выше анализ правильным, или есть ли другие Поддержка Unicode объектов отсутствует?
Вам также не хватает полного отказа от литералов UTF-8. У них нет четкого типа для узкосимвольных литералов, которые могут иметь кодировку с абсолютно несвязанными (например, кодовыми страницами). Таким образом, они не только не добавили каких-либо серьезных новых возможностей на С++ 11, они сломали то, что мало было, потому что теперь вы даже не можете предположить, что char*
используется в узкоколонном кодировании для вашей платформы, если UTF-8 это кодировка узкой строки. Итак, новая функция здесь: "Мы полностью сломали строки на основе char
на каждой платформе, где UTF-8 не является существующей узкой строковой кодировкой".
Комитет по стандартам проделал фантастическую работу в последние пару лет лет двигаясь вперед на C++ вперед. Они все умные люди и Я предполагаю, что они хорошо знают вышеупомянутые недостатки. Есть ли особая известная причина, по которой поддержка Unicode остается настолько С++?
Комитет просто, похоже, не дерьмо относится к Юникоду.
Кроме того, многие из алгоритмов поддержки Unicode - это просто алгоритмы. Это означает, что для обеспечения достойного интерфейса нам нужны диапазоны. И мы все знаем, что Комитет не может понять, чего они хотят w.r.t. диапазоны. Новая вещь Iterables от Эрика Ниблера может иметь шанс.
Вперед, кто-нибудь знает какие-либо предложения об исправлении ситуация? Быстрый поиск на isocpp.org, похоже, не выявил что-нибудь.
Был N3572, который я создал. Но когда я отправился в Бристоль и представил его, возникло множество проблем.
Во-первых, оказывается, что Комитет не утруждает себя обратной связью по предложениям, не связанным с комитетом, между встречами, в результате чего месяцы утраченной работы, когда вы повторяете проект, который им не нужен.
Во-вторых, оказывается, что он проголосовал тем, кто когда-либо блуждает в то время. Это означает, что если ваша бумага будет перенесена, у вас будет относительно случайная группа людей, которые могут или не могут ничего знать о предмете. Или действительно, что угодно.
В-третьих, по какой-то причине они, похоже, не рассматривают текущую ситуацию как серьезную проблему. Вы можете бесконечно обсуждать, как точно следует определять операции сравнения optional<T>
, но иметь дело с пользовательским вводом? Кому это нужно?
В-четвертых, каждая статья нуждается в чемпионе, эффективно, чтобы представлять и поддерживать его. Учитывая предыдущие проблемы, а также тот факт, что я не мог позволить себе путешествовать на другие встречи, это, безусловно, не будет, не буду в будущем, если вы не захотите пожертвовать все мои командировочные расходы и заплатить зарплату наверху, и никто, похоже, не заботился об этом, чтобы приложить усилия.