С++ перебирать или разбивать строку UTF-8 на массив символов?

Поиск независимого от платформы и сторонней библиотеки способа повторения строки UTF-8 или ее разделения на массив символов UTF-8.

Пожалуйста, опубликуйте фрагмент кода.

Решено: C++ повторяет или разбивает строку UTF-8 на массив символов?


person topright gamedev    schedule 17.05.2010    source источник
comment
C++ не имеет стандартных средств для работы с кодировкой UTF-8. Так что либо используйте отдельную библиотеку, либо пишите свою. Написание собственного возможно, но есть миллионы деталей.   -  person Greg Hewgill    schedule 18.05.2010
comment
Да, именно поэтому я задаю вопрос.   -  person topright gamedev    schedule 18.05.2010


Ответы (5)


Если я правильно понимаю, похоже, вы хотите найти начало каждого символа UTF-8. Если это так, то их было бы довольно просто разобрать (интерпретировать их — другое дело). Но определение того, сколько октетов задействовано, четко определено в RFC:

Char. number range  |        UTF-8 octet sequence
   (hexadecimal)    |              (binary)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

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

unsigned char lb;

if (( lb & 0x80 ) == 0 )          // lead bit is zero, must be a single ascii
   printf( "1 octet\n" );
else if (( lb & 0xE0 ) == 0xC0 )  // 110x xxxx
   printf( "2 octets\n" );
else if (( lb & 0xF0 ) == 0xE0 ) // 1110 xxxx
   printf( "3 octets\n" );
else if (( lb & 0xF8 ) == 0xF0 ) // 1111 0xxx
   printf( "4 octets\n" );
else
   printf( "Unrecognized lead byte (%02x)\n", lb );

В конечном счете, вам будет гораздо лучше использовать существующую библиотеку, как это было предложено в другом посте. Приведенный выше код может классифицировать символы в соответствии с октетами, но он не помогает «делать» что-либо с ними после завершения.

person Mark Wilkins    schedule 17.05.2010
comment
Красивый ответ! Это именно то, что я искал! Спасибо! - person The Quantum Physicist; 12.05.2017

Решено с помощью крошечной независимой от платформы библиотеки UTF8 CPP:

    char* str = (char*)text.c_str();    // utf-8 string
    char* str_i = str;                  // string iterator
    char* end = str+strlen(str)+1;      // end iterator

    do
    {
        uint32_t code = utf8::next(str_i, end); // get 32 bit code of a utf-8 symbol
        if (code == 0)
            continue;

        unsigned char[5] symbol = {0};
        utf8::append(code, symbol); // copy code to symbol

        // ... do something with symbol
    }
    while ( str_i < end );
person topright gamedev    schedule 18.05.2010
comment
В некоторых языках слово содержит 2 или более символов, таких как «哈哈» в китайском языке. Следует ли использовать vector<uint32_t> для сохранения слова? Если это так, то сравнение слов требует повторения вектора/массива и кажется довольно медленным... - person stackunderflow; 18.05.2018

CPP UTF8 — это именно то, что вам нужно.

person Nemanja Trifunovic    schedule 17.05.2010
comment
Я уже нашел эту библиотеку сам. Мне нужен был код, но все равно спасибо. - person topright gamedev; 18.05.2010

Попробуйте библиотеку ICU.

person Kirill V. Lyadvinsky    schedule 17.05.2010
comment
независимый от сторонних библиотек способ - person topright gamedev; 18.05.2010
comment
+1 ICU — это кроссплатформенная библиотека, выпущенная под разрешительной лицензией с открытым исходным кодом. Если OP хочет избежать зависимости от сторонней библиотеки, исходный код ICU находится в свободном доступе, но содержит более 1e + 06 строк кода. - person cj.; 18.05.2010
comment
Это с открытым исходным кодом. Вы можете попробовать использовать исходный итератор строки из него, а не все строки кода 1e + 06. - person Kirill V. Lyadvinsky; 18.05.2010

Без подготовки:

// Return length of s converted. On success return should equal s.length().
// On error return points to the character where decoding failed.
// Remember to check the success flag since decoding errors could occur at
// the end of the string
int convert(std::vector<int>& u, const std::string& s, bool& success) {
    success = false;
    int cp = 0;
    int runlen = 0;
    for (std::string::const_iterator it = s.begin(), end = s.end(); it != end; ++it) {
        int ch = static_cast<unsigned char>(*it);
        if (runlen > 0) {
            if ((ch & 0xc0 != 0x80) || cp == 0) return it-s.begin();
            cp = (cp << 6) + (ch & 0x3f);
            if (--runlen == 0) {
                u.push_back(cp);
                cp = 0;
            }
        }
        else if (cp == 0) {
            if (ch < 0x80)      { u.push_back(ch); }
            else if (ch > 0xf8) return it-s.begin();
            else if (ch > 0xf0) { cp = ch & 7; runlen = 3; }
            else if (ch > 0xe0) { cp = ch & 0xf; runlen = 2; }
            else if (ch > 0xc0) { cp = ch & 0x1f; runlen = 1; }
            else return it-s.begin(); // stop on error
        }
        else return it-s.begin();
    }
    success = runlen == 0; // verify we are between codepoints
    return s.length();
}
person jmucchiello    schedule 17.05.2010
comment
Спасибо. Имеет ли значение endianess для этой функции? - person topright gamedev; 18.05.2010
comment
если (*it ‹ 0x80) { u.push_back(*it); } => сравнение всегда верно из-за ограниченного диапазона типов данных - person topright gamedev; 18.05.2010
comment
неверная конверсия из const char* const' to char*' - person topright gamedev; 18.05.2010
comment
Хорошо, я исправил ошибки. UTF8 строго на уровне байтов, поэтому порядок байтов не имеет значения. - person jmucchiello; 18.05.2010
comment
Какой? Порядок следования байтов — это порядок отдельных адресуемых субъединиц (слов, байтов или даже битов) (en.wikipedia. org/wiki/Endianness) Многобайтовое кодирование зависит от порядка следования байтов. - person topright gamedev; 19.05.2010
comment
Я скажу это снова. UTF8 — это кодировка на уровне байтов. Это означает, что вы читаете каждый байт последовательно. Неважно, в каком порядке биты передаются между IP-портами или из основной памяти в регистры микропроцессора. Когда эти биты объединяются, они интерпретируются одинаково на всех процессорах (19 == 19). Порядок байтов не является проблемой. - person jmucchiello; 20.05.2010