Каков наилучший способ хранения строк UTF-8 в памяти в C / C ++? - PullRequest
9 голосов
/ 12 января 2009

Глядя на стандарт Юникод , они рекомендуют использовать простые char s для хранения строк в кодировке UTF-8. Работает ли это должным образом с C ++ и базовым std::string, или существуют случаи, когда кодировка UTF-8 может создавать проблемы?

Например, при вычислении длины она может не совпадать с количеством байтов - как это должно обрабатываться? Читая стандарт, я, вероятно, в порядке использования массива char для хранения, но мне все равно нужно будет самостоятельно писать такие функции, как strlen и т. Д., Которые работают с кодированным текстом, потому что, насколько я понимаю проблема, стандартные подпрограммы либо только ASCII, либо ожидают широких литералов (16 бит или более), которые не рекомендуются стандартом Unicode. Пока что лучший источник информации о кодировании - это сообщение о Joel's Software , но оно не объясняет, что мы, бедный разработчик C ++, должны использовать:)

Ответы [ 6 ]

5 голосов
/ 12 января 2009

Существует библиотека под названием " UTF8-CPP ", которая позволяет хранить строки UTF-8 в стандартных объектах std :: string и предоставляет дополнительные функции для перечисления и управления символами utf-8.

Я еще не тестировал его, поэтому не знаю, чего он стоит, но я сам собираюсь его использовать.

3 голосов
/ 12 января 2009

Пример с библиотекой ICU (C, C ++, Java):

#include <iostream>
#include <unicode/unistr.h> // using ICU library

int main(int argc, char *argv[]) {
    // constructing a Unicode string
    UnicodeString ustr1("Привет"); // using platform's default codepage
    // calculating the length in characters, should be 6
    int ulen1=ustr1.length();
    // extracting encoded characters from a string
    int const bufsize=25;
    char encoded[bufsize];
    ustr1.extract(0,ulen1,encoded,bufsize,"UTF-8"); // forced UTF-8 encoding
    // printing the result
    std::cout << "Length of " << encoded << " is " << ulen1 << "\n";
    return 0;
}

здание типа

$ g++ -licuuc -o icu-example{,.cc}

работает

$ ./icu-example
Length of Привет is 6

У меня работает в Linux с GCC 4.3.2 и libicu 3.8.1. Обратите внимание, что он печатается в формате UTF-8 независимо от локали системы. Вы не увидите это правильно, если у вас не UTF-8.

2 голосов
/ 12 января 2009

strlen считает число ненулевых символов перед первым \ 0. В UTF-8 это число является нормальным числом (количество используемых байтов), но это не количество символов (один символ UTF-8 обычно составляет 1-4 символа). basic_string не хранит \ 0, но также хранит количество байтов.

strcpy или базовая_строка копирования ctor копируют все байты, не заглядывая слишком внимательно.

Поиск подстроки работает нормально, так как кодируется UTF_8. Допустимые значения для первого байта символа отличаются от второго до 4-го байта (первый никогда не начинается с 10xxxxxx, второй всегда)

Взять подстроку сложно - как вы определяете позицию? Если начало и конец были найдены путем поиска текстовых маркеров ASCII (например, [и]), то проблем нет. Вы бы просто получили байты посередине, которые также являются допустимой строкой UTF8. Вы не можете жестко закодировать позиции или даже относительные смещения. Даже относительное смещение +1 символа может быть трудным; сколько байт это? В итоге вы напишите такую ​​функцию, как SkipOneChar.

2 голосов
/ 12 января 2009

Это зависит от того, что вы хотите сделать со строкой UTF8. Если все, что вас интересует, это чтение и вывод строк UTF8, то все это работает, если вы указали правильный языковой стандарт. Мы сделали это в течение некоторого времени. У нас есть несколько серверных процессов, которые ничего не делают со строками как таковыми. Там строки устанавливаются пользователем в Java и поступают как UTF8, и мы обрабатываем их в стандартных буферах c str. Затем мы отправляем данные обратно в Java, которая преобразует их обратно.

Если вам нужна длина в символах UTF8, вам нужны функции, которые могут обработать перевод для вас.

Но вы можете бросить свой собственный, например, utf8-strlen

1 голос
/ 12 января 2009

С чем мы договорились: хранить UTF8 в std :: string. Вы можете выполнять большинство операций сейчас, за исключением таких вещей, как вычисление длины. Используйте функцию преобразования UTF8-> std :: wstring (например, boost :: from_utf8) для преобразования в std :: wstring, когда вам нужны такие операции.

0 голосов
/ 12 января 2009

С UTF-8 и Unicode FAQ: C поддержка Unicode :

#include <stdio.h>
#include <locale.h>

int main()
{
  if (!setlocale(LC_CTYPE, "")) {
    fprintf(stderr, "Can't set the specified locale! "
            "Check LANG, LC_CTYPE, LC_ALL.\n");
    return 1;
  }
  printf("%ls\n", L"Schöne Grüße");
  return 0;
}

Также с здесь :

Хорошая новость в том, что если вы используете wchar_t* струны и семья связанные с ними функции, такие как wprintf, wcslen и wcslcat, вы работа со значениями Unicode. в Мир C ++, вы можете использовать std::wstring для обеспечить дружественный интерфейс. Только мой жалоба на то, что это 32-битные (4 байт) символы, поэтому они являются памятью свиньи для всех языков. Причина для этот выбор заключается в том, что он гарантирует каждому возможный символ может быть представлен на одно значение.

PS. Это, вероятно, специфично для Linux. Есть библиотека ICU для обработки сложных вещей.

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