Юникод и std :: string в C ++ - PullRequest
       0

Юникод и std :: string в C ++

9 голосов
/ 29 октября 2010

Если я записываю случайную строку в файл на C ++, состоящую из нескольких символов Юникода, мой текстовый редактор сообщает мне, что я не создал действительный файл UTF-8.

// Code example
const std::string charset = "abcdefgàèíüŷÀ";
file << random_string(charset); // using std::fstream

Что я могу сделатьсделать, чтобы решить это?Нужно ли делать много дополнительных ручных кодировок?Насколько я понимаю, std :: string не заботится о кодировке, только о байтах, поэтому, когда я передаю ей строку в кодировке Unicode и записываю ее в файл, этот файл обязательно должен содержать те же байты и распознаваться как UTF-8 закодированный файл?

Ответы [ 4 ]

15 голосов
/ 29 октября 2010

random_string может быть виновником;Интересно, как это реализовано.Если ваша строка действительно в кодировке UTF-8 и random_string выглядит как

std::string random_string(std::string const &charset)
{
    const int N = 10;
    std::string result(N);
    for (int i=0; i<N; i++)
        result[i] = charset[rand() % charset.size()];
    return result;
}

, тогда она будет случайным char с из charset, что в UTF-8 (как указывалось другими авторами)out) не кодовые точки Unicode, а простые байты.Если он выбирает случайный байт из середины многобайтового символа UTF-8 в качестве первого байта (или помещает его после 7-битного ASCII-совместимого символа), то ваши выходные данные не будут действительными UTF-8.См. Википедия и RFC 3629 .

Решением может быть преобразование в UTF-32 и из него в random_string.Я считаю, wchar_t и std::wstring используют UTF-32 в Linux.UTF-16 также будет в безопасности, пока вы остаетесь в пределах Базового Многоязычного Плана .

10 голосов
/ 29 октября 2010

Что я могу сделать, чтобы решить эту проблему? Должен ли я сделать много дополнительного руководства кодирование? Как я понимаю, std :: string не заботится о кодирование, только байты, поэтому, когда я передайте строку Unicode и напишите в файл, конечно, этот файл должен содержать одинаковые байты и быть распознан как файл в кодировке UTF-8?

Вы правы, что std::string кодирует агностик. Он просто содержит массив char элементов. То, как эти char элементы интерпретируются как текст, зависит от среды. Если для вашей локали не задана какая-либо форма Unicode (то есть UTF-8 или UTF-16), то при выводе строки она не будет отображаться / интерпретироваться как Unicode.

Вы уверены, что ваш строковый литерал "abcdefgàèíüŷÀ" на самом деле Unicode, а не, например, Latin-1 ? (ISO-8859-1 или, возможно, Windows-1252)? Вам необходимо определить, на какой локали настроена ваша платформа в данный момент.

----------- EDIT -----------

Мне кажется, я знаю вашу проблему: некоторые из этих символов Unicode в вашем строковом литерале charset, такие как акцентированный символ "А", являются двухбайтовыми символами (при условии кодировки UTF-8) , Когда вы обращаетесь к строке набора символов с помощью оператора [] в вашей функции random_string, вы возвращаете half символа Unicode. Таким образом, функция random-string создает недопустимую строку символов.

Например, рассмотрим следующий код:

std::string s = "À";
std::cout << s.length() << std::endl;

В среде, где строковый литерал интерпретируется как UTF-8, эта программа выведет 2. Следовательно, первый символ строки (s[0]) - это всего лишь половина символа Unicode, и, следовательно, он недопустим. Поскольку ваша функция random_string обращается к строке отдельными байтами с помощью оператора [], вы создаете недопустимые случайные строки.

Так что да, вам нужно использовать std::wstring и создать строковый литерал кодировки, используя префикс L.

1 голос
/ 29 октября 2010

В вашем примере кода std::string charset хранит то, что вы пишете . То есть, если вы использовали текстовый редактор UTF-8, чтобы написать это, то, что вы получите при выводе в файл, будет именно тот текст UTF-8.

UTF-8 - это просто схема кодирования, в которой разные символы используют разные размеры байтов. Однако, если вы используете редактор UTF-8, он будет кодифицировать, скажем, '-' с двумя байтами, и , когда вы запишите его в файл, он будет иметь эти два байта (снова UTF-8 совместимый).

Возможно, проблема в редакторе, который вы использовали для создания исходного файла C ++. Он может использовать латиницу 1 или другую кодировку.

0 голосов
/ 29 октября 2010

Чтобы написать UTF-8, вам нужно использовать фасет codecvt, такой как this . Пример того, как его использовать, можно увидеть здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...