Как работать с UTF-8 в C++, Преобразование из других кодировок в UTF-8

Я не знаю, как решить это:

Представьте, у нас есть 4 сайта:

  • A: UTF-8
  • B: ISO-8859-1
  • C: ASCII
  • D: UTF-16

Моя программа, написанная на C++, выполняет следующие действия: загружает веб-сайт и анализирует его. Но это должно понимать содержание. Моя проблема не в разборе, который выполняется с помощью ASCII-символов, таких как ">" или же "<",

Проблема в том, что программа должна найти все слова из текста сайта. Слово - это любая комбинация буквенно-цифровых символов. Затем я отправляю эти слова на сервер. База данных и веб-интерфейс используют UTF-8. Итак, мои вопросы:

  • Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?
  • Как я могу работать с UTF-8-строк в C++? Я думаю wchar_t не работает, потому что его длина составляет 2 байта. Кодовые точки в UTF-8 имеют длину до 4 байтов...
  • Есть ли такие функции, как isspace(), isalnum(), strlen(), tolower() для таких UTF-8-струн?

Пожалуйста, обратите внимание: я не делаю вывод (например, std::cout) в C++. Просто отфильтровываю слова и отправляю их на сервер.

Я знаю о UTF8-CPP, но он не имеет is*() функции. И, как я читал, он не конвертируется из других кодировок в UTF-8. Только от UTF- * до UTF-8.

Редактировать: я забыл сказать, что программа должна быть переносимой: Windows, Linux, ...

4 ответа

Решение

Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?

ICU (Международные компоненты для Unicode) является решением здесь. Как правило, это последнее слово в поддержке Unicode. Даже Boost.Locale и Boost.Regex используют его, когда дело доходит до Unicode. См. Мой комментарий к ответу Дори Зидон о том, почему я рекомендую использовать ICU напрямую, а не обертками (например, Boost).

Вы создаете конвертер для данной кодировки...

#include <ucnv.h>

UConverter * converter;
UErrorCode err = U_ZERO_ERROR;
converter = ucnv_open( "8859-1", &err );
if ( U_SUCCESS( error ) )
{
    // ...
    ucnv_close( converter );
}

... а затем использовать класс UnicodeString как собственный.

Я думаю, что wchar_t не работает, потому что его длина составляет 2 байта.

Размер wchar_t определяется реализацией. AFAICR, Windows - 2 байта (UCS-2 / UTF-16, в зависимости от версии Windows), Linux - 4 байта (UTF-32). В любом случае, так как стандарт не определяет семантику Unicode для wchar_t, используя это непереносимые догадки. Не угадайте, используйте ICU.

Существуют ли такие функции, как isspace(), isalnum(), strlen(), tolower() для таких строк UTF-8?

Не в их кодировке UTF-8, но вы все равно не используете это внутренне. UTF-8 хорош для внешнего представления, но внутренне UTF-16 или UTF-32 - лучший выбор. Вышеупомянутые функции существуют для кодовых точек Unicode (т. Е. UChar32); ссылка учар.ч.

Обратите внимание: я не делаю вывод (например, std::cout) в C++. Просто отфильтровываю слова и отправляю их на сервер.

Проверьте BreakIterator.

Редактировать: я забыл сказать, что программа должна быть переносимой: Windows, Linux, ...

Если я еще этого не сказал, используйте ICU и избавьте себя от множества неприятностей. Даже если на первый взгляд это может показаться немного тяжеловесным, это лучшая из существующих реализаций, она чрезвычайно портативна (использую ее в Windows, Linux и AIX сама), и вы будете использовать ее снова и снова и снова в проектах, чтобы Приходите, поэтому время, потраченное на изучение его API, не теряется.

Не уверен, что это даст вам все, что вы ищете, но это может немного помочь. Вы пробовали смотреть на:

1) Библиотека Boost.Locale? Boost.Locale был выпущен в Boost 1.48(15 ноября 2011 г.), что упрощает конвертацию из UTF8/16 и обратно.

