2012-08-20 1 views
9

Я пишу программу, которая должна иметь возможность работать с текстом на всех языках. Я понимаю, что UTF-8 выполнит эту работу, но я испытываю несколько проблем с ней.Совместимость UTF-8 в C++

Могу ли я сказать, что UTF-8 можно хранить в простом char на C++? Если да, то почему я получаю следующее предупреждение при использовании программы с char, string и stringstream: warning C4566: character represented by universal-character-name '\uFFFD' cannot be represented in the current code page (1252). (Я не получаю эту ошибку, когда я использую wchar_t, wstring и wstringstream.)

Кроме того, я знаю, что UTF является переменной длиной. Когда я использую методы строки at или substr, я получу неправильный ответ?

+0

Для UTF wchar_t рекомендуется хранить. Вы можете хранить UTF-8 в символе без проблем, но результаты будут странными. – perilbrain

+4

@ Анонимный, который зависит от вашей платформы (и от *, который * аромат UTF вам интересен). В Windows 'wchar_t' подходит для UTF-16. В Linux целесообразно использовать для UTF-32. Для UTF-8 'char' является довольно разумным кандидатом (если у вас нет доступа к« новым »типам символов в C++ 11) – jalf

+0

Эта программа будет перенесена на разные платформы. Какой тип символа можно использовать лучше всего для этой цели? – Qman

ответ

11

Чтобы использовать UTF-8, строковые литералы вы должны префикс их u8, в противном случае вы получите набор символов реализации (в вашем случае, это, кажется, Windows-1252): u8"\uFFFD" заканчивается нулем последовательность байт с Представление UTF-8 замещающего символа (U + FFFD). Он имеет тип char const[4].

Поскольку UTF-8 имеет переменную длину, все виды индексирования будут индексировать в кодовых единицах, а не в кодовых точках. Невозможно сделать произвольный доступ к кодовым точкам в последовательности UTF-8 из-за его переменной длины. Если вам нужен произвольный доступ, вам нужно использовать кодировку с фиксированной длиной, например UTF-32. Для этого вы можете использовать префикс U на строках.

+2

Я использовал префикс 'L' до сих пор. Я попытался заменить его на 'u8', но я получаю ошибку' ошибка C2065: 'u8': uneclared identifier'. – Qman

+1

@ user1563613 Возможно, ваш компилятор еще не поддерживает 'u8'. Это Visual Studio? Если это так, вы, вероятно, должны использовать UTF-16, что и использует API Windows. –

+0

Это Visual studio 2010. Если я использую UTF-16, я должен указать endianess, правильно? Если да, это не проблема при переносе этой программы на другие платформы? – Qman

1

Причины вы получите предупреждение о том, что \uFFFD вы пытаетесь соответствовать FF FD внутри одного байта, так как, как вы отметили, UTF-8 работают на char с и переменной длиной.

Если вы используете at или substr, вы можете получить неправильные ответы, так как эти методы считают, что один байт должен быть одним символом. Это не относится к UTF-8. Примечательно, что с at вы можете получить один байт последовательности символов; с substr, вы можете сломать последовательность и в итоге получить недопустимую строку UTF-8 (она начнется или закончится с помощью , \uFFFD, той же, которую вы, по-видимому, пытаетесь использовать, и сломанный символ будет потерян).

Я бы порекомендовал вам использовать wchar для хранения строк Unicode. Поскольку тип не менее 16 бит, многие другие символы могут вписываться в один «блок».

+0

Худшая часть заключается в том, что она не будет иметь заменяющего персонажа. Нарушение последовательности байтов UTF-8 в неправильном месте с помощью substr просто приводит к недопустимой последовательности. Чтобы получить заменяющие символы, вам необходимо проверить и заменить их вручную. –

+0

@ R.MartinhoFernandes, действительно. Тем не менее, я бы поверила, что к тому времени, когда данные будут представлены пользователю, некоторый уровень стека выполнит эту работу. (Тем не менее, как вы отметили, в программе на C++ он останется не исправленным.) – zneak

+0