Вот несколько удобных примеров из документов:

string utf8_string = to_utf<char>(latin1_string,"Latin1");
wstring wide_string = to_utf<wchar_t>(latin1_string,"Latin1");
string latin1_string = from_utf(wide_string,"Latin1");
string utf8_string2 = utf_to_utf<char>(wide_string);

2) Или при преобразованиях являются частью C++11?

#include <codecvt>
#include <locale>
#include <string>
#include <cassert>

int main() {
  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
  std::string utf8 = convert.to_bytes(0x5e9);
  assert(utf8.length() == 2);
  assert(utf8[0] == '\xD7');
  assert(utf8[1] == '\xA9');
}

Как я могу работать с UTF-8-строк в C++? Я думаю, что wchar_t не работает, потому что его длина составляет 2 байта. Кодовые точки в UTF-8 имеют длину до 4 байтов...

Это легко, есть проект с именем tinyutf8, который является заменой для std::string/std::wstring,

Тогда пользователь может элегантно работать с кодовыми точками, в то время как их представление всегда кодируется в chars.


Как я могу преобразовать любую (или наиболее часто используемую) кодировку символов в UTF-8?

Возможно, вы захотите взглянуть на std::codecvt_utf8 и одинаковые шаблоны из <codecvt> (C++, 11).

UTF-8 - это кодировка, которая использует несколько байтов для не-ASCII (7-битный код) с использованием 8-го бита. Как таковой, вы не найдете '\', '/' внутри многобайтовой последовательности. А также isdigit работает (правда не арабский и прочие цифры).

Это расширенный набор ASCII и может содержать все символы Unicode, поэтому определенно использовать с char и string.

Проверьте заголовки HTTP (без учета регистра); они находятся в ISO-8859-1 и предшествуют пустой строке, а затем содержанию HTML.

Content-Type: text/html; charset=UTF-8

Если нет, там также может быть

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">      <!-- HTML5 -->

ISO-8859-1 - это латиница 1, и вам лучше преобразовать из Windows-1252 расширение Windows Latin-1, используя 0x80 - 0xBF для некоторых специальных символов, таких как кавычки и тому подобное. Даже браузеры на MacOS поймут это, хотя был указан ISO-8859-1.

Библиотеки конвертации: уже упоминалось @syam.

преобразование

Давайте не будем рассматривать UTF-16. Можно прочитать заголовки и начать до мета-оператора для набора символов как однобайтовые символы.

Преобразование из однобайтовой кодировки в UTF-8 может происходить через таблицу. Например, сгенерированный с Java: const char* table[] индексируется символом.

table[157] = "\xEF\xBF\xBD";


public static void main(String[] args) {
    final String SOURCE_ENCODING = "windows-1252";
    byte[] sourceBytes = new byte[1];
    System.out.println("    const char* table[] = {");
    for (int c = 0; c < 256; ++c) {
        String comment = "";
        System.out.printf("       /* %3d */ \"", c);
        if (32 <= c && c < 127) {
            // Pure ASCII
            if (c == '\"' || c == '\\')
                System.out.print("\\");
            System.out.print((char)c);
        } else {
            if (c == 0) {
                comment = " // Unusable";
            }
            sourceBytes[0] = (byte)c;
            try {
                byte[] targetBytes = new String(sourceBytes, SOURCE_ENCODING).getBytes("UTF-8");
                for (int j = 0; j < targetBytes.length; ++j) {
                    int b = targetBytes[j] & 0xFF;
                    System.out.printf("\\x%02X", b);
                }
            } catch (UnsupportedEncodingException ex) {
                comment = " // " + ex.getMessage().replaceAll("\\s+", " "); // No newlines.
            }
        }
        System.out.print("\"");
        if (c < 255) {
            System.out.print(",");
        }
        System.out.println();
    }
    System.out.println("    };");
}
Другие вопросы по тегам