Итак, как я мог бы правильно получить подстроки или повторить символы? – Qman

9

Да, кодировка UTF-8 может использоваться с символами char, string и stringstream. Символ будет содержать единый кодовый блок UTF-8, из которых может потребоваться до четырех символов для представления одной кодовой точки Юникода.

Однако есть несколько проблем с использованием UTF-8 специально с компиляторами Microsoft. В реализациях C++ используется «набор символов выполнения» для ряда вещей, таких как кодирующий символ и строковые литералы. VC++ всегда использует кодировку языкового стандарта системы как набор символов выполнения, а Windows не поддерживает UTF-8 в качестве кодировки локали системы, поэтому UTF-8 никогда не может использоваться набором символов выполнения.

Это означает, что VC++ никогда не преднамеренно создает символы UTF-8 и строковые литералы. Вместо этого компилятор должен быть обманут.

Компилятор преобразует из известной кодировки исходного кода в исполняемую кодировку. Это означает, что если компилятор использует кодировку locale для кодировки источника и исполнения, преобразование не выполняется.Если вы можете получить данные UTF-8 в исходный код, но компилятор считает, что источник использует кодировку локали, тогда символьные и строковые литералы будут использовать кодировку UTF-8. VC++ использует так называемую «спецификацию» для обнаружения исходной кодировки и использует кодировку locale, если BOM не обнаружена. Поэтому вы можете получить кодированные строковые литералы UTF-8, сохранив все ваши исходные файлы как «UTF-8 без подписи».

Есть предостережения с этим методом. Во-первых, вы не можете использовать UCN с узкими символами и строковыми литералами. Универсальные имена символов должны быть преобразованы в набор символов выполнения, который не является UTF-8. Вы должны либо написать символ буквально, чтобы он отображался как UTF-8 в исходном коде, либо вы можете использовать шестнадцатеричные экраны, где вы вручную выписываете кодировку UTF-8. Во-вторых, для получения широких символов и строковых литералов компилятор выполняет аналогичное преобразование из исходной кодировки в широкий набор символов выполнения (который всегда является UTF-16 в VC++). Поскольку мы лжем компилятору о кодировке, он будет неправильно выполнять это преобразование в UTF-16. Таким образом, в широких символах и строковых литералах вы не можете использовать символы не-ascii буквально, и вместо этого вы должны использовать UCN или шестнадцатеричные escape-последовательности.


UTF-8 - это переменная длина (как и UTF-16). Индексы, используемые с at() и substr(), составляют единиц кода, а не индексы символов или кодовых точек. Поэтому, если вы хотите использовать конкретный блок кода, вы можете просто индексировать строку или массив или как обычно. Если вам нужна конкретная точка кода, вам понадобится библиотека, которая может понять, как составлять кодовые единицы UTF-8 в кодовые точки (например, Boost Unicode iterators library), или вам нужно преобразовать данные UTF-8 в UTF-32. Если вам нужны фактические воспринимаемые пользователем символы, вам нужна библиотека, которая понимает, как кодовые точки составлены в символы. Я полагаю, что ICU имеет такую ​​функциональность, или вы можете реализовать Default Grapheme Cluster Boundary Specification по стандарту Unicode.


Приведенное выше рассмотрение UTF-8 действительно имеет значение для того, как вы записываете данные Unicode в исходный код. Он мало влияет на ввод и вывод программы.

Если ваши требования позволяют вам выбрать способ ввода и вывода, я бы порекомендовал использовать UTF-8 для ввода. В зависимости от того, что вам нужно сделать с помощью ввода, вы можете либо преобразовать его в другую кодировку, которую легко обрабатывать, либо написать свои процедуры обработки для работы непосредственно на UTF-8.

Если вы хотите когда-либо выводить что-либо через консоль Windows, тогда вам нужен четко определенный модуль для вывода, который может иметь разные реализации, потому что для интернационализированного вывода на консоль Windows потребуется другая реализация либо из вывода в файл на Windows или консоли и вывод файлов на другие платформы. (На других платформах консоль - это еще один файл, но консоль Windows нуждается в специальной обработке.)